changeset 29677:08104b0629d5

maint: merge stable to default.
author Markus Mützel <markus.muetzel@gmx.de>
date Sun, 16 May 2021 09:44:35 +0200
parents 2f6f53651d29 (diff) e84f7449a0d8 (current diff)
children 7511182e5e9b
files libinterp/corefcn/debug.cc
diffstat 1727 files changed, 67606 insertions(+), 29902 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.github/workflows/codeql-analysis.yaml	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,66 @@
+name: "CodeQL"
+
+on:
+  schedule:
+    # Run job every Monday and Thursday at 16:30 UTC
+    - cron: '30 16 * * 1,4'
+
+jobs:
+  analyze:
+    name: CodeQL analysis
+    runs-on: ubuntu-latest
+
+    strategy:
+      fail-fast: false
+      matrix:
+        # Override automatic language detection by changing the below list
+        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
+        language: ['cpp']
+        # Learn more...
+        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
+
+    steps:
+      - name: checkout repository
+        uses: actions/checkout@v2
+
+      - name: install dependencies
+        run: |
+          sudo apt -qq update
+          sudo apt install -y autoconf automake bison dvipng epstool fig2dev \
+            flex g++ gcc gfortran gnuplot-x11 gperf gzip icoutils \
+            libarpack2-dev libblas-dev libcurl4-gnutls-dev libfftw3-dev \
+            libfltk1.3-dev libfontconfig1-dev libfreetype6-dev \
+            libgl1-mesa-dev libgl2ps-dev libglpk-dev libgraphicsmagick++1-dev \
+            libhdf5-dev liblapack-dev libosmesa6-dev libpcre3-dev \
+            libqhull-dev libqscintilla2-qt5-dev libqrupdate-dev \
+            libreadline-dev librsvg2-bin libsndfile1-dev libsuitesparse-dev \
+            libsundials-dev libtool libxft-dev llvm-dev make openjdk-8-jdk \
+            perl portaudio19-dev pstoedit qtbase5-dev qttools5-dev \
+            qttools5-dev-tools rapidjson-dev rsync tar zlib1g-dev
+
+      - name: bootstrap
+        run: ./bootstrap
+
+      - name: configure
+        run: |
+          mkdir .build
+          cd .build && ../configure \
+            CPPFLAGS="-I/usr/include/hdf5/serial -I/usr/include/suitesparse" \
+            LDFLAGS="-L/usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/hdf5/serial" \
+            --disable-docs
+
+      - name: initialize CodeQL
+        # Initialize the CodeQL tools for scanning.
+        uses: github/codeql-action/init@v1
+        with:
+          languages: ${{ matrix.language }}
+          # If you wish to specify custom queries, you can do so here or in a config file.
+          # By default, queries listed here will override any specified in a config file. 
+          # Prefix the list here with "+" to use these queries and those in the config file.
+          # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+      - name: build
+        run: make -C ./.build all -j2 V=1
+
+      - name: perform CodeQL analysis
+        uses: github/codeql-action/analyze@v1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.github/workflows/make.yaml	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,257 @@
+name: make
+on: [push]
+concurrency: ci-${{ github.ref }}
+
+jobs:
+
+  ubuntu:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      matrix:
+        # For available GitHub-hosted runners, see:
+        # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners
+        os: [ubuntu-20.04, ubuntu-18.04]
+        compiler: [gcc, clang]
+        include:
+          - compiler: gcc
+            compiler-pkgs: "g++ gcc"
+            cc: "gcc"
+            cxx: "g++"
+          - compiler: clang
+            compiler-pkgs: "clang"
+            cc: "clang"
+            cxx: "clang++"
+          # "ccache" on Ubuntu 20.04 with gcc seems to require much more cache
+          # storage than on the other runners to work effectively.
+          - ccache-max: 3G
+          - os: ubuntu-20.04
+            compiler: gcc
+            ccache-max: 6G
+
+    steps:
+      - name: checkout repository
+        uses: actions/checkout@v2
+
+      - name: install dependencies
+        env:
+          COMPILER_PKGS: ${{ matrix.compiler-pkgs }}
+        run: |
+          sudo apt -qq update
+          sudo apt install -y $COMPILER_PKGS autoconf automake bison ccache \
+            dvipng epstool fig2dev flex gfortran gnuplot-x11 gperf gzip \
+            icoutils libarpack2-dev libblas-dev libcurl4-gnutls-dev \
+            libfftw3-dev libfltk1.3-dev libfontconfig1-dev libfreetype6-dev \
+            libgl1-mesa-dev libgl2ps-dev libglpk-dev libgraphicsmagick++1-dev \
+            libhdf5-dev liblapack-dev libosmesa6-dev libpcre3-dev \
+            libqhull-dev libqscintilla2-qt5-dev libqrupdate-dev \
+            libreadline-dev librsvg2-bin libsndfile1-dev libsuitesparse-dev \
+            libsundials-dev libtool libxft-dev llvm-dev make openjdk-8-jdk \
+            perl portaudio19-dev pstoedit qtbase5-dev qttools5-dev \
+            qttools5-dev-tools rapidjson-dev rsync tar texinfo \
+            texlive-latex-extra xvfb zlib1g-dev
+
+      - name: prepare ccache
+        # create human readable timestamp
+        id: ccache_cache_timestamp
+        run: |
+          echo "::set-output name=TIMESTAMP::$(date +"%Y-%m-%d_%H-%M-%S")"
+
+      - name: setup ccache
+        # setup the github cache used to maintain the ccache from one job to the next
+        uses: actions/cache@v2
+        with:
+          path: /home/runner/.ccache
+          key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }}
+          restore-keys: |
+            ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}
+            ccache:${{ matrix.os }}:${{ matrix.compiler }}
+
+      - name: configure ccache
+        env:
+          CCACHE_MAX: ${{ matrix.ccache-max }}
+        run: |
+          test -d /home/runner/.ccache || mkdir /home/runner/.ccache
+          echo "max_size = $CCACHE_MAX" >> /home/runner/.ccache/ccache.conf
+          ccache -s
+
+      - name: bootstrap
+        run: ./bootstrap
+
+      - name: configure
+        env:
+          MY_CC: ${{ matrix.cc }}
+          MY_CXX: ${{ matrix.cxx }}
+        run: |
+          echo $MY_CC --version
+          $MY_CC --version
+          echo $MY_CXX --version
+          $MY_CXX --version
+          mkdir .build
+          cd .build && ../configure \
+            CC="ccache $MY_CC" \
+            CXX="ccache $MY_CXX" \
+            F77="ccache gfortran" \
+            CPPFLAGS="-I/usr/include/hdf5/serial -I/usr/include/suitesparse" \
+            LDFLAGS="-L/usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/hdf5/serial"
+
+      - name: build
+        env:
+          XDG_RUNTIME_DIR: "/home/runner/tmp"
+        # Parallel make seems to fail intermittently when creating the figures
+        # for the manual. The error message says it fails to connect to a
+        # display. Maybe an xvfb issue?
+        # Use single job make for now which seems to work more reliably.
+        run: |
+          test -d $XDG_RUNTIME_DIR || mkdir $XDG_RUNTIME_DIR
+          xvfb-run -a make -C ./.build all V=1
+
+      - name: ccache status
+        run: ccache -s
+
+      - name: check
+        # Continuing on error in this step means that jobs will be "green" even
+        # if the test suite crashes.  But if we don't continue, we'll loose the
+        # ccache and other jobs will be cancelled.
+        # It would be nice if we could mark the job as "yellow" (and continue)
+        # in that case.
+        # It would also be nice if we could analyze the test suite results
+        # automatically.
+        continue-on-error: true
+        env:
+          XDG_RUNTIME_DIR: "/home/runner/tmp"
+        run: xvfb-run -a make -C ./.build check V=1
+
+
+  macos:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      matrix:
+        # For available GitHub-hosted runners, see: https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners
+        os: [macos-10.15]
+        # Most (or all) homebrew packages are compiled with clang and link
+        # against libc++.  So we also use clang to avoid issues with symbols
+        # that don't match.
+        # compiler: [real-gcc, clang]
+        compiler: [clang]
+        include:
+          # - compiler: real-gcc
+          #   cc: "/usr/local/bin/gcc-10"
+          #   cxx: "/usr/local/bin/g++-10"
+          #   cppflags: "-I/usr/local/opt/hdf5/include -I/usr/local/opt/gl2ps/include -I/usr/local/opt/glpk/include -I/usr/local/opt/pcre/include -I/usr/local/opt/qscintilla2/include -I/usr/local/opt/suite-sparse/include -I/usr/local/opt/sundials/include"
+          #   ldflags: "-L/usr/local/opt/hdf5/lib -L/usr/local/opt/gl2ps/lib -L/usr/local/opt/glpk/lib -L/usr/local/opt/pcre/lib -L/usr/local/opt/qscintilla2/lib -L/usr/local/opt/suite-sparse/lib -L/usr/local/opt/sundials/lib"
+          - compiler: clang
+            cc: "clang"
+            cxx: "clang++"
+
+    env:
+      MY_PATH: "/usr/local/opt/gnu-sed/libexec/gnubin:/usr/local/opt/bison/bin:/usr/local/opt/texinfo/bin:/usr/local/opt/qt@5/bin:/Library/TeX/texbin"
+
+    steps:
+      - name: checkout repository
+        uses: actions/checkout@v2
+
+      - name: install dependencies
+        # See also: https://formulae.brew.sh/formula/octave#default
+        # The packages are listed in (alphabetically sorted) blocks:
+        # The first block is for "direct" dependencies.
+        # The second block is for additional dependencies needed when building from a release tarball.
+        # The third block is for additional dependencies needed when building from a repository checkout.
+        run: |
+          brew update
+          brew install arpack epstool fftw fig2dev fltk fontconfig freetype \
+            gcc ghostscript gl2ps glpk gnuplot graphicsmagick hdf5 libsndfile \
+            libtool openblas pcre portaudio pstoedit qhull qrupdate \
+            qscintilla2 qt@5 rapidjson readline suite-sparse sundials texinfo \
+            ccache gnu-sed openjdk pkg-config \
+            automake autoconf bison gettext icoutils librsvg mactex-no-gui
+            eval "$(/usr/libexec/path_helper)"
+
+      - name: prepare ccache
+        # create human readable timestamp
+        id: ccache_cache_timestamp
+        run: |
+          echo "::set-output name=TIMESTAMP::$(date +"%Y-%m-%d_%H-%M-%S")"
+
+      - name: setup ccache
+        # setup the github cache used to maintain the ccache from one job to the next
+        uses: actions/cache@v2
+        with:
+          path: /Users/runner/Library/Caches/ccache
+          key: ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}:${{ steps.ccache_cache_timestamp.outputs.timestamp }}:${{ github.sha }}
+          restore-keys: |
+            ccache:${{ matrix.os }}:${{ matrix.compiler }}:${{ github.ref }}
+            ccache:${{ matrix.os }}:${{ matrix.compiler }}
+
+      - name: configure ccache
+        # The cache doesn't seem to compress well on macOS. Is it already compressed?
+        # Limit the maximum size to avoid exceeding the total cache limits.
+        run: |
+          test -d /Users/runner/Library/Preferences/ccache || mkdir /Users/runner/Library/Preferences/ccache
+          echo "max_size = 1.5G" >> /Users/runner/Library/Preferences/ccache/ccache.conf
+          ccache -s
+
+      - name: bootstrap
+        run: |
+          export PATH="$MY_PATH:$PATH"
+          ./bootstrap
+
+      - name: configure
+        env:
+          MY_CC: ${{ matrix.cc }}
+          MY_CXX: ${{ matrix.cxx }}
+          MY_CPPFLAGS: ${{ matrix.cppflags }}
+          MY_LDFLAGS: ${{ matrix.ldflags }}
+        # This is a hodgepodge of configure flags put together from the
+        # buildbot rules:
+        # https://hg.octave.org/octave-buildbot/file/tip/master.cfg#l543
+        # And the homebrew formula:
+        # https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/octave.rb
+        # Amended with additional flags that seem to be needed.
+        # Not all of those might be needed or be correct.
+        run: |
+          export PATH="$MY_PATH:$PATH"
+          echo $PATH
+          echo $MY_CC --version
+          $MY_CC --version
+          echo $MY_CXX --version
+          $MY_CXX --version
+          mkdir .build
+          cd .build && ../configure \
+            CC="ccache $MY_CC" \
+            CXX="ccache $MY_CXX" \
+            F77="ccache gfortran" \
+            CPPFLAGS="-I/usr/local/opt/gettext/include -I/usr/local/opt/icu4c/include -I/usr/local/opt/qt@5/include -I/usr/local/opt/readline/include -I/usr/local/opt/sqlite/include $MY_CPPFLAGS" \
+            CXXFLAGS="-O2 -g -std=c++11" \
+            LDFLAGS="-L/usr/local/lib -L/usr/local/opt/bison/lib -L/usr/local/opt/gettext/lib -L/usr/local/opt/icu4c/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/sqlite/lib $MY_LDFLAGS" \
+            PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/qt@5/lib/pkgconfig" \
+            QCOLLECTIONGENERATOR="qhelpgenerator" \
+            --with-x=no \
+            --with-blas="-L/usr/local/opt/openblas/lib -lopenblas" \
+            --with-java-homedir="/usr/local/opt/openjdk" \
+            --prefix="${HOME}/usr"
+
+      - name: build
+        run: |
+          export PATH="$MY_PATH:$PATH"
+          make -C ./.build all -j3 V=1
+
+      - name: ccache status
+        run: ccache -s
+
+      - name: install
+        # Install Octave prior to running the test suite for "mkoctfile" to
+        # work correctly.
+        run: make -C ./.build install V=1
+
+      - name: check
+        # Continuing on error in this step means that jobs will be "green" even
+        # if the test suite crashes.  But if we don't continue, we'll loose the
+        # ccache and other jobs will be cancelled, too.
+        # It would be nice if we could mark the job as "yellow" (and continue)
+        # in that case.
+        # It would also be nice if we could analyze the test suite results
+        # automatically.
+        continue-on-error: true
+        run: make -C ./.build check V=1
--- a/Makefile.am	Sun May 16 09:43:43 2021 +0200
+++ b/Makefile.am	Sun May 16 09:44:35 2021 +0200
@@ -44,13 +44,17 @@
 
 AM_YFLAGS = -dv ${WARN_YFLAGS}
 
+if AMCOND_LIB_VISIBILITY_FLAGS
+  OCTAVE_VISIBILITY_FLAGS = ${CFLAG_VISIBILITY}
+endif
+
 # Fortran compiler flags.
 
-AM_FFLAGS = ${FPICFLAG} @FFLAGS@
+AM_FFLAGS = ${FPICFLAG} @FFLAGS@ $(OCTAVE_VISIBILITY_FLAGS)
 
 # C compiler flags.
 
-AM_CFLAGS = ${CPICFLAG} ${XTRA_CFLAGS} ${WARN_CFLAGS}
+AM_CFLAGS = ${CPICFLAG} ${XTRA_CFLAGS} ${WARN_CFLAGS} $(OCTAVE_VISIBILITY_FLAGS)
 
 # ifeq (${INCLUDE_DEPS},no)
 #   omit_deps = true;
@@ -58,7 +62,7 @@
 
 # C++ compiler flags.
 
-AM_CXXFLAGS = ${CXXPICFLAG} ${XTRA_CXXFLAGS} ${WARN_CXXFLAGS}
+AM_CXXFLAGS = ${CXXPICFLAG} ${XTRA_CXXFLAGS} ${WARN_CXXFLAGS} $(OCTAVE_VISIBILITY_FLAGS)
 
 FFTW_XCPPFLAGS = @FFTW_XCPPFLAGS@
 FFTW_XLDFLAGS = @FFTW_XLDFLAGS@
--- a/NEWS	Sun May 16 09:43:43 2021 +0200
+++ b/NEWS	Sun May 16 09:44:35 2021 +0200
@@ -1,350 +1,235 @@
-Summary of bugs fixed for version 6.2.0 (2021-02-19):
-----------------------------------------------------
-
-See: https://www.octave.org/news/release/2021/02/20/octave-6.2.0-released.html
-
-For (bug #XXXXX) see https://savannah.gnu.org/bugs/?XXXXX
-
-### Improvements
-
-- `bicgstab.m`, `cgs.m`: Fix typo in `"iter_min"` variable name (bug #60071).
-- Compute with `NA` correctly on MIPS architecture (bug #59830).
-- Fix lookup of `"caller"` stack frame (bug #59847).
-- Also wait on `main_thread` after interpreter shuts down (bug #56952).
-- Fix symbol lookup issue with anonymous functions (bug #55989).
-- Line buffer input in `terminal_reader` class.
-- `qr`: Error for dense `A` and `B` with three output arguments (bug #58944).
-- `strmatch.m`: Always return column vector for Matlab compatibility (bug #59917)
-- Avoid crash when `evalin` global variables into existence in script (bug #59937)
-- Avoid crash on null statement list (bug #59938).
-- Fix ignored output from user function in left side of assignment (bug #59704).
-- Temporarily set lvalue list to null (bug #59704).
-- `fminbnd.m`: do not ignore `"OutputFcn"` (bug #59901).
-- `load-path.cc`: Reduce number of times `"canonicalize_file_name"` is called (bug #59711).
-- `interpn.m`: Use `size_equal` for 10X speedup in cset 067b663529bb (bug #59856).
-- `interpn.m`: Fix check for scattered point coordinates (bug #59856).
-- Avoid `YYUSE` in Octave parser files (see bug #59806).
-- `struct2hdl.m`: Set `"units"` property early.
-- `load-path.cc`: Avoid copying string for loop variable.
-- `pcg.m`: Return correct `FLAG` and correct `RELRES` output (bug #59776).
-- Use static keyword on regexp pattern in `file_stat` (bug #59706).
-- `stat`: Improve regular expression for UNC roots on Windows (bug #59706).
-- `stat`: Use `"make_absolute"` instead of `"canonicalize_file_name"` on Windows (bug #59706).
-- Improve `class_simple` function handle function lookup (bug #59661).
-- `hdl2struct.m`: store hidden text properties (bug #57241).
-- Mark script created with commands from history as modified.
-- `replem.m`: Fix operations with sparse matrices (bug #59705).
-- `ode_event_handler.m`: Fix mishandling of event edge types and multiple events (bug #59709).
-- Increase size of dynamic variable `new_argv` by 1 to avoid indexing out of array.
-- Fix incorrect results for set functions with `"legacy"` option (bug #59708).
-- `dir.m`: Return folder (not including file) in field `"folder"` (bug #59689).
-- Avoid memory leak with function handles (bug #59659).
-- Avoid dispatch error if method argument is a function handle (bug #59617).
-- Avoid crash due to accessing first element of empty list (bug #59656).
-- Don't propagate prevailing `isargout` info through `mexCallMATLAB` (bug #59597).
-- Show original error when failing to create a graphics object (bug #59620).
-- Fix regression with superclass lookup in classdef constructors (bug #59602).
-- Allow Octave class `execution_exception` to catch `std::exception` objects (bug #59592).
-
-### GUI
-
-- Fix restoring editor session after having closed all tabs (bug #60051).
-- Maybe convert TAB to SPC in GUI terminal pasted text (bug #59916).
-- Make bracketed paste mode work in GUI terminal.
-- Fix regression in variable editor when printing without selection.
-- Avoid gui when octave is launched in non-interactive mode (bug #59628).
-- `file-editor-tab.cc` (dtor): do not delete `m_edit_area` (bug #59628).
-- Fix error when restoring previous main window layout (bug #59426).
-- Improve default sizes of gui dock widgets.
-- Clean up constructing main window layout of the gui.
-- Fix focus command window after command execution (bug #59609).
-- Check object size before plotting from variable editor (bug #56685).
-- `documentation.cc`: Include missing header (bug #59553).
-
-### Build system / Tests
-
-- Add default value to `OCTAVE_MIPS_NAN` configure macro for cross-compiling (bug #59830).
-- tests: Function name should match file name (bug #59704).
-- Avoid build errors with Qt4 (bug #59813).
-- eigs.m: Make tests that depend on CHOLMOD conditional.
-- tests: Make tests that depend on CXSparse conditional.
-- build: Use `SPARSE_XCPPFLAGS` in `CPP_FLAGS` for libcorefcn (bug #59806).
-- Add test case for bug #59661.
-- `hgsave.m`: Allow test to run with qt or gnuplot graphics toolkits (bug #57241).
-
-### Documentation
-
-- `embedded.cc`: Fix syntax error interpreter shutdown.
-- Update Octave Project Developers copyright for the new year.
-- Use the same comment style for copyright headers in .m files and shell scripts.
-
-
-Summary of important user-visible changes for version 6.1.0 (2020-11-26):
-------------------------------------------------------------------------
+Summary of important user-visible changes for version 7 (yyyy-mm-dd):
+----------------------------------------------------------------------
 
 ### General improvements
 
-- The `intersect`, `setdiff`, `setxor`, `union`, and `unique` functions
-  accept a new sorting option `"stable"` which will return output values
-  in the same order as the input, rather than in ascending order.
+- Many functions in Octave can be called in a command form---no
+parentheses for invocation and no return argument assignment---or in a
+functional form---parentheses and '=' for assignment of return values.
 
-- Complex RESTful web services can now be accessed by the `webread` and
-  `webwrite` functions alongside with the `weboptions` structure.  One
-  major feature is the support for cookies to enable RESTful
-  communication with the web service.
+    **Command Form Example**
 
-  Additionally, the system web browser can be opened by the `web`
-  function.
+    `mkdir new_directory`
 
-- The `linspace` function now produces symmetrical sequences when the
-  endpoints are symmetric.  This is more intuitive and also compatible
-  with recent changes made in Matlab R2019b.
+    **Function Form Example**
 
-- The underlying algorithm of the `rand` function has been changed.
-  For single precision outputs, the algorithm has been fixed so that it
-  produces values strictly in the range (0, 1).  Previously, it could
-  occasionally generate the right endpoint value of 1 (See bug #41742).
-  In addition, the new implementation uses a uniform interval between
-  floating point values in the range (0, 1) rather than targeting a
-  uniform density (# of random integers / length along real number
-  line).
+    `status = mkdir ("new_directory")`
 
-- Numerical integration has been improved.  The `quadv` function has
-  been re-written so that it can compute integrands of periodic
-  functions.  At the same time, performance is better with ~3.5X fewer
-  function evaluations required.  A bug in `quadgk` that caused complex
-  path integrals specified with `"Waypoints"` to occasionally be
-  calculated in the opposite direction was fixed.
+    Octave now handles errors that occur in a consistent manner.  If
+    called in command form and there is a failure, an error is thrown
+    and a message printed.  If called in functional form, no error or
+    message is printed and the failure is communicated to the programmer
+    via the output status variable.
+
+    The following list of functions have been modified.
 
-- The `edit` function option `"editinplace"` now defaults to `true` and
-  the option `"home"` now defaults to the empty matrix `[]`.  Files will
-  no longer be copied to the user's HOME directory for editing.  The old
-  behavior can be restored by setting `"editinplace"` to `false` and
-  `"home"` to `"~/octave"`.
-
-- The `format` command supports two new options: `uppercase` and
-  `lowercase` (default).  With the default, print a lowercase 'e' for
-  the exponent character in scientific notation and lowercase 'a-f' for
-  the hex digits representing 10-15.  With `uppercase`, print 'E' and
-  'A-F' instead.  The previous uppercase formats, `E` and `G`, no longer
-  control the case of the output.
-
-  Additionally, the `format` command can be called with multiple options
-  for controlling the format, spacing, and case in arbitrary order.
-  For example:
-
-        format long e uppercase loose
+    * `copyfile`
+    * `fcntl`
+    * `fileattrib`
+    * `kill`
+    * `link`
+    * `mkfifo`
+    * `movefile`
+    * `rename`
+    * `rmdir`
+    * `symlink`
+    * `unlink`
 
-  Note, in the case of multiple competing format options the rightmost
-  one is used, and, in case of an error, the previous format remains
-  unchanged.
-
-- L-value references (e.g., increment (++), decrement (--), and all
-  in-place assignment operators (+=, -=, *=, /=, etc.)) are no longer
-  allowed in anonymous functions.
+- Calling a user-defined function with too many inputs or outputs is now
+an error.  The interpreter makes this check automatically.  If a
+function uses varargin then the check is skipped for function inputs,
+and if a function uses varargout then the check is skipped for function
+outputs.  Input validation for functions typically begins with checking
+that the number of inputs and outputs match expectations.  Existing code
+can be simplified by removing these checks which are now done by the
+interpreter.  Typically, code blocks like the following can simply be
+deleted.
 
-- New warnings have been added about questionable uses of the colon ':'
-  range operator.  Each has a new warning ID so that it can be disabled
-  if desired.
+        ## Checking number of inputs
+        if (nargin > 2)
+          print_usage ();
+        endif
 
-  >  `Octave:colon-complex-argument`   : when any arg is complex
-  >  `Octave:colon-nonscalar-argument` : when any arg is non-scalar
+        ## Checking number of outputs
+        if (nargout > 1)
+          print_usage ();
+        endif
 
-- 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")`.
+- Binary and hexadecimal constants like `0b101` and `0xDEADBEEF` now
+create integers (unsigned by default) with sizes determined from the
+number of digits present.  For example, `0xff` creates a `uint8` value
+and `0xDEADBEEF` creates a `uint64` value.  You may also use a suffix of
+the form `u8`, `u16`, `u32`, `u64`, `s8`, `s16`, `s32`, or `s64` to
+explicitly specify the data type to use (`u` or `s` to indicate unsigned
+or signed and the number to indicate the integer size).
 
-- The startup file `octaverc` can now be located in the platform
-  dependent location for user local configuration files (e.g.,
-  ${XDG_CONFIG_HOME}/octave/octaverc on Unix-like operating systems or
-  %APPDATA%\octave\octaverc on Windows).
-
-- `pkg describe` now lists dependencies and inverse dependencies
-  (i.e., other installed packages that depend on the package in
-  question).
+    Binary constants are limited to 64 binary digits and hexadecimal
+constants are limited to 16 hexadecimal digits with no automatic
+rounding or conversion to floating point values.  Note that this may
+cause problems in existing code.  For example, an expression like
+`[0x1; 0x100; 0x10000]` will be uint8 (because of the rules of
+concatenating integers of different sizes) with the larger values
+truncated (because of the saturation semantics of integer values).  To
+avoid these kinds of problems either: 1) declare the first integer to be
+of the desired size such as `[0x1u32; 0x100; 0x10000]`, or 2) pad
+constants in array expressions with leading zeros so that they use the
+same number of digits for each value such as
+`[0x00_00_01; 0x00_01_00; 0x01_00_00]`.
 
-- `pkg test` now tests all functions in a package.
-
-- When unloading a package, `pkg` now checks if any remaining loaded
-  packages depend on the one to be removed.  If this is the case `pkg`
-  aborts with an explanatory error message.  This behavior can be
-  overridden with the `-nodeps` option.
-
-- The command
+- For Octave on Windows OS, the minimum required version of the Windows
+API is now 6.1 (Windows 7 or newer).
 
-    dbstop in CLASS at METHOD
+- As part of GSoC 2020, Abdallah K. Elshamy implemented the
+`jsondecode` and `jsonencode` functions to read and write JSON data.
 
-  now works to set breakpoints in classdef constructors and methods.
-
-#### Graphics backend
+- By default, the history file is now located at $DATA/octave/history,
+where $DATA is a platform dependent location for (roaming) user data
+files (e.g., ${XDG_DATA_HOME} or, if that is not set, ~/.local/share on
+Unix-like operating systems or %APPDATA% on Windows).
 
-- 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 non-re-entrant version of the QHull library "libqhull" was
+deprecated upstream.  Octave now requires the re-entrant version of
+that library "libqhull_r" instead.
 
-- The `legend` function has been entirely rewritten.  This fixes a
-  number of historical bugs, and also implements new properties such as
-  `"AutoUpdate"` and `"NumColumns"`.  The gnuplot toolkit---which is no
-  longer actively maintained---still uses the old legend function.
+### Graphical User Interface
 
-- The `axis` function was updated which resolved 10 bugs affecting
-  axes to which `"equal"` had been applied.
+- Turkish translation added.
 
-- Graphic primitives now accept a color property value of `"none"`
-  which is useful when a particular primitive needs to be hidden
-  (for example, the Y-axis of an axes object with `"ycolor" = "none"`)
-  without hiding the entire primitive `"visibility" = "off"`.
+- In debug mode, symbol values are now shown in tooltips when hovering
+variables in the editor panel.
+
+### Graphics backend
+
+- Support for Qt4 for both graphics and the GUI has been removed.
 
-- 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.
+- If a working LaTeX tool chain is found on the path, including `latex`,
+`dvipng`, and `dvisvgm` binaries, then text strings can now be rendered properly
+when using the `"latex"` value for the text objects' `"interpreter"` property
+and axes objects' `"ticklabelinterpreter"`.  Type `doc "latex interpreter"`
+for further info.
 
-- The figure property `"windowscrollwheelfcn"`is now implemented.
-  This makes it possible to provide a callback function to be executed
-  when users manipulate the mouse wheel on a given figure.
-
-- The figure properties `"pointer"`, `"pointershapecdata"`, and
-  `"pointershapehotspot"` are now implemented.  This makes it possible
-  to change the shape of the cursor (pointer in Matlab-speak) displayed
-  in a plot window.
+- The additional property `"contextmenu"` has been added to all graphics
+objects.  It is equivalent to the previously used `"uicontextmenu"`
+property which is hidden now.
 
-- The figure property `"paperpositionmode"` now has the default `"auto"`
-  rather than `"manual"`.  This change is more intuitive and is
-  Matlab compatible.
-
-- The appearance of patterned lines `"LineStyle" = ":"|"--"|"-."` has
-  been improved for small widths (`"LineWidth"` less than 1.5 pixels)
-  which is a common scenario.
-
-- Printing to EPS files now uses a tight bounding box (`"-tight"`
-  argument to print) by default.  This makes more sense for EPS
-  files which are normally embedded within other documents, and is
-  Matlab compatible.  If necessary use the `"-loose"` option to
-  reproduce figures as they appeared in previous versions of Octave.
-
-- The following print devices are no longer officially supported: cdr,
-  corel, aifm, ill, cgm, hpgl, mf and dxf.  A warning will be thrown
-  when using those devices, and the code for supporting those formats
-  will eventually be removed from a future version of Octave.
-
-- The placement of text subscripts and superscripts has been
-  re-engineered and now produces visually attractive results similar to
-  Latex.
+- Additional properties have been added to the `axes` graphics object:
+    * `"alphamap"` (not yet implemented)
+    * `"alphascale"` (not yet implemented)
+    * `"colorscale"` (not yet implemented)
+    * `"fontsizemode"` (not yet implemented)
+    * `"innerposition"` (equivalent to `"position"`)
+    * `"interactions"` (not yet implemented)
+    * `"layout"` (not yet implemented)
+    * `"legend"` (not yet implemented)
+    * `"nextseriesindex"` (read-only, used by `scatter`
+      graphics objects)
+    * `"positionconstraint"` (replacement for `"activepositionproperty"`
+      which is now a hidden property.  No plans for removal.)
+    * `"toolbar"` (not yet implemented)
+    * `"xaxis"` (not yet implemented)
+    * `"yaxis"` (not yet implemented)
+    * `"zaxis"` (not yet implemented)
 
 ### Matlab compatibility
 
-- The function `unique` now returns column index vectors for the second
-  and third outputs.  When duplicate values are present, the default
-  index to return is now the `"first"` occurrence.  The previous Octave
-  behavior, or Matlab behavior from releases prior to R2012b, can be
-  obtained by using the `"legacy"` flag.
-
-- The function `setdiff` with the `"rows"` argument now returns Matlab
-  compatible results.  The previous Octave behavior, or Matlab behavior
-  from releases prior to R2012b, can be obtained by using the `"legacy"`
-  flag.
+- The function `griddata` now implements the `"v4"` Biharmonic Spline
+Interpolation method.  In adddition, the function now accepts 3-D inputs
+by passing the data to `griddata3`.
 
-- The functions `intersect`, `setxor`, and `union` now accept a
-  `"legacy"` flag which changes the index values (second and third
-  outputs) as well as the orientation of all outputs to match Matlab
-  releases prior to R2012b.
+- Coordinate transformation functions `cart2sph`, `sph2cart`,
+`cart2pol`, and `pol2cart` now accept either row or column vectors for
+coordinate inputs.  A single coordinate matrix with one variable per
+column can still be used as function input, but a single output variable
+will now contain just the first output coordinate, and will no longer
+return the full output coordinate matrix.  Output size matches the size
+of input vectors, or in the case of an input matrix will be column
+vectors with rows corresponding to the input coordinate matrix.
 
-- The function `streamtube` is Matlab compatible and plots tubes along
-  streamlines which are scaled by the vector field divergence. The
-  Octave-only extension `ostreamtube` can be used to visualize the flow
-  expansion and contraction of the vector field due to the local
-  crossflow divergence.
+- The function `dec2bin` and `dec2hex` now support negative numbers.
 
-- The interpreter now supports handles to nested functions.
+- The functions `quantile` and `prctile` now permit operating on
+dimensions greater than `ndims (x)`.
 
-- 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 function `importdata` now produces more compatible results when
+the file contains a 2-D text matrix.
 
-- 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 `FMT` format argument for plot commands now accepts long forms for
+color names which may be more understandable than the existing
+one-letter codes.  For example, the RGB value `[0 0 0]` can now be
+specified by `"black"` in addition to `"k"`.
 
-- Inline functions created by the function `inline` are now of type
-  "inline" when interrogated with the `class` function.  In previous
-  versions of Octave, the class returned was "function_handle".  This
-  change is Matlab compatible.  Inline functions are deprecated in
-  both Matlab and Octave and support may eventually be removed.
-  Anonymous functions can be used to replace all instances of inline
-  functions.
+- The color graphics properties, for example `"EdgeColor"` or
+`"FaceColor"`, now accept HTML specifications.  An HTML specification is
+a string that begins with the character '#' and is followed by either 3
+or 6 hexadecimal digits.  For example, magenta which is 100% red and
+blue values can specified by `"#FF00FF"` or `"#F0F"`.
 
-- 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.
+- `uicontrol` objects now fully implement the `"Off"` and `"Inactive"`
+values of the `"Enable"` property.  When the value is `"Off"`, no
+interaction with the object occurs and the `uicontrol` changes color
+(typically to gray) to indicate it is disabled.  When the value is
+`"Inactive"`, the object appears normally (no change in color), but it is
+not possible to change the value of the object (such as modifying text
+in an `Edit` box or clicking on a `RadioButton`).
 
-- Several validator functions of type `mustBe*` have been added.  See
-  the list of new functions below.
+- The functions `scatter` and `scatter3` now return a handle to a
+scatter graphics object.  For compatibility, they return an `hggroup` of
+patch graphics objects when the `"gnuplot"` graphics toolkit is used.  In
+previous versions of Octave, these functions returned an `hggroup` of
+patch graphics objects for all graphics toolkits.
 
-### Alphabetical list of new functions added in Octave 6
+- The functions `bar` and `barh` now handle stacked negative bar values
+in a Matlab-compatible manner.  Negative values now stack below the zero
+axis independently of a positive value bars in the same stack.
+Previously the negative bars could overlap positive bars depending on
+drawing order.
+
+- The functions `bar` and `barh` now use colors from the `"ColorOrder"`
+axes property rather than the `"Colormap"` figure property unless one
+of the histogram options (@qcode{"hist"}, @qcode{"histc"} was specified.
+
+- The function `saveas` now defaults to saving in Octave figure format
+(.ofig) rather than PDF (.pdf).
 
-* `auto_repeat_debug_command`
-* `commandhistory`
-* `commandwindow`
-* `filebrowser`
-* `is_same_file`
-* `lightangle`
-* `mustBeFinite`
-* `mustBeGreaterThan`
-* `mustBeGreaterThanOrEqual`
-* `mustBeInteger`
-* `mustBeLessThan`
-* `mustBeLessThanOrEqual`
-* `mustBeMember`
-* `mustBeNegative`
-* `mustBeNonempty`
-* `mustBeNonNan`
-* `mustBeNonnegative`
-* `mustBeNonpositive`
-* `mustBeNonsparse`
-* `mustBeNonzero`
-* `mustBeNumeric`
-* `mustBeNumericOrLogical`
-* `mustBePositive`
-* `mustBeReal`
-* `namedargs2cell`
-* `newline`
-* `ode23s`
-* `ostreamtube`
-* `rescale`
-* `rotx`
-* `roty`
-* `rotz`
-* `stream2`
-* `stream3`
-* `streamline`
-* `streamtube`
-* `uisetfont`
-* `verLessThan`
-* `web`
-* `weboptions`
-* `webread`
-* `webwrite`
-* `workspace`
+- A new warning ID (`"Octave:unimplemented-matlab-functionality"`) has
+been added which prints a warning when Octave's parser recognizes valid
+Matlab code, but for which Octave does not yet implement the
+functionality.  By default, this warning is enabled.
+
+### Alphabetical list of new functions added in Octave 7
 
+* `cospi`
+* `getpixelposition`
+* `endsWith`
+* `fill3`
+* `jsondecode`
+* `jsonencode`
+* `listfonts`
+* `matlab.net.base64decode`
+* `matlab.net.base64encode`
+* `memory`
+* `ordqz`
+* `rng`
+* `sinpi`
+* `startsWith`
+* `streamribbon`
+* `turbo`
+* `uniquetol`
+* `xtickangle`
+* `ytickangle`
+* `ztickangle`
 
 ### Deprecated functions and properties
 
-The following functions and properties have been deprecated in Octave 6
-and will be removed from Octave 8 (or whatever version is the second
-major release after 6):
+The following functions and properties have been deprecated in Octave 7
+and will be removed from Octave 9 (or whatever version is the second
+major release after 7):
 
 - Functions
 
   Function               | Replacement
   -----------------------|------------------
-  `runtests`             | `oruntests`
+                         |
 
 - Properties
 
@@ -352,51 +237,44 @@
   -----------------|---------------|------------
                    |               |
 
-- The environment variable used by `mkoctfile` for linker flags is now
-  `LDFLAGS` rather than `LFLAGS`.  `LFLAGS` is deprecated, and a warning
-  is emitted if it is used, but it will continue to work.
+- Interpreter
+
+    * The use of `'...'` for line continuations *inside* double-quoted
+    strings has been deprecated.  Use `'\'` for line continuations
+    inside strings instead.
 
+    * The use of `'\'` as a line continuation *outside* of double-quoted
+    strings has been deprecated.  Use `'...'` for line continuations
+    instead.
+
+    * Any trailing whitespace after a `'\'` line continuation has been
+    deprecated.  Delete unnecessary trailing whitespace.
 
 ### Removed functions and properties
 
-The following functions and properties were deprecated in Octave 4.4
-and have been removed from Octave 6.
+The following functions and properties were deprecated in Octave 5
+and have been removed from Octave 7.
 
 - Functions
 
-  Function             | Replacement
-  ---------------------|------------------
-  `chop`               | `sprintf` for visual results
-  `desktop`            | `isguirunning`
-  `tmpnam`             | `tempname`
-  `toascii`            | `double`
-  `java2mat`           | `__java2mat__`
+  Function                 | Replacement
+  -------------------------|------------------
+  `output_max_field_width` | `output_precision`
+  `is_keyword`             | `iskeyword`
 
 - Properties
 
-  Object               | Property                  | Value
-  ---------------------|---------------------------|-----------------------
-  `annotation`         | `edgecolor ("rectangle")` |
-  `axes`               | `drawmode`                |
-  `figure`             | `doublebuffer`            |
-                       | `mincolormap`             |
-                       | `wvisual`                 |
-                       | `wvisualmode`             |
-                       | `xdisplay`                |
-                       | `xvisual`                 |
-                       | `xvisualmode`             |
-  `line`               | `interpreter`             |
-  `patch`              | `interpreter`             |
-  `surface`            | `interpreter`             |
-  `text`               | `fontweight`              | `"demi"` and `"light"`
-  `uibuttongroup`      | `fontweight`              | `"demi"` and `"light"`
-  `uicontrol`          | `fontweight`              | `"demi"` and `"light"`
-  `uipanel`            | `fontweight`              | `"demi"` and `"light"`
-  `uitable`            | `fontweight`              | `"demi"` and `"light"`
-
+  Object           | Property      | Value
+  -----------------|---------------|------------
+  `text`           | `fontangle`   | `"oblique"`
+  `uibuttongroup`  | `fontangle`   | `"oblique"`
+  `uicontrol`      | `fontangle`   | `"oblique"`
+  `uipanel`        | `fontangle`   | `"oblique"`
+  `uitable`        | `fontangle`   | `"oblique"`
 
 ### Old release news
 
+- [Octave 6.x](etc/NEWS.6)
 - [Octave 5.x](etc/NEWS.5)
 - [Octave 4.x](etc/NEWS.4)
 - [Octave 3.x](etc/NEWS.3)
--- a/bootstrap	Sun May 16 09:43:43 2021 +0200
+++ b/bootstrap	Sun May 16 09:44:35 2021 +0200
@@ -1,10 +1,10 @@
 #! /bin/sh
 # Print a version string.
-scriptversion=2020-04-13.15; # UTC
+scriptversion=2021-04-11.09; # UTC
 
 # Bootstrap this package from checked-out sources.
 
-# Copyright (C) 2003-2020 Free Software Foundation, Inc.
+# Copyright (C) 2003-2021 Free Software Foundation, Inc.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -47,7 +47,7 @@
 
 me=$0
 
-default_gnulib_url=git://git.sv.gnu.org/gnulib
+default_gnulib_url=https://git.savannah.gnu.org/git/gnulib.git
 
 usage() {
   cat <<EOF
@@ -71,7 +71,9 @@
  --no-git                 do not use git to update gnulib.  Requires that
                           --gnulib-srcdir point to a correct gnulib snapshot
  --skip-po                do not download po files
-
+EOF
+  bootstrap_print_option_usage_hook
+  cat <<EOF
 If the file $me.conf exists in the same directory as this script, its
 contents are read as shell variables to configure the bootstrap.
 
@@ -113,6 +115,12 @@
 EOF
 }
 
+copyright_year=`echo "$scriptversion" | sed -e 's/[^0-9].*//'`
+copyright="Copyright (C) ${copyright_year} Free Software Foundation, Inc.
+License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law."
+
 # warnf_ FORMAT-STRING ARG1...
 warnf_ ()
 {
@@ -154,6 +162,18 @@
 : ${AUTOPOINT=autopoint}
 : ${AUTORECONF=autoreconf}
 
+# A function to be called for each unrecognized option.  Returns 0 if
+# the option in $1 has been processed by the function.  Returns 1 if
+# the option has not been processed by the function.  Override it via
+# your own definition in bootstrap.conf
+
+bootstrap_option_hook() { return 1; }
+
+# A function to be called in order to print the --help information
+# corresponding to user-defined command-line options.
+
+bootstrap_print_option_usage_hook() { :; }
+
 # A function to be called right after gnulib-tool is run.
 # Override it via your own definition in bootstrap.conf.
 bootstrap_post_import_hook() { :; }
@@ -170,7 +190,7 @@
  https://translationproject.org/latest/%s/"
 
 # Prefer a non-empty tarname (4th argument of AC_INIT if given), else
-# fall back to the package name (1st argument with munging)
+# fall back to the package name (1st argument with munging).
 extract_package_name='
   /^AC_INIT(\[*/{
      s///
@@ -187,8 +207,11 @@
      p
   }
 '
-package=$(sed -n "$extract_package_name" configure.ac) \
-  || die 'cannot find package name in configure.ac'
+package=$(${AUTOCONF:-autoconf} --trace AC_INIT:\$4 configure.ac 2>/dev/null)
+if test -z "$package"; then
+  package=$(sed -n "$extract_package_name" configure.ac) \
+      || die 'cannot find package name in configure.ac'
+fi
 gnulib_name=lib$package
 
 build_aux=build-aux
@@ -320,6 +343,12 @@
   --help)
     usage
     exit;;
+  --version)
+    set -e
+    echo "bootstrap $scriptversion"
+    echo "$copyright"
+    exit 0
+    ;;
   --gnulib-srcdir=*)
     GNULIB_SRCDIR=${option#--gnulib-srcdir=};;
   --skip-po)
@@ -335,7 +364,7 @@
   --no-git)
     use_git=false;;
   *)
-    die "$option: unknown option";;
+    bootstrap_option_hook $option || die "$option: unknown option";;
   esac
 done
 
@@ -709,6 +738,10 @@
 
   if test -d "$GNULIB_SRCDIR"/.git && test -n "$GNULIB_REVISION" \
      && ! git_modules_config submodule.gnulib.url >/dev/null; then
+    if ! git --git-dir="$GNULIB_SRCDIR"/.git cat-file \
+         commit "$GNULIB_REVISION"; then
+      git --git-dir="$GNULIB_SRCDIR"/.git fetch
+    fi
     (cd "$GNULIB_SRCDIR" && git checkout "$GNULIB_REVISION") || cleanup_gnulib
   fi
 
--- a/bootstrap.conf	Sun May 16 09:43:43 2021 +0200
+++ b/bootstrap.conf	Sun May 16 09:44:35 2021 +0200
@@ -56,8 +56,10 @@
   getrusage
   gettimeofday
   glob
+  intprops
   isatty
   largefile
+  lib-symbol-visibility
   link
   localcharset
   lstat
@@ -117,14 +119,18 @@
   unictype/ctype-upper
   unictype/ctype-xdigit
   unistd
+  unistr/u16-to-u8
+  unistr/u32-to-u8
   unistr/u8-check
   unistr/u8-strmblen
   unistr/u8-strmbtouc
+  unistr/u8-to-u16
   unistr/u8-to-u32
   unlink
   unsetenv
   vasprintf
   waitpid
+  windows-spawn
 "
 
 # Additional gnulib files and scripts used by Octave's buildsystem.
@@ -183,13 +189,18 @@
 source_base="libgnu"
 
 # Go to https://git.savannah.gnu.org/cgit/gnulib.git to find out the latest
-# revision ID.  Paste it below and run
+# revision ID.  Paste it below and then run
 #
 #   ./bootstrap --bootstrap-sync
 #
-# To update the ./bootstrap file with that from ./gnulib/build-aux/bootstrap
+# to update the ./bootstrap file from the selected gnulib revision,
+# followed by
+#
+#   patch -p1 -u < ./build-aux/gnulib-bootstrap-git-fetch.diff
+#
+# to apply local changes from build-aux/gnulib-bootstrap-git-fetch.diff
 
-: ${GNULIB_REVISION=6160ee8e4d2b88d934c3c4c8c5930a75b835723f}
+: ${GNULIB_REVISION=57e8c5005244df16e681428986c3bf0426050814}
 
 # Don't check for translations since we don't have any in Octave yet.
 # This avoids the need for sha1sum or compatible utility in bootstrap.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build-aux/gnulib-bootstrap-git-fetch.diff	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,31 @@
+Update bootstrap script from upstream gnulib to automatically fetch from repository if needed
+
+See also: https://lists.gnu.org/archive/html/bug-gnulib/2020-08/msg00150.html
+
+diff --git a/bootstrap b/bootstrap
+index 8f76d6962..2d0a06376 100755
+--- a/bootstrap
++++ b/bootstrap
+@@ -670,6 +670,11 @@ if $use_gnulib; then
+         || cleanup_gnulib
+ 
+       trap - 1 2 13 15
++
++    elif test -n "$GNULIB_REVISION" \
++         && ! git --git-dir="$gnulib_path"/.git cat-file \
++              commit "$GNULIB_REVISION"; then
++      git --git-dir="$gnulib_path"/.git fetch
+     fi
+     GNULIB_SRCDIR=$gnulib_path
+     ;;
+@@ -704,6 +709,10 @@ if $use_gnulib; then
+ 
+   if test -d "$GNULIB_SRCDIR"/.git && test -n "$GNULIB_REVISION" \
+      && ! git_modules_config submodule.gnulib.url >/dev/null; then
++    if ! git --git-dir="$GNULIB_SRCDIR"/.git cat-file \
++         commit "$GNULIB_REVISION"; then
++      git --git-dir="$GNULIB_SRCDIR"/.git fetch
++    fi
+     (cd "$GNULIB_SRCDIR" && git checkout "$GNULIB_REVISION") || cleanup_gnulib
+   fi
+ 
--- a/build-aux/mk-octave-config-h.sh	Sun May 16 09:43:43 2021 +0200
+++ b/build-aux/mk-octave-config-h.sh	Sun May 16 09:44:35 2021 +0200
@@ -182,17 +182,61 @@
 #    define octave_unused_parameter(param) (void) param;
 #  endif
 
-#  if defined (_MSC_VER)
-#    define OCTAVE_EXPORT __declspec(dllexport)
-#    define OCTAVE_IMPORT __declspec(dllimport)
+#  if defined (OCTAVE_ENABLE_LIB_VISIBILITY_FLAGS)
+#    if defined (_WIN32) || defined (__CYGWIN__)
+#      if defined (__GNUC__)
+         /* GCC */
+#        define OCTAVE_EXPORT __attribute__ ((dllexport))
+#        define OCTAVE_IMPORT __attribute__ ((dllimport))
+#      else
+         /* MSVC */
+#        define OCTAVE_EXPORT __declspec(dllexport)
+#        define OCTAVE_IMPORT __declspec(dllimport)
+#      endif
+#    else
+       /* All other platforms. */
+#      define OCTAVE_EXPORT __attribute__ ((visibility ("default")))
+#      define OCTAVE_IMPORT
+#    endif
 #  else
-     /* All other compilers, at least for now. */
-#    define OCTAVE_EXPORT
-#    define OCTAVE_IMPORT
+#      define OCTAVE_EXPORT
+#      define OCTAVE_IMPORT
 #  endif
 
+/* API macro for liboctave */
+#if defined (OCTAVE_DLL)
+#  define OCTAVE_API OCTAVE_EXPORT
+#else
 #  define OCTAVE_API OCTAVE_IMPORT
+#endif
+
+/* API macro for libinterp */
+#if defined (OCTINTERP_DLL)
+#  define OCTINTERP_API OCTAVE_EXPORT
+#else
 #  define OCTINTERP_API OCTAVE_IMPORT
+#endif
+
+/* API macro for the Array class in liboctave and liboctinterp */
+#if (defined (OCTAVE_DLL) || defined (OCTINTERP_DLL))
+#  define OCTARRAY_API OCTAVE_EXPORT
+#else
+#  define OCTARRAY_API OCTAVE_IMPORT
+#endif
+
+/* API macro for libinterp/graphics */
+#if defined (OCTGRAPHICS_DLL)
+#  define OCTGRAPHICS_API OCTAVE_EXPORT
+#else
+#  define OCTGRAPHICS_API OCTAVE_IMPORT
+#endif
+
+/* API macro for libgui */
+#if defined (OCTGUI_DLL)
+#  define OCTGUI_API OCTAVE_EXPORT
+#else
+#  define OCTGUI_API OCTAVE_IMPORT
+#endif
 EOF
 
 octave_idx_type="`$SED -n 's/#define OCTAVE_IDX_TYPE \([_a-zA-Z][_a-zA-Z0-9]*\)/\1/p' $config_h_file`"
--- a/build-aux/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/build-aux/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -35,6 +35,7 @@
 ### utility rules to aid development
 
 ALL_TEST_FILES = \
+  $(addprefix $(srcdir)/, $(LIBOCTAVE_TST_FILES_SRC)) \
   $(addprefix $(srcdir)/, $(LIBINTERP_TST_FILES_SRC)) \
   $(addprefix $(srcdir)/, $(FCN_FILES_WITH_TESTS)) \
   $(addprefix $(srcdir)/, $(TEST_FILES))
--- a/build-aux/subst-config-vals.in.sh	Sun May 16 09:43:43 2021 +0200
+++ b/build-aux/subst-config-vals.in.sh	Sun May 16 09:44:35 2021 +0200
@@ -38,60 +38,62 @@
 prefix="@prefix@"
 exec_prefix="@exec_prefix@"
 
-archlibdir=`echo "@archlibdir@" | sed "s|^${exec_prefix}/\\+||"`
-bindir=`echo "@bindir@" | sed "s|^${exec_prefix}/\\+||"`
-libdir=`echo "@libdir@" | sed "s|^${exec_prefix}/\\+||"`
-libexecdir=`echo "@libexecdir@" | sed "s|^${exec_prefix}/\\+||"`
-localapiarchlibdir=`echo "@localapiarchlibdir@" | sed "s|^${exec_prefix}/\\+||"`
-localapioctfiledir=`echo "@localapioctfiledir@" | sed "s|^${exec_prefix}/\\+||"`
-localarchlibdir=`echo "@localarchlibdir@" | sed "s|^${exec_prefix}/\\+||"`
-localoctfiledir=`echo "@localoctfiledir@" | sed "s|^${exec_prefix}/\\+||"`
-localverarchlibdir=`echo "@localverarchlibdir@" | sed "s|^${exec_prefix}/\\+||"`
-localveroctfiledir=`echo "@localveroctfiledir@" | sed "s|^${exec_prefix}/\\+||"`
-octfiledir=`echo "@octfiledir@" | sed "s|^${exec_prefix}/\\+||"`
-octlibdir=`echo "@octlibdir@" | sed "s|^${exec_prefix}/\\+||"`
+archlibdir=`echo "@archlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
+bindir=`echo "@bindir@" | $SED "s|^${exec_prefix}/\\+||"`
+libdir=`echo "@libdir@" | $SED "s|^${exec_prefix}/\\+||"`
+libexecdir=`echo "@libexecdir@" | $SED "s|^${exec_prefix}/\\+||"`
+localapiarchlibdir=`echo "@localapiarchlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
+localapioctfiledir=`echo "@localapioctfiledir@" | $SED "s|^${exec_prefix}/\\+||"`
+localarchlibdir=`echo "@localarchlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
+localoctfiledir=`echo "@localoctfiledir@" | $SED "s|^${exec_prefix}/\\+||"`
+localverarchlibdir=`echo "@localverarchlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
+localveroctfiledir=`echo "@localveroctfiledir@" | $SED "s|^${exec_prefix}/\\+||"`
+octfiledir=`echo "@octfiledir@" | $SED "s|^${exec_prefix}/\\+||"`
+octlibdir=`echo "@octlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
 
-datadir=`echo "@datadir@" | sed "s|^${prefix}/\\+||"`
-datarootdir=`echo "@datarootdir@" | sed "s|^${prefix}/\\+||"`
-doc_cache_file=`echo "@doc_cache_file@" | sed "s|^${prefix}/\\+||"`
-exec_prefix=`echo "@exec_prefix@" | sed "s|^${prefix}/\\+||"`
-fcnfiledir=`echo "@fcnfiledir@" | sed "s|^${prefix}/\\+||"`
-imagedir=`echo "@imagedir@" | sed "s|^${prefix}/\\+||"`
-includedir=`echo "@includedir@" | sed "s|^${prefix}/\\+||"`
-infodir=`echo "@infodir@" | sed "s|^${prefix}/\\+||"`
-infofile=`echo "@infofile@" | sed "s|^${prefix}/\\+||"`
-localapifcnfiledir=`echo "@localapifcnfiledir@" | sed "s|^${prefix}/\\+||"`
-localfcnfiledir=`echo "@localfcnfiledir@" | sed "s|^${prefix}/\\+||"`
-localstartupfiledir=`echo "@localstartupfiledir@" | sed "s|^${prefix}/\\+||"`
-localapiarchlibdir=`echo "@localapiarchlibdir@" | sed "s|^${prefix}/\\+||"`
-localverfcnfiledir=`echo "@localverfcnfiledir@" | sed "s|^${prefix}/\\+||"`
-man1dir=`echo "@man1dir@" | sed "s|^${prefix}/\\+||"`
-mandir=`echo "@mandir@" | sed "s|^${prefix}/\\+||"`
-octdatadir=`echo "@octdatadir@" | sed "s|^${prefix}/\\+||"`
-octdocdir=`echo "@octdocdir@" | sed "s|^${prefix}/\\+||"`
-octetcdir=`echo "@octetcdir@" | sed "s|^${prefix}/\\+||"`
-octfontsdir=`echo "@octfontsdir@" | sed "s|^${prefix}/\\+||"`
-octincludedir=`echo "@octincludedir@" | sed "s|^${prefix}/\\+||"`
-octlocaledir=`echo "@octlocaledir@" | sed "s|^${prefix}/\\+||"`
-octtestsdir=`echo "@octtestsdir@" | sed "s|^${prefix}/\\+||"`
-startupfiledir=`echo "@startupfiledir@" | sed "s|^${prefix}/\\+||"`
-texi_macros_file=`echo "@texi_macros_file@" | sed "s|^${prefix}/\\+||"`
+datadir=`echo "@datadir@" | $SED "s|^${prefix}/\\+||"`
+datarootdir=`echo "@datarootdir@" | $SED "s|^${prefix}/\\+||"`
+doc_cache_file=`echo "@doc_cache_file@" | $SED "s|^${prefix}/\\+||"`
+exec_prefix=`echo "@exec_prefix@" | $SED "s|^${prefix}/\\+||"`
+fcnfiledir=`echo "@fcnfiledir@" | $SED "s|^${prefix}/\\+||"`
+imagedir=`echo "@imagedir@" | $SED "s|^${prefix}/\\+||"`
+includedir=`echo "@includedir@" | $SED "s|^${prefix}/\\+||"`
+infodir=`echo "@infodir@" | $SED "s|^${prefix}/\\+||"`
+infofile=`echo "@infofile@" | $SED "s|^${prefix}/\\+||"`
+localapifcnfiledir=`echo "@localapifcnfiledir@" | $SED "s|^${prefix}/\\+||"`
+localfcnfiledir=`echo "@localfcnfiledir@" | $SED "s|^${prefix}/\\+||"`
+localstartupfiledir=`echo "@localstartupfiledir@" | $SED "s|^${prefix}/\\+||"`
+localapiarchlibdir=`echo "@localapiarchlibdir@" | $SED "s|^${prefix}/\\+||"`
+localverfcnfiledir=`echo "@localverfcnfiledir@" | $SED "s|^${prefix}/\\+||"`
+man1dir=`echo "@man1dir@" | $SED "s|^${prefix}/\\+||"`
+mandir=`echo "@mandir@" | $SED "s|^${prefix}/\\+||"`
+octdatadir=`echo "@octdatadir@" | $SED "s|^${prefix}/\\+||"`
+octdocdir=`echo "@octdocdir@" | $SED "s|^${prefix}/\\+||"`
+octetcdir=`echo "@octetcdir@" | $SED "s|^${prefix}/\\+||"`
+octfontsdir=`echo "@octfontsdir@" | $SED "s|^${prefix}/\\+||"`
+octincludedir=`echo "@octincludedir@" | $SED "s|^${prefix}/\\+||"`
+octlocaledir=`echo "@octlocaledir@" | $SED "s|^${prefix}/\\+||"`
+octtestsdir=`echo "@octtestsdir@" | $SED "s|^${prefix}/\\+||"`
+startupfiledir=`echo "@startupfiledir@" | $SED "s|^${prefix}/\\+||"`
+texi_macros_file=`echo "@texi_macros_file@" | $SED "s|^${prefix}/\\+||"`
 
+## FIXME: Some of these flags might contain double quotes.
+##        Is it ok to use single quotes here?
 if [ "x@OCTAVE_RELOCATE_ALL@" = "xyes" ]; then
   ## Replace portions of compiler flags that depend on prefix on target
-  cppflags=`echo "@CPPFLAGS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  fftw3f_ldflags=`echo "@FFTW3F_LDFLAGS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  fftw3_ldflags=`echo "@FFTW3_LDFLAGS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  flibs=`echo "@FLIBS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  ldflags=`echo "@LDFLAGS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  oct_link_opts=`echo "@OCT_LINK_OPTS@" | sed "s|@prefix@|\$\{prefix\}|g"`
+  cppflags=`echo '@CPPFLAGS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  fftw3f_ldflags=`echo '@FFTW3F_LDFLAGS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  fftw3_ldflags=`echo '@FFTW3_LDFLAGS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  flibs=`echo '@FLIBS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  ldflags=`echo '@LDFLAGS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  oct_link_opts=`echo '@OCT_LINK_OPTS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
 else
-  cppflags="@CPPFLAGS@"
-  fftw3f_ldflags="@FFTW3F_LDFLAGS@"
-  fftw3_ldflags="@FFTW3_LDFLAGS@"
-  flibs="@FLIBS@"
-  ldflags="@LDFLAGS@"
-  oct_link_opts="@OCT_LINK_OPTS@"
+  cppflags=`echo '@CPPFLAGS@' | $SED 's|\"|\\\\\\\"|g'`
+  fftw3f_ldflags=`echo '@FFTW3F_LDFLAGS@' | $SED 's|\"|\\\\\\\"|g'`
+  fftw3_ldflags=`echo '@FFTW3_LDFLAGS@' | $SED 's|\"|\\\\\\\"|g'`
+  flibs=`echo '@FLIBS@' | $SED 's|\"|\\\\\\\"|g'`
+  ldflags=`echo '@LDFLAGS@' | $SED 's|\"|\\\\\\\"|g'`
+  oct_link_opts=`echo '@OCT_LINK_OPTS@' | $SED 's|\"|\\\\\\\"|g'`
 fi
 
 
--- a/build-aux/subst-cross-config-vals.in.sh	Sun May 16 09:43:43 2021 +0200
+++ b/build-aux/subst-cross-config-vals.in.sh	Sun May 16 09:44:35 2021 +0200
@@ -48,60 +48,62 @@
 prefix="@prefix@"
 exec_prefix="@exec_prefix@"
 
-archlibdir=`echo "@archlibdir@" | sed "s|^${exec_prefix}/\\+||"`
-bindir=`echo "@bindir@" | sed "s|^${exec_prefix}/\\+||"`
-libdir=`echo "@libdir@" | sed "s|^${exec_prefix}/\\+||"`
-libexecdir=`echo "@libexecdir@" | sed "s|^${exec_prefix}/\\+||"`
-localapiarchlibdir=`echo "@localapiarchlibdir@" | sed "s|^${exec_prefix}/\\+||"`
-localapioctfiledir=`echo "@localapioctfiledir@" | sed "s|^${exec_prefix}/\\+||"`
-localarchlibdir=`echo "@localarchlibdir@" | sed "s|^${exec_prefix}/\\+||"`
-localoctfiledir=`echo "@localoctfiledir@" | sed "s|^${exec_prefix}/\\+||"`
-localverarchlibdir=`echo "@localverarchlibdir@" | sed "s|^${exec_prefix}/\\+||"`
-localveroctfiledir=`echo "@localveroctfiledir@" | sed "s|^${exec_prefix}/\\+||"`
-octfiledir=`echo "@octfiledir@" | sed "s|^${exec_prefix}/\\+||"`
-octlibdir=`echo "@octlibdir@" | sed "s|^${exec_prefix}/\\+||"`
+archlibdir=`echo "@archlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
+bindir=`echo "@bindir@" | $SED "s|^${exec_prefix}/\\+||"`
+libdir=`echo "@libdir@" | $SED "s|^${exec_prefix}/\\+||"`
+libexecdir=`echo "@libexecdir@" | $SED "s|^${exec_prefix}/\\+||"`
+localapiarchlibdir=`echo "@localapiarchlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
+localapioctfiledir=`echo "@localapioctfiledir@" | $SED "s|^${exec_prefix}/\\+||"`
+localarchlibdir=`echo "@localarchlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
+localoctfiledir=`echo "@localoctfiledir@" | $SED "s|^${exec_prefix}/\\+||"`
+localverarchlibdir=`echo "@localverarchlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
+localveroctfiledir=`echo "@localveroctfiledir@" | $SED "s|^${exec_prefix}/\\+||"`
+octfiledir=`echo "@octfiledir@" | $SED "s|^${exec_prefix}/\\+||"`
+octlibdir=`echo "@octlibdir@" | $SED "s|^${exec_prefix}/\\+||"`
 
-datadir=`echo "@datadir@" | sed "s|^${prefix}/\\+||"`
-datarootdir=`echo "@datarootdir@" | sed "s|^${prefix}/\\+||"`
-doc_cache_file=`echo "@doc_cache_file@" | sed "s|^${prefix}/\\+||"`
-exec_prefix=`echo "@exec_prefix@" | sed "s|^${prefix}/\\+||"`
-fcnfiledir=`echo "@fcnfiledir@" | sed "s|^${prefix}/\\+||"`
-imagedir=`echo "@imagedir@" | sed "s|^${prefix}/\\+||"`
-includedir=`echo "@includedir@" | sed "s|^${prefix}/\\+||"`
-infodir=`echo "@infodir@" | sed "s|^${prefix}/\\+||"`
-infofile=`echo "@infofile@" | sed "s|^${prefix}/\\+||"`
-localapifcnfiledir=`echo "@localapifcnfiledir@" | sed "s|^${prefix}/\\+||"`
-localfcnfiledir=`echo "@localfcnfiledir@" | sed "s|^${prefix}/\\+||"`
-localstartupfiledir=`echo "@localstartupfiledir@" | sed "s|^${prefix}/\\+||"`
-localapiarchlibdir=`echo "@localapiarchlibdir@" | sed "s|^${prefix}/\\+||"`
-localverfcnfiledir=`echo "@localverfcnfiledir@" | sed "s|^${prefix}/\\+||"`
-man1dir=`echo "@man1dir@" | sed "s|^${prefix}/\\+||"`
-mandir=`echo "@mandir@" | sed "s|^${prefix}/\\+||"`
-octdatadir=`echo "@octdatadir@" | sed "s|^${prefix}/\\+||"`
-octdocdir=`echo "@octdocdir@" | sed "s|^${prefix}/\\+||"`
-octetcdir=`echo "@octetcdir@" | sed "s|^${prefix}/\\+||"`
-octfontsdir=`echo "@octfontsdir@" | sed "s|^${prefix}/\\+||"`
-octincludedir=`echo "@octincludedir@" | sed "s|^${prefix}/\\+||"`
-octlocaledir=`echo "@octlocaledir@" | sed "s|^${prefix}/\\+||"`
-octtestsdir=`echo "@octtestsdir@" | sed "s|^${prefix}/\\+||"`
-startupfiledir=`echo "@startupfiledir@" | sed "s|^${prefix}/\\+||"`
-texi_macros_file=`echo "@texi_macros_file@" | sed "s|^${prefix}/\\+||"`
+datadir=`echo "@datadir@" | $SED "s|^${prefix}/\\+||"`
+datarootdir=`echo "@datarootdir@" | $SED "s|^${prefix}/\\+||"`
+doc_cache_file=`echo "@doc_cache_file@" | $SED "s|^${prefix}/\\+||"`
+exec_prefix=`echo "@exec_prefix@" | $SED "s|^${prefix}/\\+||"`
+fcnfiledir=`echo "@fcnfiledir@" | $SED "s|^${prefix}/\\+||"`
+imagedir=`echo "@imagedir@" | $SED "s|^${prefix}/\\+||"`
+includedir=`echo "@includedir@" | $SED "s|^${prefix}/\\+||"`
+infodir=`echo "@infodir@" | $SED "s|^${prefix}/\\+||"`
+infofile=`echo "@infofile@" | $SED "s|^${prefix}/\\+||"`
+localapifcnfiledir=`echo "@localapifcnfiledir@" | $SED "s|^${prefix}/\\+||"`
+localfcnfiledir=`echo "@localfcnfiledir@" | $SED "s|^${prefix}/\\+||"`
+localstartupfiledir=`echo "@localstartupfiledir@" | $SED "s|^${prefix}/\\+||"`
+localapiarchlibdir=`echo "@localapiarchlibdir@" | $SED "s|^${prefix}/\\+||"`
+localverfcnfiledir=`echo "@localverfcnfiledir@" | $SED "s|^${prefix}/\\+||"`
+man1dir=`echo "@man1dir@" | $SED "s|^${prefix}/\\+||"`
+mandir=`echo "@mandir@" | $SED "s|^${prefix}/\\+||"`
+octdatadir=`echo "@octdatadir@" | $SED "s|^${prefix}/\\+||"`
+octdocdir=`echo "@octdocdir@" | $SED "s|^${prefix}/\\+||"`
+octetcdir=`echo "@octetcdir@" | $SED "s|^${prefix}/\\+||"`
+octfontsdir=`echo "@octfontsdir@" | $SED "s|^${prefix}/\\+||"`
+octincludedir=`echo "@octincludedir@" | $SED "s|^${prefix}/\\+||"`
+octlocaledir=`echo "@octlocaledir@" | $SED "s|^${prefix}/\\+||"`
+octtestsdir=`echo "@octtestsdir@" | $SED "s|^${prefix}/\\+||"`
+startupfiledir=`echo "@startupfiledir@" | $SED "s|^${prefix}/\\+||"`
+texi_macros_file=`echo "@texi_macros_file@" | $SED "s|^${prefix}/\\+||"`
 
+## FIXME: Some of these flags might contain double quotes.
+##        Is it ok to use single quotes here?
 if [ "x@OCTAVE_RELOCATE_ALL@" = "xyes" ]; then
   ## Replace portions of compiler flags that depend on prefix on target
-  cppflags=`echo "@CPPFLAGS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  fftw3f_ldflags=`echo "@FFTW3F_LDFLAGS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  fftw3_ldflags=`echo "@FFTW3_LDFLAGS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  flibs=`echo "@FLIBS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  ldflags=`echo "@LDFLAGS@" | sed "s|@prefix@|\$\{prefix\}|g"`
-  oct_link_opts=`echo "@OCT_LINK_OPTS@" | sed "s|@prefix@|\$\{prefix\}|g"`
+  cppflags=`echo '@CPPFLAGS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  fftw3f_ldflags=`echo '@FFTW3F_LDFLAGS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  fftw3_ldflags=`echo '@FFTW3_LDFLAGS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  flibs=`echo '@FLIBS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  ldflags=`echo '@LDFLAGS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
+  oct_link_opts=`echo '@OCT_LINK_OPTS@' | $SED "s|@prefix@|\$\{prefix\}|g" | $SED 's|\"|\\\\\\\"|g'`
 else
-  cppflags="@CPPFLAGS@"
-  fftw3f_ldflags="@FFTW3F_LDFLAGS@"
-  fftw3_ldflags="@FFTW3_LDFLAGS@"
-  flibs="@FLIBS@"
-  ldflags="@LDFLAGS@"
-  oct_link_opts="@OCT_LINK_OPTS@"
+  cppflags=`echo '@CPPFLAGS@' | $SED 's|\"|\\\\\\\"|g'`
+  fftw3f_ldflags=`echo '@FFTW3F_LDFLAGS@' | $SED 's|\"|\\\\\\\"|g'`
+  fftw3_ldflags=`echo '@FFTW3_LDFLAGS@' | $SED 's|\"|\\\\\\\"|g'`
+  flibs=`echo '@FLIBS@' | $SED 's|\"|\\\\\\\"|g'`
+  ldflags=`echo '@LDFLAGS@' | $SED 's|\"|\\\\\\\"|g'`
+  oct_link_opts=`echo '@OCT_LINK_OPTS@' | $SED 's|\"|\\\\\\\"|g'`
 fi
 
 
--- a/configure.ac	Sun May 16 09:43:43 2021 +0200
+++ b/configure.ac	Sun May 16 09:44:35 2021 +0200
@@ -27,7 +27,7 @@
 
 ### Initialize Autoconf
 AC_PREREQ([2.65])
-AC_INIT([GNU Octave], [6.2.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,16 +39,16 @@
 ## explains how to update these numbers for release and development
 ## versions.
 
-OCTAVE_MAJOR_VERSION=6
-OCTAVE_MINOR_VERSION=2
-OCTAVE_PATCH_VERSION=1
+OCTAVE_MAJOR_VERSION=7
+OCTAVE_MINOR_VERSION=0
+OCTAVE_PATCH_VERSION=0
 
 dnl PACKAGE_VERSION is set by the AC_INIT VERSION argument.
 OCTAVE_VERSION="$PACKAGE_VERSION"
 
-OCTAVE_COPYRIGHT="Copyright (C) 2021 The Octave Project Developers."
-
-OCTAVE_RELEASE_DATE="2021-02-19"
+OCTAVE_COPYRIGHT="Copyright (C) 2020 The Octave Project Developers."
+
+OCTAVE_RELEASE_DATE="2020-08-26"
 
 ## The "API version" is used as a way of checking that interfaces in the
 ## liboctave and libinterp libraries haven't changed in a backwardly
@@ -63,7 +63,7 @@
 dnl FIXME: Since we also set libtool versions for liboctave and libinterp,
 dnl perhaps we should be computing the "api version" from those versions numbers
 dnl in some way instead of setting it independently here.
-OCTAVE_API_VERSION="api-v55"
+OCTAVE_API_VERSION="api-v55+"
 
 AC_SUBST(OCTAVE_MAJOR_VERSION)
 AC_SUBST(OCTAVE_MINOR_VERSION)
@@ -536,20 +536,6 @@
 AC_DEFINE_UNQUOTED(OCTAVE_IDX_TYPE, [$OCTAVE_IDX_TYPE],
   [Define to the type of octave_idx_type (64 or 32 bit signed integer).])
 
-### Enable bounds checking on element references within Octave's array and
-### matrix classes.
-dnl This slows down some operations a bit, so it is turned off by default.
-
-ENABLE_BOUNDS_CHECK=no
-AC_ARG_ENABLE([bounds-check],
-  [AS_HELP_STRING([--enable-bounds-check],
-    [OBSOLETE: use --enable-address-sanitizer-flags instead])],
-  [if test "$enableval" = yes; then ENABLE_BOUNDS_CHECK=yes; fi], [])
-if test $ENABLE_BOUNDS_CHECK = yes; then
-  warn_bounds_check="--enable-bounds-check is obsolete; use --enable-address-sanitizer-flags instead"
-  OCTAVE_CONFIGURE_WARNING([warn_bounds_check])
-fi
-
 ### Check for pthread library
 
 AX_PTHREAD
@@ -640,10 +626,12 @@
 AC_SUBST(STATIC_LIBS)
 
 XTRA_EXTERNAL_SH_LDFLAGS=
-if test $have_msvc = yes; then
-  FLIBS="$FLIBS -lkernel32"
-  XTRA_EXTERNAL_SH_LDFLAGS="-Wl,external/external.def"
-fi
+case $host_os in
+  msdosmsvc | mingw*)
+    FLIBS="$FLIBS -lkernel32"
+    XTRA_EXTERNAL_SH_LDFLAGS="-Wl,liboctave/external/external.def"
+  ;;
+esac
 AC_SUBST(XTRA_EXTERNAL_SH_LDFLAGS)
 
 if test $STATIC_LIBS = no && test $SHARED_LIBS = no; then
@@ -653,15 +641,23 @@
 
 ### More configure argument checking related to linking
 
+case $host_os in
+  msdosmsvc | mingw* | AIX | BeOS | OS/2 )
+    DEFAULT_NO_UNDEFINED_LDFLAG="-no-undefined"
+  ;;
+  *)
+    DEFAULT_NO_UNDEFINED_LDFLAG=""
+  ;;
+esac
 AC_ARG_ENABLE([no-undefined],
-  [AS_HELP_STRING([--disable-no-undefined],
-    [don't pass -no-undefined to libtool when linking Octave and its shared libraries])],
+  [AS_HELP_STRING([--enable-no-undefined],
+    [pass -no-undefined to libtool when linking Octave and its shared libraries. This is done by default for msdosmsvc, mingw*, AIX, BeOS, or OS/2 hosts.])],
   [case $enableval in
      yes) NO_UNDEFINED_LDFLAG="-no-undefined" ;;
      no)  NO_UNDEFINED_LDFLAG="" ;;
-     *) AC_MSG_ERROR([bad value $enableval for --disable-no-undefined]) ;;
+     *) AC_MSG_ERROR([bad value $enableval for --enable-no-undefined]) ;;
    esac],
-  [NO_UNDEFINED_LDFLAG="-no-undefined"])
+  [NO_UNDEFINED_LDFLAG="$DEFAULT_NO_UNDEFINED_LDFLAG"])
 AC_SUBST(NO_UNDEFINED_LDFLAG)
 
 AC_ARG_ENABLE([link-all-dependencies],
@@ -670,17 +666,10 @@
   [case $enableval in
      yes) link_all_deps=yes ;;
      no)  link_all_deps=no ;;
-     *) AC_MSG_ERROR([bad value $enableval for --enable-link-all-depenencies])
+     *) AC_MSG_ERROR([bad value $enableval for --enable-link-all-dependencies])
      ;;
    esac],
-  [case $host_os in
-    darwin*)
-      link_all_deps=yes
-    ;;
-    *)
-      link_all_deps=no
-    ;;
-  esac])
+  [link_all_deps=no])
 AM_CONDITIONAL([AMCOND_LINK_ALL_DEPS], [test $link_all_deps = yes])
 
 ### Check for BLAS and LAPACK libraries:
@@ -1072,6 +1061,24 @@
 ## Does the C compiler support Automake subdir-objects option?
 AM_PROG_CC_C_O
 
+## Set the target Windows version early so that gnulib can use all functions
+## that are available in that version.
+case $host_os in
+  msdosmsvc | mingw*)
+    AC_MSG_CHECKING([for required _WIN32_WINNT])
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+        #include <windows.h>
+        #if _WIN32_WINNT < 0x0601
+        #error "Wrong version"
+        #endif
+        ]], [])],
+      [AC_MSG_RESULT([none])],
+      [AC_DEFINE(_WIN32_WINNT, 0x0601,
+        [Define to 0x0601 to access SetCurrentProcessExplicitAppUserModelID.])
+       AC_MSG_RESULT([0x0601])])
+  ;;
+esac
+
 ### gnulib initialization: part 2
 dnl Must take place after part 1, and after standard compiler options and
 dnl search paths have been established, and at the same priority level as
@@ -1245,23 +1252,23 @@
   AC_MSG_ERROR([MATH DEFINES in math.h such as M_PI are required to build Octave])
 fi
 
-## Windows-specific tests for extra #defines
+## Use Unicode aware functions on Windows
 case $host_os in
   msdosmsvc | mingw*)
-    AC_MSG_CHECKING([for required _WIN32_WINNT])
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <windows.h>
-        #if _WIN32_WINNT < 0x0403
-        #error "Wrong version"
-        #endif
-        ]], [])],
-      [AC_MSG_RESULT([none])],
-      [AC_DEFINE(_WIN32_WINNT, 0x0403,
-        [Define to 0x0403 to access InitializeCriticalSectionAndSpinCount.])
-       AC_MSG_RESULT([0x0403])])
+    AC_DEFINE(_UNICODE, 1, [Use Unicode CRT functions on Windows by default.])
+    AC_DEFINE(UNICODE, 1, [Use Windows Unicode API by default.])
   ;;
 esac
 
+OCTAVE_UNICODE_EXE_LDFLAGS=""
+case $host_os in
+  mingw*)
+    OCTAVE_UNICODE_EXE_LDFLAGS="-municode"
+  ;;
+esac
+
+AC_SUBST(OCTAVE_UNICODE_EXE_LDFLAGS)
+
 ## Windows-specific use of functions
 case $host_os in
   msdosmsvc | mingw*)
@@ -1337,15 +1344,24 @@
 
 ### Check for the Qhull library.
 
-OCTAVE_CHECK_LIB(qhull, QHull,
+QHULL_CPPFLAGS=
+QHULL_LDFLAGS=
+QHULL_LIBS=
+OCTAVE_CHECK_LIB(qhull_r, QHull,
   [Qhull library not found.  This will result in loss of functionality for some geometry functions.],
-  [libqhull/libqhull.h qhull/libqhull.h libqhull.h qhull/qhull.h qhull.h],
+  [libqhull_r/libqhull_r.h libqhull_r.h],
   [qh_qhull], [], [],
-  [warn_qhull=
+  [warn_qhull_r=
   OCTAVE_CHECK_QHULL_VERSION
   OCTAVE_CHECK_LIB_QHULL_OK(
-    [AC_DEFINE(HAVE_QHULL, 1, [Define to 1 if Qhull is available.])],
-    [warn_qhull="Qhull library found, but does not seem to work properly.  This will result in loss of functionality for some geometry functions.  Please try recompiling the library with -fno-strict-aliasing."])])
+    [AC_DEFINE(HAVE_QHULL, 1, [Define to 1 if Qhull is available.])
+     QHULL_CPPFLAGS="$QHULL_R_CPPFLAGS"
+     QHULL_LDFLAGS="$QHULL_R_LDFLAGS"
+     QHULL_LIBS="$QHULL_R_LIBS"],
+    [warn_qhull_r="Qhull library found, but does not seem to work properly.  This will result in loss of functionality for some geometry functions.  Please try recompiling the library with -fno-strict-aliasing."])])
+AC_SUBST(QHULL_CPPFLAGS)
+AC_SUBST(QHULL_LDFLAGS)
+AC_SUBST(QHULL_LIBS)
 
 ### Check for PCRE regex library.
 
@@ -1356,6 +1372,39 @@
   ],
   [libpcre], [REQUIRED])
 
+### Check for RapidJSON header only library.
+
+AC_LANG_PUSH(C++)
+AC_CHECK_HEADER([rapidjson/rapidjson.h],
+                [have_rapidjson=yes], [have_rapidjson=no])
+
+if test $have_rapidjson = yes; then
+  AC_DEFINE(HAVE_RAPIDJSON, 1, [Define to 1 if RapidJSON is available.])
+
+  ## Additional check on RapidJSON library that was found
+  AC_CACHE_CHECK([for working PrettyWriter in RapidJSON],
+    [octave_cv_rapidjson_has_prettywriter],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+      #include <rapidjson/prettywriter.h>
+      ]], [[
+      rapidjson::StringBuffer json;
+      rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>,
+                              rapidjson::UTF8<>, rapidjson::CrtAllocator,
+                              rapidjson::kWriteNanAndInfFlag> writer (json);
+      ]])],
+      [octave_cv_rapidjson_has_prettywriter=yes],
+      [octave_cv_rapidjson_has_prettywriter=no])
+    ])
+  if test $octave_cv_rapidjson_has_prettywriter = yes; then
+    AC_DEFINE(HAVE_RAPIDJSON_PRETTYWRITER, 1,
+      [Define to 1 if the RapidJSON PrettyWriter function is available.])
+  else
+    rapid_json_warning='Older RapidJSON library found.  The "PrettyWriter" option in jsonencode will be disabled.'
+    OCTAVE_CONFIGURE_WARNING([rapid_json_warning])
+  fi
+fi
+AC_LANG_POP([C++])
+
 ### Check for readline library.
 
 OCTAVE_ENABLE_READLINE
@@ -1382,7 +1431,7 @@
   [zlib.h], [gzclearerr])
 
 ## Also define HAVE_ZLIB if libz is found.
-if test -z "$warn_z"; then
+if test -n "$Z_LIBS"; then
   AC_DEFINE(HAVE_ZLIB, 1, [Define to 1 if ZLIB is available.])
 fi
 
@@ -1604,7 +1653,7 @@
 LIBS="$Z_LDFLAGS $Z_LIBS $LIBS"
 OCTAVE_CHECK_LIB(glpk, GLPK,
   [GLPK library not found.  The glpk function for solving linear programs will be disabled.],
-  [glpk/glpk.h glpk.h], [glp_simplex], [], [],
+  [glpk.h glpk/glpk.h], [glp_simplex], [], [],
   [warn_glpk=
    OCTAVE_CHECK_LIB_GLPK_OK(
     [AC_DEFINE(HAVE_GLPK, 1, [Define to 1 if GLPK is available.])],
@@ -1621,7 +1670,7 @@
 OCTAVE_CHECK_LIB(curl, cURL,
   [cURL library not found.  The ftp objects, urlread, and urlwrite functions will be disabled.],
   [curl/curl.h], [curl_easy_escape])
-if test -z "$warn_curl"; then
+if test -n "$CURL_LIBS"; then
   ## Additional check on cURL library that was found
   AC_CACHE_CHECK([for CURLOPT_DIRLISTONLY in curl/curl.h],
     [octave_cv_curl_has_curlopt_dirlistonly],
@@ -1669,8 +1718,6 @@
     [select library to use for image I/O (options: GraphicsMagick(default) or ImageMagick)])],
   [if test x"$withval" = xno; then
      check_magick=no
-     warn_magick_disabled="--without-magick specified.  The imread, imwrite, and imfinfo functions for reading and writing image files will not be fully functional."
-     OCTAVE_CONFIGURE_WARNING([warn_magick_disabled])
    else
      magick="$withval"
    fi], [magick="GraphicsMagick"])
@@ -1782,8 +1829,6 @@
     [don't use OpenGL libraries, disable OpenGL graphics])],
   [if test x"$withval" = xno; then
      check_opengl=no
-     warn_opengl_disabled="--without-opengl specified.  OpenGL graphics will be disabled."
-     OCTAVE_CONFIGURE_WARNING([warn_opengl_disabled])
    fi])
 
 ## Check for OpenGL library
@@ -1804,7 +1849,6 @@
     [don't use FreeType library, OpenGL graphics will not be fully functional])],
   [if test x"$withval" = xno; then
      check_freetype=no
-     warn_freetype="--without-freetype specified.  OpenGL graphics will not be fully functional."
    fi])
 
 if test $check_freetype = yes; then
@@ -1845,26 +1889,9 @@
   [fontconfig.h fontconfig/fontconfig.h], [FcInit],
   [], [don't use fontconfig library, OpenGL graphics will not be fully functional])
 
-## Check for gl2ps which is required for printing with OpenGL graphics.
-
-AC_CHECK_HEADERS([gl2ps.h],
-  [GL2PS_LIBS="-lgl2ps"],
-  [warn_gl2ps="gl2ps library not found.  Printing of OpenGL graphics will be disabled."])
-
-if test -n "$warn_gl2ps"; then
-  OCTAVE_CONFIGURE_WARNING([warn_gl2ps])
-else
-  save_LIBS="$LIBS"
-  LIBS="$GL2PS_LIBS $LIBS"
-  AC_CHECK_FUNCS([gl2psLineJoin])
-  LIBS="$save_LIBS"
-fi
-
-AC_SUBST(GL2PS_LIBS)
-
 ### GUI/Qt related tests.
 
-QT_VERSIONS="5 4"
+QT_VERSIONS="5"
 
 AC_ARG_WITH([qt],
   [AS_HELP_STRING([--with-qt=VER], [use the Qt major version VER])
@@ -1875,8 +1902,6 @@
      ;;
      no)
        QT_VERSIONS=
-       warn_qt_disabled="--without-qt specified.  The Qt GUI will be disabled."
-       OCTAVE_CONFIGURE_WARNING([warn_qt_disabled])
      ;;
      *)
        QT_VERSIONS="$withval"
@@ -1888,8 +1913,6 @@
   [AS_HELP_STRING([--without-qscintilla], [disable QScintilla editor])],
   [if test x"$withval" = xno; then
      check_qscintilla=no
-     warn_qscintilla_disabled="--without-qscintilla specified.  The GUI editor will be disabled."
-     OCTAVE_CONFIGURE_WARNING([warn_qscintilla_disabled])
    fi])
 
 OCTAVE_CHECK_QT([$QT_VERSIONS])
@@ -2030,6 +2053,25 @@
   opengl_graphics=yes
 fi
 
+## Check for gl2ps which is required for printing with OpenGL graphics.
+
+if test $opengl_graphics = yes; then
+  AC_CHECK_HEADERS([gl2ps.h],
+    [GL2PS_LIBS="-lgl2ps"],
+    [warn_gl2ps="gl2ps library not found.  Printing of OpenGL graphics will be disabled."])
+
+  if test -n "$warn_gl2ps"; then
+    OCTAVE_CONFIGURE_WARNING([warn_gl2ps])
+  else
+    save_LIBS="$LIBS"
+    LIBS="$GL2PS_LIBS $LIBS"
+    AC_CHECK_FUNCS([gl2psLineJoin])
+    LIBS="$save_LIBS"
+  fi
+
+  AC_SUBST(GL2PS_LIBS)
+fi
+
 ### Check for the qrupdate library
 
 dnl No need to adjust FFLAGS because only link is attempted.
@@ -2043,7 +2085,7 @@
   [Fortran 77], [don't use qrupdate, disable QR & Cholesky updating functions])
 
 ## Additional check to see if qrupdate lib found supports LU updates
-if test -z "$warn_qrupdate"; then
+if test -n "$QRUPDATE_LIBS"; then
   AC_CACHE_CHECK([for slup1up in $QRUPDATE_LIBS],
     [octave_cv_func_slup1up],
     [LIBS="$LIBS $QRUPDATE_LIBS"
@@ -2092,7 +2134,7 @@
 
 OCTAVE_CHECK_LIB(amd, AMD,
   [AMD library not found.  This will result in some lack of functionality for sparse matrices.],
-  [suitesparse/amd.h ufsparse/amd.h amd/amd.h amd.h],
+  [amd.h suitesparse/amd.h amd/amd.h],
   [amd_postorder],
   [], [don't use AMD library, disable some sparse matrix functionality])
 
@@ -2100,7 +2142,7 @@
 
 OCTAVE_CHECK_LIB(camd, CAMD,
   [CAMD library not found.  This will result in some lack of functionality for sparse matrices.],
-  [suitesparse/camd.h ufsparse/camd.h camd/camd.h camd.h],
+  [camd.h suitesparse/camd.h camd/camd.h],
   [camd_postorder],
   [], [don't use CAMD library, disable some sparse matrix functionality])
 
@@ -2108,7 +2150,7 @@
 
 OCTAVE_CHECK_LIB(colamd, COLAMD,
   [COLAMD library not found.  This will result in some lack of functionality for sparse matrices.],
-  [suitesparse/colamd.h ufsparse/colamd.h colamd/colamd.h colamd.h],
+  [colamd.h suitesparse/colamd.h colamd/colamd.h],
   [colamd],
   [], [don't use COLAMD library, disable some sparse matrix functionality])
 
@@ -2116,7 +2158,7 @@
 
 OCTAVE_CHECK_LIB(ccolamd, CCOLAMD,
   [CCOLAMD library not found.  This will result in some lack of functionality for sparse matrices.],
-  [suitesparse/ccolamd.h ufsparse/ccolamd.h ccolamd/ccolamd.h ccolamd.h],
+  [ccolamd.h suitesparse/ccolamd.h ccolamd/ccolamd.h],
   [ccolamd],
   [], [don't use CCOLAMD library, disable some sparse matrix functionality])
 
@@ -2128,20 +2170,31 @@
 LIBS="$COLAMD_LDFLAGS $COLAMD_LIBS $AMD_LDFLAGS $AMD_LIBS $LAPACK_LIBS $BLAS_LIBS $FLIBS $LIBS"
 OCTAVE_CHECK_LIB(cholmod, CHOLMOD,
   [CHOLMOD library not found.  This will result in some lack of functionality for sparse matrices.],
-  [suitesparse/cholmod.h ufsparse/cholmod.h cholmod/cholmod.h cholmod.h],
+  [cholmod.h suitesparse/cholmod.h cholmod/cholmod.h],
   [cholmod${CHOLMOD_TAG}start],
   [], [don't use CHOLMOD library, disable some sparse matrix functionality])
 LIBS="$save_LIBS"
 
+### Check for SPQR library
+
+save_LIBS="$LIBS"
+LIBS="$CHOLMOD_LIBS $LIBS"
+OCTAVE_CHECK_LIB(spqr, SPQR,
+  [SPQR library not found.  This will result in some lack of functionality for sparse matrices.],
+  [SuiteSparseQR.hpp suitesparse/SuiteSparseQR.hpp],
+  [SuiteSparseQR_C],
+  [C++], [don't use SPQR library, disable some sparse matrix functionality])
+LIBS="$save_LIBS"
+
 ### Check for CXSparse library
 
 OCTAVE_CHECK_LIB(cxsparse, CXSparse,
   [CXSparse library not found.  This will result in some lack of functionality for sparse matrices.],
-  [suitesparse/cs.h ufsparse/cs.h cxsparse/cs.h cs.h],
+  [cs.h suitesparse/cs.h cxsparse/cs.h],
   [cs${CXSPARSE_TAG}sqr],
   [C++], [don't use CXSparse library, disable some sparse matrix functionality])
 
-if test -z "$warn_cxsparse"; then
+if test -n "$CXSPARSE_LIBS"; then
   ## Additional check for CXSparse version >= 2.2
   if test $octave_cv_lib_cxsparse = yes; then
     OCTAVE_CHECK_CXSPARSE_VERSION_OK
@@ -2159,7 +2212,7 @@
 CPPFLAGS="$AMD_CPPFLAGS $CPPFLAGS"
 OCTAVE_CHECK_LIB([umfpack], UMFPACK,
   [UMFPACK not found.  This will result in some lack of functionality for sparse matrices.],
-  [suitesparse/umfpack.h ufsparse/umfpack.h umfpack/umfpack.h umfpack.h],
+  [umfpack.h suitesparse/umfpack.h umfpack/umfpack.h],
   [umfpack${UMFPACK_TAG}get_determinant],
   [], [don't use UMFPACK, disable some sparse matrix functionality])
 CPPFLAGS="$save_CPPFLAGS"
@@ -2173,7 +2226,7 @@
   LIBS="-lcblas $AMD_LDFLAGS $AMD_LIBS $BLAS_LIBS $FLIBS $LIBS"
   OCTAVE_CHECK_LIB([umfpack], UMFPACK,
     [UMFPACK not found.  This will result in some lack of functionality for sparse matrices.],
-    [suitesparse/umfpack.h ufsparse/umfpack.h umfpack/umfpack.h umfpack.h],
+    [umfpack.h suitesparse/umfpack.h umfpack/umfpack.h],
     [umfpack${UMFPACK_TAG}get_determinant],
     [], [don't use UMFPACK, disable some sparse matrix functionality])
   if test -n "$UMFPACK_LIBS"; then
@@ -2186,7 +2239,7 @@
 
 OCTAVE_CHECK_LIB(klu, KLU,
   [KLU library not found.  This will result in some lack of functionality for sparse matrices.],
-  [suitesparse/klu.h ufsparse/klu.h klu/klu.h klu.h], [klu_solve],
+  [klu.h suitesparse/klu.h klu/klu.h], [klu_solve],
   [], [don't use KLU library, disable some sparse matrix functionality])
 
 ### SUITESPARSECONFIG_LIBS added to LIBS above.
@@ -2198,11 +2251,11 @@
 
 ## Order matters, at least on some systems (Cygwin, for example).
 
-SPARSE_XCPPFLAGS="$CHOLMOD_CPPFLAGS $UMFPACK_CPPFLAGS $AMD_CPPFLAGS $CAMD_CPPFLAGS $COLAMD_CPPFLAGS $CCOLAMD_CPPFLAGS $CXSPARSE_CPPFLAGS"
-
-SPARSE_XLDFLAGS="$CHOLMOD_LDFLAGS $UMFPACK_LDFLAGS $AMD_LDFLAGS $CAMD_LDFLAGS $COLAMD_LDFLAGS  $CCOLAMD_LDFLAGS $CXSPARSE_LDFLAGS"
-
-SPARSE_XLIBS="$CHOLMOD_LIBS $UMFPACK_LIBS $AMD_LIBS $CAMD_LIBS $COLAMD_LIBS $CCOLAMD_LIBS $CXSPARSE_LIBS $SUITESPARSECONFIG_LIBS"
+SPARSE_XCPPFLAGS="$CHOLMOD_CPPFLAGS $UMFPACK_CPPFLAGS $AMD_CPPFLAGS $CAMD_CPPFLAGS $COLAMD_CPPFLAGS $CCOLAMD_CPPFLAGS $CXSPARSE_CPPFLAGS $SPQR_CPPFLAGS"
+
+SPARSE_XLDFLAGS="$CHOLMOD_LDFLAGS $UMFPACK_LDFLAGS $AMD_LDFLAGS $CAMD_LDFLAGS $COLAMD_LDFLAGS  $CCOLAMD_LDFLAGS $CXSPARSE_LDFLAGS $SPQR_LDFLAGS"
+
+SPARSE_XLIBS="$CHOLMOD_LIBS $UMFPACK_LIBS $AMD_LIBS $CAMD_LIBS $COLAMD_LIBS $CCOLAMD_LIBS $CXSPARSE_LIBS $SUITESPARSECONFIG_LIBS $SPQR_LIBS"
 
 AC_SUBST(SPARSE_XCPPFLAGS)
 AC_SUBST(SPARSE_XLDFLAGS)
@@ -2229,55 +2282,61 @@
 
 OCTAVE_CHECK_LIB(sundials_nvecserial, [SUNDIALS NVECTOR],
   [SUNDIALS NVECTOR serial library not found.  The solvers ode15i and ode15s will be disabled.],
-  [nvector/nvector_serial.h nvector_serial.h ], [N_VNew_Serial],
+  [nvector_serial.h nvector/nvector_serial.h], [N_VNew_Serial],
   [], [don't use SUNDIALS NVECTOR library, disable solvers ode15i and ode15s])
 
 ### Check for SUNDIALS IDA library and header.
 
-save_CPPFLAGS="$CPPFLAGS"
-save_LDFLAGS="$LDFLAGS"
-save_LIBS="$LIBS"
-LIBS="$SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS $BLAS_LIBS $FLIBS $LIBS"
-LDFLAGS="$SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS $BLAS_LDFLAGS $LDFLAGS"
-CPPFLAGS="$SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS $BLAS_CPPFLAGS $CPPFLAGS"
-OCTAVE_CHECK_LIB(sundials_ida, [SUNDIALS IDA],
-  [SUNDIALS IDA library not found.  The solvers ode15i and ode15s will be disabled.],
-  [ida/ida.h ida.h], [IDAInit],
-  [], [don't use SUNDIALS IDA library, disable solvers ode15i and ode15s])
-CPPFLAGS="$save_CPPFLAGS"
-LDFLAGS="$save_LDFLAGS"
-LIBS="$save_LIBS"
+if test -n "$SUNDIALS_NVECSERIAL_LIBS"; then
+
+  save_CPPFLAGS="$CPPFLAGS"
+  save_LDFLAGS="$LDFLAGS"
+  save_LIBS="$LIBS"
+  LIBS="$SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS $BLAS_LIBS $FLIBS $LIBS"
+  LDFLAGS="$SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS $BLAS_LDFLAGS $LDFLAGS"
+  CPPFLAGS="$SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS $BLAS_CPPFLAGS $CPPFLAGS"
+  OCTAVE_CHECK_LIB(sundials_ida, [SUNDIALS IDA],
+    [SUNDIALS IDA library not found.  The solvers ode15i and ode15s will be disabled.],
+    [ida.h ida/ida.h], [IDAInit],
+    [], [don't use SUNDIALS IDA library, disable solvers ode15i and ode15s])
+  CPPFLAGS="$save_CPPFLAGS"
+  LDFLAGS="$save_LDFLAGS"
+  LIBS="$save_LIBS"
+fi
 
 ### Check for SUNDIALS library features, some required, some optional.
 
-CPPFLAGS="$SUNDIALS_IDA_CPPFLAGS $SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS $BLAS_CPPFLAGS $CPPFLAGS"
-LDFLAGS="$SUNDIALS_IDA_LDFLAGS $SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS $BLAS_LDFLAGS $LDFLAGS"
-LIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS $BLAS_LIBS $FLIBS $LIBS"
-if test -z "$warn_sundials_nvecserial" && test -z "$warn_sundials_ida"; then
-  dnl Any of the following tests could determine that SUNDIALS is incompatible
-  dnl and should be disabled. In that event, they all populate the same
-  dnl variable with appropriate warning messages, and further tests should be
-  dnl skipped if a warning message has already been generated that SUNDIALS is
-  dnl disabled.
-  warn_sundials_disabled=
-  if test -z "$warn_sundials_disabled"; then
-    OCTAVE_CHECK_SUNDIALS_COMPATIBLE_API
+if test -n "$SUNDIALS_IDA_LIBS" && test -n "$SUNDIALS_NVECSERIAL_LIBS"; then
+
+  CPPFLAGS="$SUNDIALS_IDA_CPPFLAGS $SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS $BLAS_CPPFLAGS $CPPFLAGS"
+  LDFLAGS="$SUNDIALS_IDA_LDFLAGS $SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS $BLAS_LDFLAGS $LDFLAGS"
+  LIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS $BLAS_LIBS $FLIBS $LIBS"
+  if test -z "$warn_sundials_nvecserial" && test -z "$warn_sundials_ida"; then
+    dnl Any of the following tests could determine that SUNDIALS is incompatible
+    dnl and should be disabled. In that event, they all populate the same
+    dnl variable with appropriate warning messages, and further tests should be
+    dnl skipped if a warning message has already been generated that SUNDIALS is
+    dnl disabled.
+    warn_sundials_disabled=
+    if test -z "$warn_sundials_disabled"; then
+      OCTAVE_CHECK_SUNDIALS_COMPATIBLE_API
+    fi
+    if test -z "$warn_sundials_disabled"; then
+      OCTAVE_CHECK_SUNDIALS_SIZEOF_REALTYPE
+    fi
+    if test -z "$warn_sundials_disabled"; then
+      OCTAVE_CHECK_SUNDIALS_SUNLINSOL_DENSE
+    fi
+    dnl The following tests determine whether certain optional features are
+    dnl present in the SUNDIALS libraries, but will not disable using SUNDIALS.
+    if test -z "$warn_sundials_disabled"; then
+      OCTAVE_CHECK_SUNDIALS_SUNLINSOL_KLU
+    fi
   fi
-  if test -z "$warn_sundials_disabled"; then
-    OCTAVE_CHECK_SUNDIALS_SIZEOF_REALTYPE
-  fi
-  if test -z "$warn_sundials_disabled"; then
-    OCTAVE_CHECK_SUNDIALS_SUNLINSOL_DENSE
-  fi
-  dnl The following tests determine whether certain optional features are
-  dnl present in the SUNDIALS libraries, but will not disable using SUNDIALS.
-  if test -z "$warn_sundials_disabled"; then
-    OCTAVE_CHECK_SUNDIALS_SUNLINSOL_KLU
-  fi
+  CPPFLAGS="$save_CPPFLAGS"
+  LDFLAGS="$save_LDFLAGS"
+  LIBS="$save_LIBS"
 fi
-CPPFLAGS="$save_CPPFLAGS"
-LDFLAGS="$save_LDFLAGS"
-LIBS="$save_LIBS"
 
 dnl Define this way instead of with an #if in oct-conf-post.h so that
 dnl the build features script will get the correct value.
@@ -2286,36 +2345,36 @@
 dnl How can we do a better job here?  Do we need to disable sundials
 dnl any tests fail, or can we fix __ode15__.cc so that it still partially
 dnl works when some things are missing (for example, KLU)?
-if test -n "$SUNDIALS_IDA_LIBS" \
-    && test -n "$SUNDIALS_NVECSERIAL_LIBS" \
-    && test "x$octave_cv_sundials_sunlinsol_dense" = xyes \
-    && test "x$octave_cv_sundials_realtype_is_double" = xyes \
-    && test "x$octave_have_sundials_compatible_api" = xyes; then
-  AC_DEFINE(HAVE_SUNDIALS, 1, [Define to 1 if SUNDIALS is available.])
-
-  ## Collections of options needed to build with SUNDIALS and its dependencies.
-  SUNDIALS_XCPPFLAGS="$SUNDIALS_IDA_CPPFLAGS $SUNDIALS_SUNLINSOLKLU_CPPFLAGS $SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS"
-  SUNDIALS_XLDFLAGS="$SUNDIALS_IDA_LDFLAGS $SUNDIALS_SUNLINSOLKLU_LDFLAGS $SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS"
-  SUNDIALS_XLIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_SUNLINSOLKLU_LIBS $SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS"
-else
-  SUNDIALS_IDA_CPPFLAGS=
-  SUNDIALS_IDA_LDFLAGS=
-  SUNDIALS_IDA_LIBS=
-  SUNDIALS_SUNLINSOLKLU_CPPFLAGS=
-  SUNDIALS_SUNLINSOLKLU_LDFLAGS=
-  SUNDIALS_SUNLINSOLKLU_LIBS=
-  SUNDIALS_NVECSERIAL_CPPFLAGS=
-  SUNDIALS_NVECSERIAL_LDFLAGS=
-  SUNDIALS_NVECSERIAL_LIBS=
-  SUNDIALS_XCPPFLAGS=
-  SUNDIALS_XLDFLAGS=
-  SUNDIALS_XLIBS=
-  dnl Emit a fallback warning message in case SUNDIALS has been disabled for
-  dnl some reason that hasn't already generated one of these known warnings.
-  if test -z "$warn_sundials_nvecserial" && test -z "$warn_sundials_ida" \
-      && test -z "$warn_sundials_disabled"; then
-    warn_sundials_disabled="SUNDIALS libraries are missing some feature.  The solvers ode15i and ode15s will be disabled."
-    OCTAVE_CONFIGURE_WARNING([warn_sundials_disabled])
+if test -n "$SUNDIALS_IDA_LIBS" && test -n "$SUNDIALS_NVECSERIAL_LIBS"; then
+  if test "x$octave_cv_sundials_sunlinsol_dense" = xyes \
+      && test "x$octave_cv_sundials_realtype_is_double" = xyes \
+      && test "x$octave_have_sundials_compatible_api" = xyes; then
+    AC_DEFINE(HAVE_SUNDIALS, 1, [Define to 1 if SUNDIALS is available.])
+
+    ## Options needed to build with SUNDIALS and its dependencies.
+    SUNDIALS_XCPPFLAGS="$SUNDIALS_IDA_CPPFLAGS $SUNDIALS_SUNLINSOLKLU_CPPFLAGS $SUNDIALS_NVECSERIAL_CPPFLAGS $KLU_CPPFLAGS"
+    SUNDIALS_XLDFLAGS="$SUNDIALS_IDA_LDFLAGS $SUNDIALS_SUNLINSOLKLU_LDFLAGS $SUNDIALS_NVECSERIAL_LDFLAGS $KLU_LDFLAGS"
+    SUNDIALS_XLIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_SUNLINSOLKLU_LIBS $SUNDIALS_NVECSERIAL_LIBS $KLU_LIBS"
+  else
+    SUNDIALS_IDA_CPPFLAGS=
+    SUNDIALS_IDA_LDFLAGS=
+    SUNDIALS_IDA_LIBS=
+    SUNDIALS_SUNLINSOLKLU_CPPFLAGS=
+    SUNDIALS_SUNLINSOLKLU_LDFLAGS=
+    SUNDIALS_SUNLINSOLKLU_LIBS=
+    SUNDIALS_NVECSERIAL_CPPFLAGS=
+    SUNDIALS_NVECSERIAL_LDFLAGS=
+    SUNDIALS_NVECSERIAL_LIBS=
+    SUNDIALS_XCPPFLAGS=
+    SUNDIALS_XLDFLAGS=
+    SUNDIALS_XLIBS=
+    dnl Emit a fallback warning message in case SUNDIALS has been disabled for
+    dnl some reason that hasn't already generated one of these known warnings.
+    if test -z "$warn_sundials_nvecserial" && test -z "$warn_sundials_ida" \
+        && test -z "$warn_sundials_disabled"; then
+      warn_sundials_disabled="SUNDIALS libraries are missing some feature.  The solvers ode15i and ode15s will be disabled."
+      OCTAVE_CONFIGURE_WARNING([warn_sundials_disabled])
+    fi
   fi
 fi
 
@@ -2336,7 +2395,7 @@
    OCTAVE_CHECK_LIB_ARPACK_OK_1(
      [AC_DEFINE(HAVE_ARPACK, 1, [Define to 1 if ARPACK is available.])],
      [warn_arpack="ARPACK library found, but does not seem to work properly; disabling eigs function"])
-   if test -z "$warn_arpack"; then
+   if test -n "$ARPACK_LIBS"; then
      OCTAVE_CHECK_LIB_ARPACK_OK_2([],
        [AC_MSG_WARN([ARPACK library found, but is buggy; upgrade library (>= v3.3.0) for better results])])
    fi
@@ -2473,7 +2532,6 @@
         else
           JAVA_CPPFLAGS="-I\"${JAVA_HOME}/include\" -I\"${JAVA_HOME}/include/win32\""
         fi
-        LDFLAGS="$LDFLAGS -Wl,--export-all-symbols"
       fi
       AC_DEFINE(HAVE_JAVA, 1,
         [Define to 1 if Java is available and is at least version 1.5])
@@ -2613,6 +2671,7 @@
      warn_docs="building documentation disabled; make dist will fail."
      OCTAVE_CONFIGURE_WARNING([warn_docs])
    fi], [])
+
 if test $ENABLE_DOCS = yes; then
   if test $opengl_graphics = no || test "$have_qt_opengl_offscreen" = no; then
     if test -n "$warn_gnuplot"; then
@@ -2631,6 +2690,7 @@
   AC_DEFINE(ENABLE_DOCS, 1,
     [Define to 1 to build Octave documentation files.])
 fi
+
 AM_CONDITIONAL([AMCOND_BUILD_DOCS], [test $ENABLE_DOCS = yes])
 
 AM_CONDITIONAL([AMCOND_BUILD_QT_DOCS],
@@ -2664,6 +2724,64 @@
   [if test "$enableval" = yes; then install_build_logs=yes; fi])
 AM_CONDITIONAL([AMCOND_INSTALL_BUILD_LOGS], [test $install_build_logs = yes])
 
+### Determine whether libraries should be linked with visibility attributes
+
+ENABLE_LIB_VISIBILITY_FLAGS=yes
+AC_ARG_ENABLE(lib-visibility-flags,
+  [AS_HELP_STRING([--disable-lib-visibility-flags],
+    [don't build libraries with visibility flags (export all symbols)])],
+  [case $enableval in
+     yes) ENABLE_LIB_VISIBILITY_FLAGS=yes ;;
+     no) ENABLE_LIB_VISIBILITY_FLAGS=no ;;
+     *) AC_MSG_ERROR([bad value $enableval for --enable-lib-visibility-flags]) ;;
+   esac])
+
+if test $ENABLE_LIB_VISIBILITY_FLAGS = yes && test $HAVE_VISIBILITY = 0; then
+  AC_MSG_NOTICE([cannot build with visibility flags on this platform])
+  ENABLE_LIB_VISIBILITY_FLAGS=no
+fi
+
+if test $ENABLE_LIB_VISIBILITY_FLAGS = yes; then
+  AC_DEFINE(OCTAVE_ENABLE_LIB_VISIBILITY_FLAGS, 1,
+    [Define to 1 if building libraries with visibility flags])
+else
+  case $host_os in
+    msdosmsvc | mingw* | cygwin*)
+      LDFLAGS="$LDFLAGS -Wl,--export-all-symbols"
+    ;;
+  esac
+fi
+
+AM_CONDITIONAL([AMCOND_LIB_VISIBILITY_FLAGS],
+  [test $ENABLE_LIB_VISIBILITY_FLAGS = yes])
+
+### Set flags for symbol visibility
+
+if test $ENABLE_LIB_VISIBILITY_FLAGS = yes; then
+  EXTERNAL_DLL_DEFS="-DEXTERNAL_DLL"
+  OCTAVE_DLL_DEFS="-DOCTAVE_DLL"
+  OCTINTERP_DLL_DEFS="-DOCTINTERP_DLL"
+  OCTGUI_DLL_DEFS="-DOCTGUI_DLL"
+  OCTGRAPHICS_DLL_DEFS="-DOCTGRAPHICS_DLL"
+else
+  EXTERNAL_DLL_DEFS=
+  OCTAVE_DLL_DEFS=
+  OCTINTERP_DLL_DEFS=
+  OCTGUI_DLL_DEFS=
+  OCTGRAPHICS_DLL_DEFS=
+fi
+AC_MSG_NOTICE([defining EXTERNAL_DLL_DEFS to be $EXTERNAL_DLL_DEFS])
+AC_MSG_NOTICE([defining OCTAVE_DLL_DEFS to be $OCTAVE_DLL_DEFS])
+AC_MSG_NOTICE([defining OCTINTERP_DLL_DEFS to be $OCTINTERP_DLL_DEFS])
+AC_MSG_NOTICE([defining OCTGUI_DLL_DEFS to be $OCTGUI_DLL_DEFS])
+AC_MSG_NOTICE([defining OCTGRAPHICS_DLL_DEFS to be $OCTGRAPHICS_DLL_DEFS])
+
+AC_SUBST(EXTERNAL_DLL_DEFS)
+AC_SUBST(OCTAVE_DLL_DEFS)
+AC_SUBST(OCTINTERP_DLL_DEFS)
+AC_SUBST(OCTGUI_DLL_DEFS)
+AC_SUBST(OCTGRAPHICS_DLL_DEFS)
+
 ### Add extra compiler flags now that feature testing is complete.
 
 ## Add warning flags
@@ -2772,19 +2890,19 @@
 
 ### Check for GCC-specific pragmas to control warnings.
 
+AC_LANG_PUSH(C++)
 AC_CACHE_CHECK([for @%:@pragma GCC diagnostic push/pop/ignore],
   [octave_cv_gcc_has_pragma_GCC_diagnostic],
-  [AC_LANG_PUSH(C++)
-   AC_TRY_COMPILE([], [
+  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignore "-Wold-style-cast"
   int three = (int) 3.1415926;
 #pragma GCC diagnostic pop
-    ],
+    ]])],
     [octave_cv_gcc_has_pragma_GCC_diagnostic=yes],
-    [octave_cv_gcc_has_pragma_GCC_diagnostic=no])
-   AC_LANG_POP(C++)],
+    [octave_cv_gcc_has_pragma_GCC_diagnostic=no])],
   ])
+AC_LANG_POP(C++)
 
 if test $octave_cv_gcc_has_pragma_GCC_diagnostic = yes; then
   AC_DEFINE(HAVE_PRAGMA_GCC_DIAGNOSTIC, 1,
@@ -2847,6 +2965,8 @@
 OCT_GUI_LINK_OPTS="$LDFLAGS"
 
 if test $link_all_deps = yes; then
+  AC_DEFINE(OCTAVE_LINK_ALL_DEPS, 1, [Link with all dependencies.])
+
   OCT_LINK_DEPS="libinterp/liboctinterp.la liboctave/liboctave.la"
   OCT_GUI_LINK_DEPS="libgui/liboctgui.la libinterp/liboctinterp.la liboctave/liboctave.la"
 
@@ -3021,10 +3141,9 @@
   [$SHELL $srcdir/build-aux/move-if-change oct-conf-post.h-tmp oct-conf-post.h])
 
 OCTAVE_CONFIG_MOVE_IF_CHANGE_FILES([
-  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])
@@ -3140,6 +3259,9 @@
   Sndfile CPPFLAGS:              $SNDFILE_CPPFLAGS
   Sndfile LDFLAGS:               $SNDFILE_LDFLAGS
   Sndfile libraries:             $SNDFILE_LIBS
+  SPQR CPPFLAGS:                 $SPQR_CPPFLAGS
+  SPQR LDFLAGS:                  $SPQR_LDFLAGS
+  SPQR libraries:                $SPQR_LIBS
   SuiteSparse config libraries:  $SUITESPARSECONFIG_LIBS
   SUNDIALS IDA CPPFLAGS:         $SUNDIALS_IDA_CPPFLAGS
   SUNDIALS IDA LDFLAGS:          $SUNDIALS_IDA_LDFLAGS
--- a/doc/interpreter/arith.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/arith.txi	Sun May 16 09:44:35 2021 +0200
@@ -198,6 +198,12 @@
 @DOCSTRING(acscd)
 @DOCSTRING(acotd)
 
+Finally, there are two trigonometric functions that calculate special
+arguments with increased accuracy.
+
+@DOCSTRING(sinpi)
+@DOCSTRING(cospi)
+
 @node Sums and Products
 @section Sums and Products
 
--- a/doc/interpreter/container.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/container.txi	Sun May 16 09:44:35 2021 +0200
@@ -914,11 +914,11 @@
 The following string functions support cell arrays of strings:
 @code{char}, @code{strvcat}, @code{strcat} (@pxref{Concatenating
 Strings}), @code{strcmp}, @code{strncmp}, @code{strcmpi},
-@code{strncmpi} (@pxref{Comparing Strings}), @code{str2double},
+@code{strncmpi} (@pxref{Searching in Strings}), @code{str2double},
 @code{deblank}, @code{strtrim}, @code{strtrunc}, @code{strfind},
 @code{strmatch}, , @code{regexp}, @code{regexpi}
-(@pxref{Manipulating Strings}) and @code{str2double}
-(@pxref{String Conversions}).
+(@pxref{String Operations}) and @code{str2double}
+(@pxref{Converting Strings}).
 
 The function @code{iscellstr} can be used to test if an object is a
 cell array of strings.
--- a/doc/interpreter/contributors.in	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/contributors.in	Sun May 16 09:44:35 2021 +0200
@@ -41,6 +41,7 @@
 Marcus Brinkmann
 Max Brister
 Remy Bruno
+Stefan Brüns
 Clemens Buchacher
 Ansgar Burchard
 Antonius Burgers
@@ -89,6 +90,7 @@
 Paul Eggert
 Stephen Eglen
 Peter Ekberg
+Abdallah K. Elshamy
 Garrett Euler
 Edmund Grimley Evans
 Rolf Fabian
@@ -191,6 +193,7 @@
 Alexander Klein
 Lasse Kliemann
 Geoffrey Knauth
+Martin Köhler
 Heine Kolltveit
 Ken Kouno
 Kacper Kowalik
@@ -227,6 +230,7 @@
 David Livings
 Barbara Locsi
 Sebastien Loisel
+Andrej Lojdl
 Erik de Castro Lopo
 Massimo Lorenzin
 Emil Lucretiu
@@ -247,6 +251,7 @@
 Laurent Mazet
 G. D. McBain
 Ronald van der Meer
+Markus Meisinger
 Júlio Hoffimann Mendes
 Ed Meyer
 Thorsten Meyer
@@ -286,6 +291,7 @@
 Peter O'Gorman
 Thorsten Ohl
 Kai T. Ohlhus
+Serkan Önder
 Arno Onken
 Valentin Ortega-Clavero
 Luis F. Ortiz
@@ -325,6 +331,7 @@
 Lukas Reichlin
 Michael Reifenberger
 Ernst Reissner
+Reinhard Resch
 Jens Restemeier
 Anthony Richardson
 Jason Riedy
@@ -419,6 +426,7 @@
 Sébastien Villemot
 Marco Vitetta
 Daniel Wagenaar
+Steven Waldrip
 Thomas Walter
 Jun Wang
 Andreas Weber
--- a/doc/interpreter/doccheck/README	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/doccheck/README	Sun May 16 09:44:35 2021 +0200
@@ -78,7 +78,7 @@
 which can be added to the private dictionary.  Instead the source is marked up:
 Manchester @nospell{Centre} for Computational Mathematics.
 
-aspell will no longer reports any misspellings for linalg.texi.
+aspell will no longer report any misspellings for linalg.texi.
 
 GRAMMAR:
 
--- a/doc/interpreter/doccheck/aspell-octave.en.pws	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/doccheck/aspell-octave.en.pws	Sun May 16 09:44:35 2021 +0200
@@ -1,13 +1,14 @@
 personal_ws-1.1 en 1
 AbsTol
 accumarray
+Acknowledgements
 acknowledgements
-Acknowledgements
 adams
 Affero
 afterwards
 al
 aleph
+allocatable
 amd
 amongst
 anisotropic
@@ -21,8 +22,6 @@
 arpack
 ArrayValued
 ascii
-Associativity
-associativity
 ast
 async
 atan
@@ -30,12 +29,11 @@
 audiodevinfo
 audioplayer
 audiorecorder
-AutoCAD
 Autoconf
 autocorrelated
 autocovariances
+autoload
 Autoload
-autoload
 autoloaded
 Autoloading
 Automake
@@ -52,29 +50,28 @@
 Barycentric
 basevalue
 BaseValue
+BDF
 bdf
-BDF
 benchmarking
 betacdf
 betainc
 betainv
 betaln
 betapdf
-betarnd
 BFGS
 BICG
 BiConjugate
+biharmonic
 bincoeff
 binocdf
 binoinv
 binopdf
-binornd
 Biomathematics
-bitmapped
 bitwise
 blas
 bmp
 boolean
+Booleans
 boolMatrix
 boxoff
 boxon
@@ -102,8 +99,8 @@
 cd
 cdata
 cdatamapping
+CDF
 cdf
-CDF
 cdot
 ceil
 cellstr
@@ -146,11 +143,11 @@
 colorcube
 colormap
 colormaps
+colororder
 ColorOrder
-colororder
 colperm
+CommentStyle
 commentstyle
-CommentStyle
 ComplexEqn
 cond
 condest
@@ -159,10 +156,10 @@
 const
 contextless
 contourc
+ConvertInfAndNaN
 convhull
 Convolve
 copyrightable
-CorelDraw
 corrcoef
 cosecant
 courseware
@@ -201,8 +198,8 @@
 daspk
 dasrt
 dassl
+DataAspectRatio
 dataset
-datasets
 datasource
 datenum
 datenums
@@ -221,17 +218,16 @@
 delaunay
 Delaunay
 delaunayn
+deletefcn
 DeleteFcn
-deletefcn
 delim
 deltaX
-demi
 det
 dggsvd
 diag
 diagcomp
+dialogs
 Dialogs
-dialogs
 diamondsuit
 differentiable
 digamma
@@ -254,7 +250,6 @@
 doublearrow
 downarrow
 downdate
-dpi
 droptol
 dt
 dx
@@ -273,31 +268,31 @@
 elementwise
 elseif
 emacs
+EmptyValue
 emptyvalue
-EmptyValue
 encodings
 endfunction
+Endian
 endian
-Endian
 endif
+EndOfLine
 endofline
-EndOfLine
 EOF
 EOLs
 eps
 eq
 equidistributed
+Equilibration
 equilibration
-Equilibration
 equispaced
 erf
 erfc
 erfi
 errno
+Errorbar
 errorbar
-Errorbar
+Errorbars
 errorbars
-Errorbars
 errordlg
 ErrorHandler
 ESC
@@ -312,11 +307,10 @@
 expcdf
 expinv
 exppdf
-exprnd
 extendedtext
 extrema
+FaceColor
 facecolor
-FaceColor
 FaceLighting
 FaceNormals
 FaceVertexCData
@@ -334,8 +328,8 @@
 fieldname
 fieldnames
 FIFOs
+filename
 FileName
-filename
 filenames
 filepaths
 Filesystem
@@ -346,11 +340,13 @@
 fitboxtotext
 FIXME
 flac
+fltk
 FLTK
-fltk
 fminsearch
 fminunc
+FontConfig
 fontconfig
+FontName
 fontname
 forall
 forcecelloutput
@@ -362,9 +358,8 @@
 FreeBSD
 FreeSans
 freespacing
+freetype
 FreeType
-freetype
-frnd
 Fs
 FSF
 fullpath
@@ -374,7 +369,6 @@
 gamcdf
 gaminv
 gampdf
-gamrnd
 gaussian
 gca
 gcbo
@@ -382,11 +376,9 @@
 gcd
 ge
 GECOS
-genvarname
 geocdf
 geoinv
 geopdf
-geornd
 geotagging
 geq
 gesdd
@@ -394,17 +386,17 @@
 gfortran
 Ghostscript
 Ghostscript's
+GIF
 gif
-GIF
 glibc
 globbing
 glpk
+GLS
 gls
-GLS
 glyphs
 GMRES
+gnuplot
 Gnuplot
-gnuplot
 GNUTERM
 Goto
 goto
@@ -428,13 +420,13 @@
 HandleVisibility
 handlevisibility
 Hankel
+Hanning
 hanning
-Hanning
 hardcode
 hardcoded
 hardcoding
+hdf
 HDF
-hdf
 HeaderLines
 headerlines
 headlength
@@ -451,20 +443,19 @@
 hggroups
 hgid
 hgload
+hh
 HH
-hh
 histc
 holomorphic
 horizontalalignment
 horzcat
 hostname
+HSV
 hsv
-HSV
 html
 hygecdf
 hygeinv
 hygepdf
-hygernd
 hypervolume
 ichol
 ict
@@ -476,6 +467,7 @@
 ifft
 ifftn
 ignorecase
+IgnoreCase
 ij
 ilu
 ilutp
@@ -492,7 +484,6 @@
 InitialStep
 InitialValue
 inline
-Inline
 inmax
 inmin
 inpolygon
@@ -545,12 +536,13 @@
 JConstant
 JDK
 JIS
+jit
 JIT
-jit
 JPattern
 jpeg
 JPEG
 jpg
+JSON
 jvm
 JVM's
 kendall
@@ -606,9 +598,8 @@
 logncdf
 logninv
 lognpdf
-lognrnd
+lookup
 Lookup
-lookup
 lookups
 lossless
 lsode
@@ -649,11 +640,10 @@
 meshgridded
 meshstyle
 metadata
+metafile
 Metafile
 MetaFile
-metafile
 metafiles
-Metafont
 mex
 mget
 michol
@@ -669,8 +659,8 @@
 mkoctfile
 mldivide
 mmd
+mmm
 MMM
-mmm
 mmmm
 mmmyy
 mmmyyyy
@@ -683,12 +673,12 @@
 MStateDependence
 MSYS
 mtimes
+Multi
 multi
-Multi
 multibyte
 multipage
+multipledelimsasone
 MultipleDelimsAsOne
-multipledelimsasone
 MultiSelect
 multistep
 MvPattern
@@ -696,8 +686,8 @@
 myclass
 myfun
 nabla
+namespace
 NAMESPACE
-namespace
 nan
 NaN
 nancond
@@ -705,10 +695,10 @@
 NaNs
 nargin
 nargout
+natively
 nbincdf
 nbininv
 nbinpdf
-nbinrnd
 ncols
 nd
 ndgrid
@@ -717,7 +707,6 @@
 neq
 NeXT
 NextPlot
-nfev
 nfft
 ni
 NLP
@@ -730,7 +719,6 @@
 nonconformant
 nondecreasing
 nonincreasing
-nonmodal
 nonnan
 NonNegative
 nonnegativity
@@ -747,7 +735,6 @@
 normest
 norminv
 normpdf
-normrnd
 northeastoutside
 northoutside
 NorthOutside
@@ -775,8 +762,8 @@
 onCleanup
 online
 OpenBLAS
+OpenGL
 opengl
-OpenGL
 OpenJDK
 oplus
 optimizations
@@ -796,8 +783,8 @@
 overdetermined
 overridable
 paperorientation
+paperposition
 PaperPosition
-paperposition
 paperpositionmode
 papersize
 paperunits
@@ -805,7 +792,6 @@
 parametrically
 parseparams
 pbm
-PBM
 PBMplus
 pc
 PCG
@@ -815,8 +801,8 @@
 pcre
 PCRE
 PCX
+PDF
 pdf
-PDF
 pdflatex
 pentadiagonal
 periodogram
@@ -825,16 +811,16 @@
 PGMRES
 PHP
 pict
+piecewise
 Piecewise
-piecewise
 pinv
 PixelRegion
+PlotBoxAspectRatio
+png
 PNG
-png
 poisscdf
 poissinv
 poisspdf
-poissrnd
 polyderiv
 polyeig
 polyfit
@@ -859,10 +845,11 @@
 prepended
 preselected
 presolver
+PrettyWriter
 printf
 priori
+Profiler
 profiler
-Profiler
 programmatically
 prolate
 PromptString
@@ -877,12 +864,12 @@
 pushbutton
 pushbuttons
 Pxx
+Qhull
 qhull
-Qhull
 QP
 QQ
+qrupdate
 QRUPDATE
-qrupdate
 QScintilla
 quadcc
 quadgk
@@ -897,8 +884,8 @@
 quartile
 questdlg
 Quickhull
+qz
 QZ
-qz
 radian
 radians
 radices
@@ -927,7 +914,6 @@
 relicensing
 RelTol
 renderer
-renderers
 repelems
 replacechildren
 ReplacementStyle
@@ -936,8 +922,8 @@
 reproducibility
 resampled
 resampling
+Resize
 resize
-Resize
 resized
 resizing
 Resizing
@@ -1029,8 +1015,8 @@
 ss
 sT
 stairstep
+Startup
 startup
-Startup
 statinfo
 stdin
 stdout
@@ -1038,9 +1024,12 @@
 STFT
 str
 strcmp
+streamribbon
+Streamribbons
+streamribbons
 streamtube
+Streamtubes
 streamtubes
-Streamtubes
 stringanchors
 strncmp
 strncmpi
@@ -1101,12 +1090,12 @@
 svd
 SVD
 svds
+svg
 SVG
-svg
+Sym
 sym
-Sym
+symamd
 SYMAMD
-symamd
 symbfact
 symrcm
 Syntaxes
@@ -1114,8 +1103,8 @@
 terminal's
 tex
 texi
+Texinfo
 texinfo
-Texinfo
 TextAlphaBits
 textarrow
 textbackgroundcolor
@@ -1140,7 +1129,6 @@
 togglebutton
 togglebuttons
 tokenExtents
-TolF
 TolFun
 TolX
 toolchain
@@ -1162,9 +1150,8 @@
 triplot
 trisurf
 trivariate
-trnd
+TrueColor
 truecolor
-TrueColor
 tuples
 txi
 typedefs
@@ -1174,37 +1161,36 @@
 uchar
 UHESS
 UI
+uibuttongroup
 Uibuttongroup
-uibuttongroup
-uibuttongroups
 Uicontextmenu
 uicontextmenu
+uicontrol
 Uicontrol
-uicontrol
 uicontrols
 UID
 uimenu
 uint
+Uipanel
 uipanel
-Uipanel
 uipanels
+Uipushtool
 uipushtool
-Uipushtool
 uipushtools
 uiputfile
 uitab
+Uitable
 uitable
-Uitable
 Uitoggletool
 uitoggletool
+Uitoolbar
 uitoolbar
-Uitoolbar
 ulong
 Ultrix
 umfpack
 uminus
+Unary
 unary
-Unary
 unconvertible
 undirected
 unifcdf
@@ -1212,7 +1198,6 @@
 UniformOutput
 UniformValues
 unifpdf
-unifrnd
 unimodal
 Uninstall
 uninstalled
@@ -1249,8 +1234,8 @@
 vech
 vectorization
 vectorize
+Vectorized
 vectorized
-Vectorized
 vectorizing
 vee
 versa
@@ -1266,31 +1251,28 @@
 Voronoi
 waitbar
 waitbars
-warndlg
 wav
 WAV
-WayPoints
 Waypoints
 waypoints
+WayPoints
 wblcdf
 wblinv
 wblpdf
-wblrnd
 westoutside
 WestOutside
+whitespace
 Whitespace
-whitespace
 whos
-wienrnd
 Wikipedia
 wildcard
+wildcards
 Wildcards
-wildcards
 windowbuttondownfcn
 windowbuttonmotionfcn
 windowbuttonupfcn
+WindowStyle
 windowstyle
-WindowStyle
 WIPO
 wireframe
 wlen
@@ -1346,8 +1328,8 @@
 ypos
 yticklabels
 yticks
+YY
 yy
-YY
 YYYY
 yyyy
 yyyymmddTHHMMSS
--- a/doc/interpreter/doccheck/mk_undocumented_list	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/doccheck/mk_undocumented_list	Sun May 16 09:44:35 2021 +0200
@@ -64,10 +64,12 @@
 }
 
 # Second, remove functions based on directory location
-# deprecated directory, doc/interpreter directory, test/ directory
+# deprecated directory, legacy directory, doc/interpreter directory,
+# test/ directory
 FUNC: foreach $idx (0 .. $#where)
 {
   next FUNC if ($where[$idx] =~ /deprecated/i);
+  next FUNC if ($where[$idx] =~ /legacy/i);
   next FUNC if ($where[$idx] =~ /interpreter/i);
   next FUNC if ($where[$idx] =~ m#test/#i);
 
@@ -81,7 +83,8 @@
 # Fourth, remove exceptions based on name that do not require documentation
 # Load list of function exceptions not requiring a DOCSTRING
 # Exception data is stored at the bottom of this script
-map { chomp, $exceptions{$_}=1; } <DATA>;
+foreach $_ (<DATA>)
+{ chomp, $exceptions{$_}=1; }
 
 # Remove exception data from the list
 @functions = grep (! $exceptions{$_}, @functions);
@@ -135,6 +138,7 @@
 flipdim
 fmod
 gammaln
+gui_mainfcn
 home
 i
 ifelse
--- a/doc/interpreter/func.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/func.txi	Sun May 16 09:44:35 2021 +0200
@@ -115,7 +115,7 @@
 @end example
 
 The @code{printf} statement (@pxref{Input and Output}) simply tells
-Octave to print the string @qcode{"@xbackslashchar{}a"}.  The special character
+Octave to print the string @qcode{"@backslashchar{}a"}.  The special character
 @samp{\a} stands for the alert character (ASCII 7).  @xref{Strings}.
 
 Once this function is defined, you can ask Octave to evaluate it by
@@ -924,6 +924,8 @@
 
 @DOCSTRING(dir_in_loadpath)
 
+@DOCSTRING(dir_encoding)
+
 @node Subfunctions
 @subsection Subfunctions
 
@@ -1804,6 +1806,8 @@
 
 @DOCSTRING(str2func)
 
+@DOCSTRING(symvar)
+
 @node Anonymous Functions
 @subsection Anonymous Functions
 
--- a/doc/interpreter/genpropdoc.m	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/genpropdoc.m	Sun May 16 09:44:35 2021 +0200
@@ -39,9 +39,10 @@
 
 function genpropdoc (objname, fname = "", props = {})
   objnames = {"root", "figure", "axes", "legend", ...
-              "image", "light", "line", "patch", "surface", "text", ...
-              "uibuttongroup", "uicontextmenu", "uicontrol", "uipanel", ...
-              "uimenu", "uipushtool", "uitable", "uitoggletool", "uitoolbar"
+              "image", "light", "line", "patch", "scatter", "surface", ...
+              "text", "uibuttongroup", "uicontextmenu", "uicontrol", ...
+              "uipanel", "uimenu", "uipushtool", "uitable", ...
+              "uitoggletool", "uitoolbar"
              };
 
   ## Base properties
@@ -169,6 +170,11 @@
         s.doc = "If __prop__ is @qcode{\"on\"}, the __objname__ is \
 clipped in its parent axes limits.";
 
+      case "contextmenu"
+        s.doc = "Graphics handle of the uicontextmenu object that is \
+currently associated to this __objname__ object.";
+        s.valid = valid_handle;
+
       case "createfcn"
         s.doc = "Callback function executed immediately after __objname__ \
 has been created.  Function is set by using default property on root object, \
@@ -228,11 +234,6 @@
         s.valid = valid_string;
         s.printdefault = false;
 
-      case "uicontextmenu"
-        s.doc = "Graphics handle of the uicontextmenu object that is \
-currently associated to this __objname__ object.";
-        s.valid = valid_handle;
-
       case "userdata"
         s.doc = "User-defined data to associate with the graphics object.";
         s.valid = "Any Octave data";
@@ -656,12 +657,6 @@
         s.doc = doc_unused;
 
       ## Specific properties
-      case "activepositionproperty"
-        s.doc = "Specify which of @qcode{\"position\"} or \
-@qcode{\"outerposition\"} properties takes precedence when axes \
-annotations extent changes.  @xref{XREFaxesposition, , @w{position property}}, \
-and @ref{XREFaxesposition, , @w{outerposition property}}.";
-
       case "alim"
         s.doc = sprintf (doc_notimpl, "Transparency");
 
@@ -769,6 +764,11 @@
 
       case "gridlinestyle"
 
+      case "innerposition"
+        s.doc = "The @qcode{\"innerposition\"} property is the same as the \
+@ref{XREFaxesposition, , @w{@qcode{\"position\"} property}}.";
+        s.valid = valid_4elvec;
+
       case "labelfontsizemultiplier"
         s.doc = "Ratio between the x/y/zlabel fontsize and the tick \
 label fontsize";
@@ -844,6 +844,13 @@
         endif
         s.valid = valid_4elvec;
 
+      case "positionconstraint"
+        s.doc = "Specify which of @qcode{\"innerposition\"} or \
+@qcode{\"outerposition\"} properties takes precedence when axes \
+annotations extent changes.  \
+@xref{XREFaxesinnerposition, , @w{@qcode{\"innerposition\"} property}}, \
+and @ref{XREFaxesouterposition, , @w{@qcode{\"outerposition\"} property}}.";
+
       case "projection"
         s.doc = doc_unused;
 
@@ -1621,6 +1628,117 @@
 
     endswitch
 
+  ## Scatter properties
+  elseif (strcmp (objname, "scatter"))
+    switch (field)
+      ## Overridden shared properties
+      case "children"
+        s.doc = doc_unused;
+
+      ## Specific properties
+      case "cdatamode"
+        s.doc = "If @code{cdatamode} is @qcode{\"auto\"}, @code{cdata} is set \
+to the color from the @code{colororder} of the ancestor axes corresponding to \
+the @code{seriesindex}.";
+
+      case "cdatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "cdata"
+        s.doc = "Data defining the scatter object color.\n\
+\n\
+If @code{cdata} is a scalar index into the current colormap or a RGB triplet, \
+it defines the color of all scatter markers.\n\
+\n\
+If @code{cdata} is an N-by-1 vector of indices or an N-by-3 (RGB) matrix, \
+it defines the color of each one of the N scatter markers.";
+        s.valid = valid_scalmat;
+
+
+      case "displayname"
+        s.doc = "Text of the legend entry corresponding to this scatter object.";
+
+      case "linewidth"
+        s.doc = "Line width of the edge of the markers.";
+
+      case "marker"
+        s.doc = "@xref{XREFlinemarker, , @w{line marker property}}.";
+
+      case "markeredgealpha"
+        s.doc = "Transparency level of the faces of the markers where a \
+value of 0 means complete transparency and a value of 1 means solid faces \
+without transparency.  Note that the markers are not sorted from back to \
+front which might lead to unexpected results when rendering layered \
+transparent markers or in combination with other transparent objects.";
+        s.valid = "scalar";
+
+      case "markeredgecolor"
+        s.doc = "Color of the edge of the markers.  @qcode{\"none\"} means \
+that the edges are transparent and @qcode{\"flat\"} means that the value \
+from @code{cdata} is used.  @xref{XREFlinemarkeredgecolor, , \
+@w{line markeredgecolor property}}.";
+        s.valid = packopt ({markdef("@qcode{\"none\"}"), ...
+                            "@qcode{\"flat\"}", ...
+                            valid_color});
+
+      case "markerfacealpha"
+        s.doc = "Transparency level of the faces of the markers where a \
+value of 0 means complete transparency and a value of 1 means solid faces \
+without transparency.  Note that the markers are not sorted from back to \
+front which might lead to unexpected results when rendering layered \
+transparent markers or in combination with other transparent objects.";
+        s.valid = "scalar";
+
+      case "markerfacecolor"
+        s.doc = "Color of the face of the markers.  @qcode{\"none\"} means \
+that the faces are transparent, @qcode{\"flat\"} means that the value from \
+@code{cdata} is used, and @qcode{\"auto\"} uses the @code{color} property of \
+the ancestor axes. @xref{XREFlinemarkerfacecolor, , \
+@w{line markerfacecolor property}}.";
+        s.valid = packopt ({markdef("@qcode{\"none\"}"), ...
+                            "@qcode{\"flat\"}", ...
+                            "@qcode{\"auto\"}", ...
+                            valid_color});
+
+      case "seriesindex"
+        s.doc = "Each scatter object in the same axes is asigned an \
+incrementing integer.  This corresponds to the index into the \
+@code{colororder} of the ancestor axes that is used if @code{cdatamode} is \
+set to @qcode{\"auto\"}.";
+
+      case "sizedatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "sizedata"
+        s.doc = "Size of the area of the marker. A scalar value applies to \
+all markers.  If @code{cdata} is an N-by-1 vector, it defines the color of \
+each one of the N scatter markers.";
+        s.valid =  packopt ({"[]", "scalar", "vector"});
+
+      case "xdatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "xdata"
+        s.doc = "Vector with the x coordinates of the scatter object.";
+        s.valid = "vector";
+
+      case "ydatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "ydata"
+        s.doc = "Vector with the y coordinates of the scatter object.";
+        s.valid = "vector";
+
+      case "zdatasource"
+        s.doc = sprintf (doc_notimpl, "Data from workspace variables");
+
+      case "zdata"
+        s.doc = "For 3D data, vector with the y coordinates of the scatter \
+object.";
+        s.valid = packopt ({"[]", "vector"});
+
+    endswitch
+
   ## Light properties
   elseif (strcmp (objname, "light"))
     switch (field)
@@ -1962,6 +2080,10 @@
                  "location", "numcolumns", "orientation", "position", ...
                  "string", "textcolor", "title", "units"};
     endif
+  elseif (strcmp (objname, "scatter"))
+    ## Make sure to get a scatter object independent of graphics toolkit
+    hax = axes (hf);
+    h = __go_scatter__ (hax);
   else
     eval (["h = " objname " ();"]);
   endif
--- a/doc/interpreter/graphics_properties.mk	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/graphics_properties.mk	Sun May 16 09:44:35 2021 +0200
@@ -5,6 +5,7 @@
   interpreter/plot-lineproperties.texi \
   interpreter/plot-patchproperties.texi \
   interpreter/plot-rootproperties.texi \
+  interpreter/plot-scatterproperties.texi \
   interpreter/plot-surfaceproperties.texi \
   interpreter/plot-textproperties.texi
 
@@ -35,5 +36,8 @@
 interpreter/plot-surfaceproperties.texi: interpreter/genpropdoc.m
 	$(AM_V_GEN)$(call gen-propdoc-texi,surface)
 
+interpreter/plot-scatterproperties.texi: interpreter/genpropdoc.m
+	$(AM_V_GEN)$(call gen-propdoc-texi,scatter)
+
 interpreter/plot-textproperties.texi: interpreter/genpropdoc.m
 	$(AM_V_GEN)$(call gen-propdoc-texi,text)
--- a/doc/interpreter/gui.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/gui.txi	Sun May 16 09:44:35 2021 +0200
@@ -141,6 +141,10 @@
 
 @DOCSTRING(isguirunning)
 
+@DOCSTRING(getpixelposition)
+
+@DOCSTRING(listfonts)
+
 @DOCSTRING(movegui)
 
 @DOCSTRING(openvar)
--- a/doc/interpreter/image.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/image.txi	Sun May 16 09:44:35 2021 +0200
@@ -213,6 +213,8 @@
 
 @DOCSTRING(summer)
 
+@DOCSTRING(turbo)
+
 @DOCSTRING(viridis)
 
 @DOCSTRING(white)
--- a/doc/interpreter/io.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/io.txi	Sun May 16 09:44:35 2021 +0200
@@ -399,7 +399,7 @@
 performance of printing vector and matrix values.
 
 Implementation Note: For compatibility with @sc{matlab}, escape sequences in
-the template string (e.g., @qcode{"@xbackslashchar{}n"} => newline) are
+the template string (e.g., @qcode{"@backslashchar{}n"} => newline) are
 expanded even when the template string is defined with single quotes.
 
 @DOCSTRING(printf)
--- a/doc/interpreter/linalg.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/linalg.txi	Sun May 16 09:44:35 2021 +0200
@@ -183,6 +183,8 @@
 
 @DOCSTRING(ordschur)
 
+@DOCSTRING(ordqz)
+
 @DOCSTRING(ordeig)
 
 @DOCSTRING(subspace)
--- a/doc/interpreter/macros.texi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/macros.texi	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,9 @@
 
 @c The following macro works around the Info/plain text expansion of @code{XXX}
 @c which is `XXX'.  This looks particularly bad when the macro body is
-@c single or double-quoted text, such as a property value `"position"'
+@c single or double-quoted text, such as a property value `"position"'.
+@c The mnemonic to remember this macro is Quoted CODE.
+
 @ifinfo
 @macro qcode{arg}
 \arg\
@@ -46,20 +48,35 @@
 @end macro
 @end ifnotinfo
 
-@c The following macro is used for the on-line help system, but we don't
-@c want lots of `See also: foo, bar, and baz' strings cluttering the
-@c printed manual (that information should be in the supporting text for
-@c each group of functions and variables).
+@c The following macro works around the Info/plain text expansion of @code{XXX}
+@c which is `XXX'.  This can be confusing when the macro body itself
+@c ends with a transpose character, such as `x''.
+@c The mnemonic to remember this macro is Transpose CODE.
+
+@ifinfo
+@macro tcode{arg}
+\arg\
+@end macro
+@end ifinfo
+@ifnotinfo
+@macro tcode{arg}
+@code{\arg\}
+@end macro
+@end ifnotinfo
+
+@c The following macro is used for the on-line help system, but we don't want
+@c lots of `See also: foo, bar, and baz' strings cluttering the printed manual
+@c (that information should be in the supporting text for each group of
+@c functions and variables).
 @c
 @c Implementation Note:
 @c For TeX, @vskip produces a nice separation.
 @c For Texinfo, '@sp 1' should work, but in practice produces ugly results
-@c for HTML.  We use a simple blank line to produce the correct
-@c behavior.
+@c for HTML.  We use a simple blank line to produce the correct behavior.
 @c
-@c We use @xseealso now because Texinfo introduced its own @seealso
-@c command.  But instead of modifying all source files, we'll have the
-@c munge-texi script convert @seealso to @xseealso.
+@c The macro is named @xseealso now because Texinfo introduced its own @seealso
+@c command.  But, instead of modifying all source files, the build system uses
+@c the munge-texi script to convert @seealso to @xseealso.
 
 @macro xseealso {args}
 @iftex
@@ -78,26 +95,9 @@
 @end ifinfo
 @end macro
 
-@c The following macro works around a situation where the Info/plain text
-@c expansion of the @code{XXX} macro is `XXX'.  The use of the apostrophe
-@c can be confusing if the code segment itself ends with a transpose operator.
-@ifinfo
-@macro tcode{arg}
-\arg\
-@end macro
-@end ifinfo
-@ifnotinfo
-@macro tcode{arg}
-@code{\arg\}
-@end macro
-@end ifnotinfo
-
-@c FIXME: someday, when Texinfo 5.X is standard, we might replace this with
-@c @backslashchar, which is a new addition to Texinfo.
-
-@macro xbackslashchar
-\\
-@end macro
+@c ------------------------------------------------------------
+@c non-macro items
+@c ------------------------------------------------------------
 
 @c These may be useful for all, not just for octave.texi.
 @tex
@@ -121,5 +121,6 @@
   \fi
 @end tex
 
-@c Make the apostrophe in code examples cut-and-paste friendly.
+@c Make the apostrophe in code examples cut-and-paste friendly so programmers
+@c can take examples from the Octave manual and directly run them in Octave.
 @codequoteundirected on
--- a/doc/interpreter/matrix.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/matrix.txi	Sun May 16 09:44:35 2021 +0200
@@ -175,6 +175,8 @@
 
 @DOCSTRING(randg)
 
+@DOCSTRING(rng)
+
 The generators operate in the new or old style together, it is not
 possible to mix the two.  Initializing any generator with
 @qcode{"state"} or @qcode{"seed"} causes the others to switch to the
--- a/doc/interpreter/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -9,6 +9,7 @@
   %reldir%/plot-lineproperties.texi \
   %reldir%/plot-patchproperties.texi \
   %reldir%/plot-rootproperties.texi \
+  %reldir%/plot-scatterproperties.texi \
   %reldir%/plot-surfaceproperties.texi \
   %reldir%/plot-textproperties.texi \
   %reldir%/plot-uimenuproperties.texi \
@@ -55,6 +56,9 @@
 %reldir%/plot-rootproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,root)
 
+%reldir%/plot-scatterproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
+	$(AM_V_GEN)$(call gen-propdoc-texi,scatter)
+
 %reldir%/plot-surfaceproperties.texi: %reldir%/genpropdoc.m $(GRAPHICS_PROPS_SRC)
 	$(AM_V_GEN)$(call gen-propdoc-texi,surface)
 
--- a/doc/interpreter/octave.texi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/octave.texi	Sun May 16 09:44:35 2021 +0200
@@ -307,16 +307,23 @@
 
 * Escape Sequences in String Constants::
 * Character Arrays::
-* Creating Strings::
-* Comparing Strings::
-* Manipulating Strings::
-* String Conversions::
+* String Operations::
+* Converting Strings::
 * Character Class Functions::
 
-Creating Strings
+String Operations
 
+* Common String Operations::
 * Concatenating Strings::
-* Converting Numerical Data to Strings::
+* Splitting and Joining Strings::
+* Searching in Strings::
+* Searching and Replacing in Strings::
+
+Converting Strings
+
+* String encoding::
+* Numerical Data and Strings::
+* JSON data encoding/decoding::
 
 Data Containers
 
@@ -581,6 +588,7 @@
 * Text Properties::
 * Image Properties::
 * Patch Properties::
+* Scatter Properties::
 * Surface Properties::
 * Light Properties::
 * Uimenu Properties::
@@ -613,7 +621,6 @@
 * Error Bar Series::
 * Line Series::
 * Quiver Group::
-* Scatter Group::
 * Stair Group::
 * Stem Series::
 * Surface Group::
--- a/doc/interpreter/package.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/package.txi	Sun May 16 09:44:35 2021 +0200
@@ -135,16 +135,18 @@
 @node Administrating Packages
 @section Administrating Packages
 
-On UNIX-like systems it is possible to make both per-user and
-system-wide installations of a package.  If the user performing the
-installation is @code{root} the packages will be installed in a
-system-wide directory that defaults to
-@file{OCTAVE_HOME/share/octave/packages/}.  If the user is not
-@code{root} the default installation directory is
-@file{~/octave/}.  Packages will be installed in a subdirectory of the
-installation directory that will be named after the package.  It is
-possible to change the installation directory by using the
-@code{pkg prefix} command
+It is possible to make both per-user (local) and system-wide (global)
+installations of a package.  If the user performing the installation is
+@code{root} (or Administrator with elevated rights on Windows), the
+packages by default install in a system-wide directory that defaults to
+@file{@var{OCTAVE_HOME}/share/octave/packages/}.  If the user is not
+@code{root} (or without elevated rights), packages are installed
+locally.  The default installation directory for local packages is
+@file{@var{user_data_dir}/octave/@var{OCTAVE_MAJOR_VERSION}/packages}.
+Packages will be installed in a subdirectory of the installation
+directory that will be named after the package.  It is possible to
+change the installation directory by using the @code{pkg prefix}
+command:
 
 @example
 pkg prefix new_installation_directory
@@ -157,21 +159,24 @@
 current_installation_directory = pkg ("prefix")
 @end example
 
-To function properly the package manager needs to keep some
-information about the installed packages.  For per-user packages this
-information is by default stored in the file @file{~/.octave_packages}
-and for system-wide installations it is stored in
-@file{OCTAVE_HOME/share/octave/octave_packages}.  The path to the
-per-user file can be changed with the @code{pkg local_list} command
+The package manager stores some information about the installed
+packages in configuration files.  For per-user (local) packages, this
+information is stored in the file
+@file{@var{user_config_dir}/octave/@var{OCTAVE_MAJOR_VERSION}/octave_packages}
+by default.  For system-wide (global) installations, it is stored in
+@file{@var{OCTAVE_HOME}/share/octave/octave_packages}.  The path to the
+per-user file can be changed with the @code{pkg local_list} command:
 
 @example
 pkg local_list /path/to/new_file
 @end example
 
 @noindent
-For system-wide installations this can be changed in the same way
-using the @code{pkg global_list} command.  If these commands are
-called without a new path, the current path will be returned.
+For system-wide installations, this can be changed in the same way
+using the @code{pkg global_list} command.  If these commands are called
+without a new path, the current path will be returned.  To retain these
+settings between sessions, they can be set in one of the startup files,
+see @ref{Startup Files}.
 
 @node Creating Packages
 @section Creating Packages
--- a/doc/interpreter/plot.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/plot.txi	Sun May 16 09:44:35 2021 +0200
@@ -259,6 +259,8 @@
 
 @DOCSTRING(quiver3)
 
+@DOCSTRING(streamribbon)
+
 @DOCSTRING(streamtube)
 
 @DOCSTRING(ostreamtube)
@@ -279,6 +281,8 @@
 
 @DOCSTRING(fill)
 
+@DOCSTRING(fill3)
+
 @DOCSTRING(comet)
 
 @DOCSTRING(comet3)
@@ -340,6 +344,16 @@
 @findex zticklabels
 @DOCSTRING(xticklabels)
 
+The @code{xtickangle}, @code{ytickangle}, and @code{ztickangle} functions
+may be used to get or set the rotation angle of labels for the respective axis.
+Each has the same form.
+
+@anchor{XREFytickangle}
+@anchor{XREFztickangle}
+@findex ytickangle
+@findex ztickangle
+@DOCSTRING(xtickangle)
+
 @node Two-dimensional Function Plotting
 @subsubsection Two-dimensional Function Plotting
 @cindex plotting, two-dimensional functions
@@ -735,20 +749,31 @@
 @subsection Use of the @code{interpreter} Property
 @anchor{XREFinterpreterusage}
 
-All text objects---such as titles, labels, legends, and text---include
-the property @qcode{"interpreter"} that determines the manner in
-which special control sequences in the text are rendered.
+@code{text} (such as titles, labels, legend item) and @code{axes} objects
+feature a @ref{XREFtextinterpreter,,interpreter} and
+@ref{XREFaxesticklabelinterpreter,,ticklabelinterpreter} property respectively.
+It determines the manner in which special control sequences in the text are
+rendered.
 
 The interpreter property can take three values: @qcode{"none"}, @qcode{"tex"},
-@qcode{"latex"}.  If the interpreter is set to @qcode{"none"} then no special
+@qcode{"latex"}.
+
+@menu
+* @code{none} interpreter::
+* @code{tex} interpreter::
+* @code{latex} interpreter::
+@end menu
+
+@node @code{none} interpreter
+@subsubsection @code{none} interpreter
+@anchor{XREFnoneinterpreter}
+If the interpreter is set to @qcode{"none"} then no special
 rendering occurs---the displayed text is a verbatim copy of the specified text.
-Currently, the @qcode{"latex"} interpreter is not implemented for on-screen
-display and is equivalent to @qcode{"none"}.  Note that Octave does not parse
-or validate the text strings when in @qcode{"latex"} mode---it is the
-responsibility of the programmer to generate valid strings which may include
-wrapping sections that should appear in Math mode with @qcode{'$'} characters.
-
-The @qcode{"tex"} option implements a subset of @TeX{} functionality when
+
+@node @code{tex} interpreter
+@subsubsection @code{tex} interpreter
+@anchor{XREFtexinterpreter}
+The @qcode{"tex"} interpreter implements a subset of @TeX{} functionality when
 rendering text.  This allows the insertion of special glyphs such as Greek
 characters or mathematical symbols.  Special characters are inserted by using
 a backslash (\) character followed by a code, as shown in @ref{tab:extended}.
@@ -1039,7 +1064,7 @@
 @end tex
 @end float
 
-@subsubsection Degree Symbol
+@strong{Caution: Degree Symbol}
 @cindex Degree Symbol
 
 Conformance to both @TeX{} and @sc{matlab} with respect to the @code{\circ}
@@ -1048,6 +1073,56 @@
 has chosen to follow the @TeX{} specification, but has added the additional
 symbol @code{\deg} which maps to the degree symbol (U+00B0).
 
+@node @code{latex} interpreter
+@subsubsection @code{latex} interpreter
+@anchor{XREFlatexinterpreter}
+The @qcode{"latex"} interpreter only works if an external LaTeX tool chain is
+present.  Three binaries are needed: @code{latex}, @code{dvipng}, and
+@code{dvisvgm}.  If those binaries are installed but not on the path, one can
+still provide their respective path using the following environment variables:
+OCTAVE_LATEX_BINARY, OCTAVE_DVIPNG_BINARY, and OCTAVE_DVISVG_BINARY.
+
+Note that Octave does not parse or validate the text strings when in
+@qcode{"latex"} mode---it is the responsibility of the programmer to generate
+valid strings which may include wrapping sections that should appear in Math
+mode with @qcode{'$'} characters.
+See e.g. @url{https://www.latex-project.org/help/documentation/} for
+documentation about LaTeX typesetting.
+
+For debugging purpose, a convenience environment variable,
+OCTAVE_LATEX_DEBUG_FLAG, can be set to trigger more verbose output when Octave
+fails to have a given text compiled by an external latex engine. E.g.
+@qcode{"x^2"} is not a valid LaTeX string and the following example should fail
+
+@example
+@group
+setenv ("OCTAVE_LATEX_DEBUG_FLAG", "1")
+x = 1:10;
+plot (x, x.^2)
+title ("x^2", "interpreter", "latex")
+@end group
+@end example
+
+Searching the terminal output you should find some helpful info about the origin
+of the failure:
+
+@example
+@group
+...
+No file default.aux.
+! Missing $ inserted.
+<inserted text>
+                $
+l.6 x^
+      2
+! Missing $ inserted.
+...
+@end group
+@end example
+
+If no usable latex tool chain is found at the first text rendering, using
+the @qcode{"latex"} interpreter is equivalent to @qcode{"none"}.
+
 @node Printing and Saving Plots
 @subsection Printing and Saving Plots
 @cindex plotting, saving and printing plots
@@ -1077,9 +1152,19 @@
 such text.  In general, the @qcode{"tex"} interpreter (default) is the best
 all-around performer for both on-screen display and printing.  However, for the
 reproduction of complicated text formulas the @qcode{"latex"} interpreter is
-preferred.  The @qcode{"latex"} interpreter will not display symbols on-screen,
-but the printed output will be correct.  When printing, use one of the
-@code{standalone} options which provide full access to @LaTeX{} commands.
+preferred.  When printing with the @code{-painters} renderer, the default for
+all vector formats, two options may be considered:
+@itemize @bullet
+@item
+Use the @option{-svgconvert} option to allow for rendering LaTeX formulas. Note
+that the glyph are rendered as path and the original textual info are lost.
+@item
+Use one of the @option{-d*latex*} devices to produce a .tex file (plus support
+.eps or .pdf files) to be further processed by an external LaTeX engine.
+Note that the @code{print} function will first set the interpreter of all
+strings to @qcode{"latex"}, which means all strings must be valid latex strings.
+provided that all strings can be processed by LaTeX, not only those.
+@end itemize
 
 A complete example showing the capabilities of text printing using the
 @option{-dpdflatexstandalone} option is:
@@ -1182,23 +1267,30 @@
 The graphics functions use pointers, which are of class graphics_handle, in
 order to address the data structures which control visual display.  A
 graphics handle may point to any one of a number of different base object
-types and these objects are the graphics data structures themselves.  The
+types.  These objects are the graphics data structures themselves.  The
 primitive graphic object types are: @code{figure}, @code{axes}, @code{line},
-@code{text}, @code{patch}, @code{surface}, @code{text}, @code{image}, and
-@code{light}.
-
-Each of these objects has a function by the same name, and, each of these
+@code{text}, @code{patch}, @code{scatter}, @code{surface}, @code{text},
+@code{image}, and @code{light}.
+
+Each of these objects has a function by the same name, and each of these
 functions returns a graphics handle pointing to an object of the corresponding
-type.  In addition there are several functions which operate on properties of
-the graphics objects and which also return handles: the functions @code{plot}
-and @code{plot3} return a handle pointing to an object of type line, the
-function @code{subplot} returns a handle pointing to an object of type axes,
-the function @code{fill} returns a handle pointing to an object of type patch,
-the functions @code{area}, @code{bar}, @code{barh}, @code{contour},
-@code{contourf}, @code{contour3}, @code{surf}, @code{mesh}, @code{surfc},
-@code{meshc}, @code{errorbar}, @code{quiver}, @code{quiver3}, @code{scatter},
-@code{scatter3}, @code{stair}, @code{stem}, @code{stem3} each return a handle
-to a complex data structure as documented in
+type.
+
+In addition, there are several functions which operate on properties of the
+graphics objects and which also return handles.  This includes but is not
+limited to the following functions: The functions @code{plot} and @code{plot3}
+return a handle pointing to an object of type @code{line}.  The function
+@code{subplot} returns a handle pointing to an object of type @code{axes}.
+The functions @code{fill}, @code{fill3}, @code{trimesh}, and @code{trisurf}
+return a handle pointing to an object of type patch.  The function
+@code{scatter3} returns a handle to an object of type scatter.  The functions
+@code{slice}, @code{surf}, @code{surfl}, @code{mesh}, @code{meshz},
+@code{pcolor}, and @code{waterfall} each return a handle of type surface.  The
+function @code{camlight} returns a handle to an object of type light.  The
+functions @code{area}, @code{bar}, @code{barh}, @code{contour},
+@code{contourf}, @code{contour3}, @code{surfc}, @code{meshc}, @code{errorbar},
+@code{quiver}, @code{quiver3}, @code{stair}, @code{stem}, @code{stem3} each
+return a handle to a complex data structure as documented in
 @ref{XREFdatasources,,Data Sources}.
 
 The graphics objects are arranged in a hierarchy:
@@ -1211,8 +1303,12 @@
 
 3. Below the @code{figure} objects are @code{axes} or @code{hggroup} objects.
 
-4. Below the @code{axes} objects are @code{line}, @code{text}, @code{patch},
-@code{surface}, @code{image}, and @code{light} objects.
+4. Below the @code{axes} or @code{hggroup} objects are @code{line},
+@code{text}, @code{patch}, @code{scatter}, @code{surface}, @code{image}, and
+@code{light} objects.
+
+It is possible to walk this hierarchical tree by querying the @qcode{"parent"}
+and @qcode{"children"} properties of the graphics objects.
 
 Graphics handles may be distinguished from function handles
 (@pxref{Function Handles}) by means of the function @code{ishghandle}.
@@ -1348,7 +1444,7 @@
 Alternatively, the easier way is to call a high-level graphics routine which
 will both create the plot and then populate it with low-level graphics objects.
 Instead of calling @code{line}, use @code{plot}.  Or use @code{surf} instead of
-@code{surface}.  Or use @code{fill} instead of @code{patch}.
+@code{surface}.  Or use @code{fill} or @code{fill3} instead of @code{patch}.
 
 @DOCSTRING(axes)
 
@@ -1502,6 +1598,7 @@
 * Text Properties::
 * Image Properties::
 * Patch Properties::
+* Scatter Properties::
 * Surface Properties::
 * Light Properties::
 * Uimenu Properties::
@@ -1583,6 +1680,13 @@
 @include plot-patchproperties.texi
 
 
+@node Scatter Properties
+@subsubsection Scatter Properties
+@prindex @sortas{@ Scatter Properties} Scatter Properties
+
+@include plot-scatterproperties.texi
+
+
 @node Surface Properties
 @subsubsection Surface Properties
 @prindex @sortas{@ Surface Properties} Surface Properties
@@ -1800,10 +1904,44 @@
 @cindex graphics colors
 @cindex colors, graphics
 
-Colors may be specified as RGB triplets with values ranging from zero to
-one, or by name.  Recognized color names include @qcode{"blue"},
-@qcode{"black"}, @qcode{"cyan"}, @qcode{"green"}, @qcode{"magenta"},
-@qcode{"red"}, @qcode{"white"}, and @qcode{"yellow"}.
+Colors may be specified in three ways: 1) RGB triplets, 2) by name, or 3) by HTML notation.
+
+@table @asis
+
+@item RGB triplet
+
+An RGB triplet is a 1x3 vector where each value is between 0 and 1 inclusive.
+The first value represents the percentage of Red, the second value the
+percentage of Green, and the third value the percentage of Blue.  For example,
+@code{[1, 0, 1]} represents full Red and Blue channels resulting in the color
+magenta.
+
+@item short or long name
+
+Eight colors can be specified directly by name or by a single character short
+name.
+
+@multitable @columnfractions 0.21 0.79
+@headitem Name @tab Color
+@item @samp{k}, @qcode{"black"}   @tab blacK
+@item @samp{r}, @qcode{"red"}     @tab Red
+@item @samp{g}, @qcode{"green"}   @tab Green
+@item @samp{b}, @qcode{"blue"}    @tab Blue
+@item @samp{y}, @qcode{"yellow"}  @tab Yellow
+@item @samp{m}, @qcode{"magenta"} @tab Magenta
+@item @samp{c}, @qcode{"cyan"}    @tab Cyan
+@item @samp{w}, @qcode{"white"}   @tab White
+@end multitable
+
+@item HTML notation
+
+HTML notation is a string that begins with the character @samp{#} and is
+followed by either 3 or 6 hexadecimal digits.  As with RGB triplets, each
+hexadecimal number represents the fraction of the Red, Green, and Blue channels
+present in the specified color.  For example, @qcode{"#FF00FF"} represents
+the color magenta.
+
+@end table
 
 @node Line Styles
 @subsection Line Styles
@@ -2149,7 +2287,6 @@
 * Error Bar Series::
 * Line Series::
 * Quiver Group::
-* Scatter Group::
 * Stair Group::
 * Stem Series::
 * Surface Group::
@@ -2475,46 +2612,6 @@
 Data source variables.
 @end table
 
-@node Scatter Group
-@subsubsection Scatter Group
-@cindex group objects
-@cindex scatter group
-
-Scatter series objects are created by the @code{scatter} or @code{scatter3}
-functions.  A single hggroup element contains as many children as there are
-points in the scatter plot, with each child representing one of the points.
-The properties of the stem series are
-
-@table @code
-@item linewidth
-The line width of the line objects of the points.  @xref{Line Styles}.
-
-@item  marker
-@itemx markeredgecolor
-@itemx markerfacecolor
-The line and fill color of the markers of the points.  @xref{Colors}.
-
-@item  xdata
-@itemx ydata
-@itemx zdata
-The original x, y and z data of the stems.
-
-@item cdata
-The color data for the points of the plot.  Each point can have a separate
-color, or a unique color can be specified.
-
-@item sizedata
-The size data for the points of the plot.  Each point can its own size or a
-unique size can be specified.
-
-@item  xdatasource
-@itemx ydatasource
-@itemx zdatasource
-@itemx cdatasource
-@itemx sizedatasource
-Data source variables.
-@end table
-
 @node Stair Group
 @subsubsection Stair Group
 @cindex group objects
--- a/doc/interpreter/set.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/set.txi	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,8 @@
 
 @DOCSTRING(unique)
 
+@DOCSTRING(uniquetol)
+
 @menu
 * Set Operations::
 @end menu
--- a/doc/interpreter/strings.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/strings.txi	Sun May 16 09:44:35 2021 +0200
@@ -56,13 +56,17 @@
 While strings can in principle store arbitrary content, most functions expect
 them to be UTF-8 encoded Unicode strings.
 
+Furthermore, it is possible to create a string without actually writing a text.
+The function @code{blanks} creates a string of a given length consisting only
+of blank characters (ASCII code 32).
+
+@DOCSTRING(blanks)
+
 @menu
 * Escape Sequences in String Constants::
 * Character Arrays::
-* Creating Strings::
-* Comparing Strings::
-* Manipulating Strings::
-* String Conversions::
+* String Operations::
+* Converting Strings::
 * Character Class Functions::
 @end menu
 
@@ -207,26 +211,65 @@
 
 @DOCSTRING(string_fill_char)
 
+Another useful function to control the text justification in this case is
+the @code{strjust} function.
+
+@DOCSTRING(strjust)
+
 This shows a problem with character matrices.  It simply isn't possible to
 represent strings of different lengths.  The solution is to use a cell array of
 strings, which is described in @ref{Cell Arrays of Strings}.
 
-@node Creating Strings
-@section Creating Strings
+@node String Operations
+@section String Operations
+
+Octave supports a wide range of functions for manipulating strings.
+Since a string is just a matrix, simple manipulations can be accomplished
+using standard operators.  The following example shows how to replace
+all blank characters with underscores.
 
-The easiest way to create a string is, as illustrated in the introduction,
-to enclose a text in double-quotes or single-quotes.  It is however
-possible to create a string without actually writing a text.  The
-function @code{blanks} creates a string of a given length consisting
-only of blank characters (ASCII code 32).
+@example
+@group
+quote = ...
+  "First things first, but not necessarily in that order";
+quote( quote == " " ) = "_"
+@result{} quote =
+    First_things_first,_but_not_necessarily_in_that_order
+@end group
+@end example
 
-@DOCSTRING(blanks)
+For more complex manipulations, such as searching, replacing, and
+general regular expressions, the following functions come with Octave.
 
 @menu
+* Common String Operations::
 * Concatenating Strings::
-* Converting Numerical Data to Strings::
+* Splitting and Joining Strings::
+* Searching in Strings::
+* Searching and Replacing in Strings::
 @end menu
 
+@node Common String Operations
+@subsection Common String Operations
+
+The following functions are useful to perform common String operations.
+
+@DOCSTRING(tolower)
+
+@DOCSTRING(toupper)
+
+@DOCSTRING(deblank)
+
+@DOCSTRING(strtrim)
+
+@DOCSTRING(strtrunc)
+
+@DOCSTRING(untabify)
+
+@DOCSTRING(do_string_escapes)
+
+@DOCSTRING(undo_string_escapes)
+
 @node Concatenating Strings
 @subsection Concatenating Strings
 
@@ -370,25 +413,21 @@
 
 @DOCSTRING(cstrcat)
 
-@node Converting Numerical Data to Strings
-@subsection Converting Numerical Data to Strings
-Apart from the string concatenation functions (@pxref{Concatenating Strings})
-which cast numerical data to the corresponding UTF-8 encoded characters, there
-are several functions that format numerical data as strings.  @code{mat2str}
-and @code{num2str} convert real or complex matrices, while @code{int2str}
-converts integer matrices.  @code{int2str} takes the real part of complex
-values and round fractional values to integer.  A more flexible way to format
-numerical data as strings is the @code{sprintf} function
-(@pxref{Formatted Output}, @ref{XREFsprintf,,sprintf}).
+@node Splitting and Joining Strings
+@subsection Splitting and Joining Strings
+
+@DOCSTRING(substr)
+
+@DOCSTRING(strtok)
 
-@DOCSTRING(mat2str)
+@DOCSTRING(strsplit)
 
-@DOCSTRING(num2str)
+@DOCSTRING(ostrsplit)
 
-@DOCSTRING(int2str)
+@DOCSTRING(strjoin)
 
-@node Comparing Strings
-@section Comparing Strings
+@node Searching in Strings
+@subsection Searching in Strings
 
 Since a string is a character array, comparisons between strings work
 element by element as the following example shows:
@@ -416,32 +455,12 @@
 
 @DOCSTRING(strncmpi)
 
-@node Manipulating Strings
-@section Manipulating Strings
-
-Octave supports a wide range of functions for manipulating strings.
-Since a string is just a matrix, simple manipulations can be accomplished
-using standard operators.  The following example shows how to replace
-all blank characters with underscores.
+Despite those comparison functions, there are more specialized function to
+find the index position of a search pattern within a string.
 
-@example
-@group
-quote = ...
-  "First things first, but not necessarily in that order";
-quote( quote == " " ) = "_"
-@result{} quote =
-    First_things_first,_but_not_necessarily_in_that_order
-@end group
-@end example
+@DOCSTRING(startsWith)
 
-For more complex manipulations, such as searching, replacing, and
-general regular expressions, the following functions come with Octave.
-
-@DOCSTRING(deblank)
-
-@DOCSTRING(strtrim)
-
-@DOCSTRING(strtrunc)
+@DOCSTRING(endsWith)
 
 @DOCSTRING(findstr)
 
@@ -451,26 +470,19 @@
 
 @DOCSTRING(rindex)
 
-@DOCSTRING(strfind)
+@DOCSTRING(unicode_idx)
 
-@DOCSTRING(strjoin)
+@DOCSTRING(strfind)
 
 @DOCSTRING(strmatch)
 
-@DOCSTRING(strtok)
-
-@DOCSTRING(strsplit)
-
-@DOCSTRING(ostrsplit)
-
-@DOCSTRING(strread)
+@node Searching and Replacing in Strings
+@subsection Searching and Replacing in Strings
 
 @DOCSTRING(strrep)
 
 @DOCSTRING(erase)
 
-@DOCSTRING(substr)
-
 @DOCSTRING(regexp)
 
 @DOCSTRING(regexpi)
@@ -479,23 +491,45 @@
 
 @DOCSTRING(regexptranslate)
 
-@DOCSTRING(untabify)
+@node Converting Strings
+@section Converting Strings
+
+Octave offers several kinds of conversion functions for Strings.
 
-@DOCSTRING(unicode_idx)
+@menu
+* String encoding::
+* Numerical Data and Strings::
+* JSON data encoding/decoding::
+@end menu
 
-@node String Conversions
-@section String Conversions
+@node String encoding
+@subsection String encoding
+
+@DOCSTRING(unicode2native)
+
+@DOCSTRING(native2unicode)
 
-Octave supports various kinds of conversions between strings and
-numbers.  As an example, it is possible to convert a string containing
-a hexadecimal number to a floating point number.
+@node Numerical Data and Strings
+@subsection Numerical Data and Strings
 
-@example
-@group
-hex2dec ("FF")
-      @result{} 255
-@end group
-@end example
+Apart from the string concatenation functions (@pxref{Concatenating Strings})
+which cast numerical data to the corresponding UTF-8 encoded characters, there
+are several functions that format numerical data as strings.  @code{mat2str}
+and @code{num2str} convert real or complex matrices, while @code{int2str}
+converts integer matrices.  @code{int2str} takes the real part of complex
+values and round fractional values to integer.  A more flexible way to format
+numerical data as strings is the @code{sprintf} function
+(@pxref{Formatted Output}, @ref{XREFsprintf,,sprintf}).
+
+@DOCSTRING(mat2str)
+
+@DOCSTRING(num2str)
+
+@DOCSTRING(int2str)
+
+@DOCSTRING(str2double)
+
+@DOCSTRING(str2num)
 
 @DOCSTRING(bin2dec)
 
@@ -513,23 +547,18 @@
 
 @DOCSTRING(hex2num)
 
-@DOCSTRING(str2double)
-
-@DOCSTRING(strjust)
+@DOCSTRING(strread)
 
-@DOCSTRING(str2num)
-
-@DOCSTRING(tolower)
+@node JSON data encoding/decoding
+@subsection JSON data encoding/decoding
 
-@DOCSTRING(toupper)
-
-@DOCSTRING(unicode2native)
+JavaScript Object Notation, in short JSON, is a very common human readable
+and structured data format.  GNU Octave supports encoding and decoding this
+format with the following two functions.
 
-@DOCSTRING(native2unicode)
+@DOCSTRING(jsonencode)
 
-@DOCSTRING(do_string_escapes)
-
-@DOCSTRING(undo_string_escapes)
+@DOCSTRING(jsondecode)
 
 @node Character Class Functions
 @section Character Class Functions
--- a/doc/interpreter/system.txi	Sun May 16 09:43:43 2021 +0200
+++ b/doc/interpreter/system.txi	Sun May 16 09:44:35 2021 +0200
@@ -324,6 +324,10 @@
 
 @DOCSTRING(base64_decode)
 
+@DOCSTRING(matlab.net.base64encode)
+
+@DOCSTRING(matlab.net.base64decode)
+
 @node Controlling Subprocesses
 @section Controlling Subprocesses
 
@@ -542,6 +546,10 @@
 
 @DOCSTRING(matlabroot)
 
+@DOCSTRING(user_config_dir)
+
+@DOCSTRING(user_data_dir)
+
 @DOCSTRING(OCTAVE_VERSION)
 
 @DOCSTRING(version)
@@ -554,6 +562,8 @@
 
 @DOCSTRING(license)
 
+@DOCSTRING(memory)
+
 @DOCSTRING(getrusage)
 
 @DOCSTRING(winqueryreg)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/NEWS.6	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,404 @@
+Summary of bugs fixed for version 6.2.0 (2021-02-19):
+----------------------------------------------------
+
+See: https://www.octave.org/news/release/2021/02/20/octave-6.2.0-released.html
+
+For (bug #XXXXX) see https://savannah.gnu.org/bugs/?XXXXX
+
+### Improvements
+
+- `bicgstab.m`, `cgs.m`: Fix typo in `"iter_min"` variable name (bug #60071).
+- Compute with `NA` correctly on MIPS architecture (bug #59830).
+- Fix lookup of `"caller"` stack frame (bug #59847).
+- Also wait on `main_thread` after interpreter shuts down (bug #56952).
+- Fix symbol lookup issue with anonymous functions (bug #55989).
+- Line buffer input in `terminal_reader` class.
+- `qr`: Error for dense `A` and `B` with three output arguments (bug #58944).
+- `strmatch.m`: Always return column vector for Matlab compatibility (bug #59917)
+- Avoid crash when `evalin` global variables into existence in script (bug #59937)
+- Avoid crash on null statement list (bug #59938).
+- Fix ignored output from user function in left side of assignment (bug #59704).
+- Temporarily set lvalue list to null (bug #59704).
+- `fminbnd.m`: do not ignore `"OutputFcn"` (bug #59901).
+- `load-path.cc`: Reduce number of times `"canonicalize_file_name"` is called (bug #59711).
+- `interpn.m`: Use `size_equal` for 10X speedup in cset 067b663529bb (bug #59856).
+- `interpn.m`: Fix check for scattered point coordinates (bug #59856).
+- Avoid `YYUSE` in Octave parser files (see bug #59806).
+- `struct2hdl.m`: Set `"units"` property early.
+- `load-path.cc`: Avoid copying string for loop variable.
+- `pcg.m`: Return correct `FLAG` and correct `RELRES` output (bug #59776).
+- Use static keyword on regexp pattern in `file_stat` (bug #59706).
+- `stat`: Improve regular expression for UNC roots on Windows (bug #59706).
+- `stat`: Use `"make_absolute"` instead of `"canonicalize_file_name"` on Windows (bug #59706).
+- Improve `class_simple` function handle function lookup (bug #59661).
+- `hdl2struct.m`: store hidden text properties (bug #57241).
+- Mark script created with commands from history as modified.
+- `replem.m`: Fix operations with sparse matrices (bug #59705).
+- `ode_event_handler.m`: Fix mishandling of event edge types and multiple events (bug #59709).
+- Increase size of dynamic variable `new_argv` by 1 to avoid indexing out of array.
+- Fix incorrect results for set functions with `"legacy"` option (bug #59708).
+- `dir.m`: Return folder (not including file) in field `"folder"` (bug #59689).
+- Avoid memory leak with function handles (bug #59659).
+- Avoid dispatch error if method argument is a function handle (bug #59617).
+- Avoid crash due to accessing first element of empty list (bug #59656).
+- Don't propagate prevailing `isargout` info through `mexCallMATLAB` (bug #59597).
+- Show original error when failing to create a graphics object (bug #59620).
+- Fix regression with superclass lookup in classdef constructors (bug #59602).
+- Allow Octave class `execution_exception` to catch `std::exception` objects (bug #59592).
+
+### GUI
+
+- Fix restoring editor session after having closed all tabs (bug #60051).
+- Maybe convert TAB to SPC in GUI terminal pasted text (bug #59916).
+- Make bracketed paste mode work in GUI terminal.
+- Fix regression in variable editor when printing without selection.
+- Avoid gui when octave is launched in non-interactive mode (bug #59628).
+- `file-editor-tab.cc` (dtor): do not delete `m_edit_area` (bug #59628).
+- Fix error when restoring previous main window layout (bug #59426).
+- Improve default sizes of gui dock widgets.
+- Clean up constructing main window layout of the gui.
+- Fix focus command window after command execution (bug #59609).
+- Check object size before plotting from variable editor (bug #56685).
+- `documentation.cc`: Include missing header (bug #59553).
+
+### Build system / Tests
+
+- Add default value to `OCTAVE_MIPS_NAN` configure macro for cross-compiling (bug #59830).
+- tests: Function name should match file name (bug #59704).
+- Avoid build errors with Qt4 (bug #59813).
+- eigs.m: Make tests that depend on CHOLMOD conditional.
+- tests: Make tests that depend on CXSparse conditional.
+- build: Use `SPARSE_XCPPFLAGS` in `CPP_FLAGS` for libcorefcn (bug #59806).
+- Add test case for bug #59661.
+- `hgsave.m`: Allow test to run with qt or gnuplot graphics toolkits (bug #57241).
+
+### Documentation
+
+- `embedded.cc`: Fix syntax error interpreter shutdown.
+- Update Octave Project Developers copyright for the new year.
+- Use the same comment style for copyright headers in .m files and shell scripts.
+
+
+Summary of important user-visible changes for version 6.1.0 (2020-11-26):
+------------------------------------------------------------------------
+
+### General improvements
+
+- The `intersect`, `setdiff`, `setxor`, `union`, and `unique` functions
+  accept a new sorting option `"stable"` which will return output values
+  in the same order as the input, rather than in ascending order.
+
+- Complex RESTful web services can now be accessed by the `webread` and
+  `webwrite` functions alongside with the `weboptions` structure.  One
+  major feature is the support for cookies to enable RESTful
+  communication with the web service.
+
+  Additionally, the system web browser can be opened by the `web`
+  function.
+
+- The `linspace` function now produces symmetrical sequences when the
+  endpoints are symmetric.  This is more intuitive and also compatible
+  with recent changes made in Matlab R2019b.
+
+- The underlying algorithm of the `rand` function has been changed.
+  For single precision outputs, the algorithm has been fixed so that it
+  produces values strictly in the range (0, 1).  Previously, it could
+  occasionally generate the right endpoint value of 1 (See bug #41742).
+  In addition, the new implementation uses a uniform interval between
+  floating point values in the range (0, 1) rather than targeting a
+  uniform density (# of random integers / length along real number
+  line).
+
+- Numerical integration has been improved.  The `quadv` function has
+  been re-written so that it can compute integrands of periodic
+  functions.  At the same time, performance is better with ~3.5X fewer
+  function evaluations required.  A bug in `quadgk` that caused complex
+  path integrals specified with `"Waypoints"` to occasionally be
+  calculated in the opposite direction was fixed.
+
+- The `edit` function option `"editinplace"` now defaults to `true` and
+  the option `"home"` now defaults to the empty matrix `[]`.  Files will
+  no longer be copied to the user's HOME directory for editing.  The old
+  behavior can be restored by setting `"editinplace"` to `false` and
+  `"home"` to `"~/octave"`.
+
+- The `format` command supports two new options: `uppercase` and
+  `lowercase` (default).  With the default, print a lowercase 'e' for
+  the exponent character in scientific notation and lowercase 'a-f' for
+  the hex digits representing 10-15.  With `uppercase`, print 'E' and
+  'A-F' instead.  The previous uppercase formats, `E` and `G`, no longer
+  control the case of the output.
+
+  Additionally, the `format` command can be called with multiple options
+  for controlling the format, spacing, and case in arbitrary order.
+  For example:
+
+        format long e uppercase loose
+
+  Note, in the case of multiple competing format options the rightmost
+  one is used, and, in case of an error, the previous format remains
+  unchanged.
+
+- L-value references (e.g., increment (++), decrement (--), and all
+  in-place assignment operators (+=, -=, *=, /=, etc.)) are no longer
+  allowed in anonymous functions.
+
+- New warnings have been added about questionable uses of the colon ':'
+  range operator.  Each has a new warning ID so that it can be disabled
+  if desired.
+
+  >  `Octave:colon-complex-argument`   : when any arg is complex
+  >  `Octave:colon-nonscalar-argument` : when any arg is non-scalar
+
+- The `regexp` and related functions now correctly handle and *require*
+  strings in UTF-8 encoding.  As with any other function that requires
+  strings to be encoded in Octave's native encoding, you can use
+  `native2unicode` to convert from your preferred locale.  For example,
+  the copyright symbol in UTF-8 is `native2unicode (169, "latin1")`.
+
+- The startup file `octaverc` can now be located in the platform
+  dependent location for user local configuration files (e.g.,
+  ${XDG_CONFIG_HOME}/octave/octaverc on Unix-like operating systems or
+  %APPDATA%\octave\octaverc on Windows).
+
+- `pkg describe` now lists dependencies and inverse dependencies
+  (i.e., other installed packages that depend on the package in
+  question).
+
+- `pkg test` now tests all functions in a package.
+
+- When unloading a package, `pkg` now checks if any remaining loaded
+  packages depend on the one to be removed.  If this is the case `pkg`
+  aborts with an explanatory error message.  This behavior can be
+  overridden with the `-nodeps` option.
+
+- The command
+
+    dbstop in CLASS at METHOD
+
+  now works to set breakpoints in classdef constructors and methods.
+
+#### Graphics backend
+
+- The use of Qt4 for graphics and the GUI is deprecated in Octave
+  version 6 and no further bug fixes will be made.  Qt4 support will be
+  removed completely in Octave version 7.
+
+- The `legend` function has been entirely rewritten.  This fixes a
+  number of historical bugs, and also implements new properties such as
+  `"AutoUpdate"` and `"NumColumns"`.  The gnuplot toolkit---which is no
+  longer actively maintained---still uses the old legend function.
+
+- The `axis` function was updated which resolved 10 bugs affecting
+  axes to which `"equal"` had been applied.
+
+- Graphic primitives now accept a color property value of `"none"`
+  which is useful when a particular primitive needs to be hidden
+  (for example, the Y-axis of an axes object with `"ycolor" = "none"`)
+  without hiding the entire primitive `"visibility" = "off"`.
+
+- A new property `"FontSmoothing"` has been added to text and axes
+  objects that controls whether anti-aliasing is used during the
+  rendering of characters.  The default is `"on"` which produces smooth,
+  more visually appealing text.
+
+- The figure property `"windowscrollwheelfcn"`is now implemented.
+  This makes it possible to provide a callback function to be executed
+  when users manipulate the mouse wheel on a given figure.
+
+- The figure properties `"pointer"`, `"pointershapecdata"`, and
+  `"pointershapehotspot"` are now implemented.  This makes it possible
+  to change the shape of the cursor (pointer in Matlab-speak) displayed
+  in a plot window.
+
+- The figure property `"paperpositionmode"` now has the default `"auto"`
+  rather than `"manual"`.  This change is more intuitive and is
+  Matlab compatible.
+
+- The appearance of patterned lines `"LineStyle" = ":"|"--"|"-."` has
+  been improved for small widths (`"LineWidth"` less than 1.5 pixels)
+  which is a common scenario.
+
+- Printing to EPS files now uses a tight bounding box (`"-tight"`
+  argument to print) by default.  This makes more sense for EPS
+  files which are normally embedded within other documents, and is
+  Matlab compatible.  If necessary use the `"-loose"` option to
+  reproduce figures as they appeared in previous versions of Octave.
+
+- The following print devices are no longer officially supported: cdr,
+  corel, aifm, ill, cgm, hpgl, mf and dxf.  A warning will be thrown
+  when using those devices, and the code for supporting those formats
+  will eventually be removed from a future version of Octave.
+
+- The placement of text subscripts and superscripts has been
+  re-engineered and now produces visually attractive results similar to
+  Latex.
+
+### Matlab compatibility
+
+- The function `unique` now returns column index vectors for the second
+  and third outputs.  When duplicate values are present, the default
+  index to return is now the `"first"` occurrence.  The previous Octave
+  behavior, or Matlab behavior from releases prior to R2012b, can be
+  obtained by using the `"legacy"` flag.
+
+- The function `setdiff` with the `"rows"` argument now returns Matlab
+  compatible results.  The previous Octave behavior, or Matlab behavior
+  from releases prior to R2012b, can be obtained by using the `"legacy"`
+  flag.
+
+- The functions `intersect`, `setxor`, and `union` now accept a
+  `"legacy"` flag which changes the index values (second and third
+  outputs) as well as the orientation of all outputs to match Matlab
+  releases prior to R2012b.
+
+- The function `streamtube` is Matlab compatible and plots tubes along
+  streamlines which are scaled by the vector field divergence. The
+  Octave-only extension `ostreamtube` can be used to visualize the flow
+  expansion and contraction of the vector field due to the local
+  crossflow divergence.
+
+- The interpreter now supports handles to nested functions.
+
+- The graphics properties `"LineWidth"` and `"MarkerSize"` are now
+  measured in points, *not* pixels.  Compared to previous versions
+  of Octave, some lines and markers will appear 4/3 larger.
+
+- The meta.class property "SuperClassList" has been renamed
+  "Superclasslist" for Matlab compatibility.  The original name will
+  exist as an alias until Octave version 8.1.
+
+- Inline functions created by the function `inline` are now of type
+  "inline" when interrogated with the `class` function.  In previous
+  versions of Octave, the class returned was "function_handle".  This
+  change is Matlab compatible.  Inline functions are deprecated in
+  both Matlab and Octave and support may eventually be removed.
+  Anonymous functions can be used to replace all instances of inline
+  functions.
+
+- The function `javaaddpath` now prepends new directories to the
+  existing dynamic classpath by default.  To append them instead, use
+  the new `"-end"` argument.  Multiple directories may now be specified
+  in a cell array of strings.
+
+- An undocumented function `gui_mainfcn` has been added, for compatibility
+  with figures created with Matlab's GUIDE.
+
+- Several validator functions of type `mustBe*` have been added.  See
+  the list of new functions below.
+
+### Alphabetical list of new functions added in Octave 6
+
+* `auto_repeat_debug_command`
+* `commandhistory`
+* `commandwindow`
+* `filebrowser`
+* `is_same_file`
+* `lightangle`
+* `mustBeFinite`
+* `mustBeGreaterThan`
+* `mustBeGreaterThanOrEqual`
+* `mustBeInteger`
+* `mustBeLessThan`
+* `mustBeLessThanOrEqual`
+* `mustBeMember`
+* `mustBeNegative`
+* `mustBeNonempty`
+* `mustBeNonNan`
+* `mustBeNonnegative`
+* `mustBeNonpositive`
+* `mustBeNonsparse`
+* `mustBeNonzero`
+* `mustBeNumeric`
+* `mustBeNumericOrLogical`
+* `mustBePositive`
+* `mustBeReal`
+* `namedargs2cell`
+* `newline`
+* `ode23s`
+* `ostreamtube`
+* `rescale`
+* `rotx`
+* `roty`
+* `rotz`
+* `stream2`
+* `stream3`
+* `streamline`
+* `streamtube`
+* `uisetfont`
+* `verLessThan`
+* `web`
+* `weboptions`
+* `webread`
+* `webwrite`
+* `workspace`
+
+
+### Deprecated functions and properties
+
+The following functions and properties have been deprecated in Octave 6
+and will be removed from Octave 8 (or whatever version is the second
+major release after 6):
+
+- Functions
+
+  Function               | Replacement
+  -----------------------|------------------
+  `runtests`             | `oruntests`
+
+- Properties
+
+  Object           | Property      | Value
+  -----------------|---------------|------------
+                   |               |
+
+- The environment variable used by `mkoctfile` for linker flags is now
+  `LDFLAGS` rather than `LFLAGS`.  `LFLAGS` is deprecated, and a warning
+  is emitted if it is used, but it will continue to work.
+
+
+### Removed functions and properties
+
+The following functions and properties were deprecated in Octave 4.4
+and have been removed from Octave 6.
+
+- Functions
+
+  Function             | Replacement
+  ---------------------|------------------
+  `chop`               | `sprintf` for visual results
+  `desktop`            | `isguirunning`
+  `tmpnam`             | `tempname`
+  `toascii`            | `double`
+  `java2mat`           | `__java2mat__`
+
+- Properties
+
+  Object               | Property                  | Value
+  ---------------------|---------------------------|-----------------------
+  `annotation`         | `edgecolor ("rectangle")` |
+  `axes`               | `drawmode`                |
+  `figure`             | `doublebuffer`            |
+                       | `mincolormap`             |
+                       | `wvisual`                 |
+                       | `wvisualmode`             |
+                       | `xdisplay`                |
+                       | `xvisual`                 |
+                       | `xvisualmode`             |
+  `line`               | `interpreter`             |
+  `patch`              | `interpreter`             |
+  `surface`            | `interpreter`             |
+  `text`               | `fontweight`              | `"demi"` and `"light"`
+  `uibuttongroup`      | `fontweight`              | `"demi"` and `"light"`
+  `uicontrol`          | `fontweight`              | `"demi"` and `"light"`
+  `uipanel`            | `fontweight`              | `"demi"` and `"light"`
+  `uitable`            | `fontweight`              | `"demi"` and `"light"`
+
+
+### Old release news
+
+- [Octave 5.x](etc/NEWS.5)
+- [Octave 4.x](etc/NEWS.4)
+- [Octave 3.x](etc/NEWS.3)
+- [Octave 2.x](etc/NEWS.2)
+- [Octave 1.x](etc/NEWS.1)
--- a/examples/code/@FIRfilter/FIRfilter.m	Sun May 16 09:43:43 2021 +0200
+++ b/examples/code/@FIRfilter/FIRfilter.m	Sun May 16 09:44:35 2021 +0200
@@ -6,10 +6,6 @@
 
 function f = FIRfilter (p)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     p = @polynomial ([1]);
   elseif (! isa (p, "polynomial"))
--- a/examples/code/@FIRfilter/FIRfilter_aggregation.m	Sun May 16 09:43:43 2021 +0200
+++ b/examples/code/@FIRfilter/FIRfilter_aggregation.m	Sun May 16 09:44:35 2021 +0200
@@ -6,10 +6,6 @@
 
 function f = FIRfilter (p)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     f.polynomial = @polynomial ([1]);
   else
--- a/examples/code/@polynomial/get.m	Sun May 16 09:43:43 2021 +0200
+++ b/examples/code/@polynomial/get.m	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,6 @@
 function val = get (p, prop)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/examples/code/@polynomial/polynomial.m	Sun May 16 09:43:43 2021 +0200
+++ b/examples/code/@polynomial/polynomial.m	Sun May 16 09:44:35 2021 +0200
@@ -13,10 +13,6 @@
 
 function p = polynomial (a)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     p.poly = 0;
     p = class (p, "polynomial");
--- a/examples/code/@polynomial/polynomial_superiorto.m	Sun May 16 09:43:43 2021 +0200
+++ b/examples/code/@polynomial/polynomial_superiorto.m	Sun May 16 09:44:35 2021 +0200
@@ -13,10 +13,6 @@
 
 function p = polynomial (a)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     p.poly = [0];
     p = class (p, "polynomial");
--- a/examples/code/make_int.cc	Sun May 16 09:43:43 2021 +0200
+++ b/examples/code/make_int.cc	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,8 @@
   void operator delete (void *p, std::size_t size);
 #endif
 
-  idx_vector index_vector (bool) const { return idx_vector ((double) scalar); }
+  octave::idx_vector index_vector (bool) const
+  { return octave::idx_vector ((double) scalar); }
 
   int rows (void) const { return 1; }
   int columns (void) const { return 1; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/code/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,75 @@
+%canon_reldir%_EXTRA_DIST =
+
+%canon_reldir%_CLEANFILES =
+%canon_reldir%_DISTCLEANFILES =
+%canon_reldir%_MAINTAINERCLEANFILES =
+
+%canon_reldir%_SRC = \
+  %reldir%/@FIRfilter/FIRfilter.m \
+  %reldir%/@FIRfilter/FIRfilter_aggregation.m \
+  %reldir%/@FIRfilter/display.m \
+  %reldir%/@FIRfilter/subsasgn.m \
+  %reldir%/@FIRfilter/subsref.m \
+  %reldir%/@polynomial/disp.m \
+  %reldir%/@polynomial/double.m \
+  %reldir%/@polynomial/end.m \
+  %reldir%/@polynomial/get.m \
+  %reldir%/@polynomial/mtimes.m \
+  %reldir%/@polynomial/numel.m \
+  %reldir%/@polynomial/plot.m \
+  %reldir%/@polynomial/polynomial.m \
+  %reldir%/@polynomial/polynomial_superiorto.m \
+  %reldir%/@polynomial/polyval.m \
+  %reldir%/@polynomial/roots.m \
+  %reldir%/@polynomial/set.m \
+  %reldir%/@polynomial/subsasgn.m \
+  %reldir%/@polynomial/subsref.m \
+  %reldir%/addtwomatrices.cc \
+  %reldir%/celldemo.cc \
+  %reldir%/embedded.cc \
+  %reldir%/fortrandemo.cc \
+  %reldir%/fortransub.f \
+  %reldir%/funcdemo.cc \
+  %reldir%/globaldemo.cc \
+  %reldir%/helloworld.cc \
+  %reldir%/make_int.cc \
+  %reldir%/mex_demo.c \
+  %reldir%/mycell.c \
+  %reldir%/myfeval.c \
+  %reldir%/myfevalf.f \
+  %reldir%/myfunc.c \
+  %reldir%/myhello.c \
+  %reldir%/mypow2.c \
+  %reldir%/myprop.c \
+  %reldir%/myset.c \
+  %reldir%/mysparse.c \
+  %reldir%/mystring.c \
+  %reldir%/mystruct.c \
+  %reldir%/oct_demo.cc \
+  %reldir%/oregonator.cc \
+  %reldir%/oregonator.m \
+  %reldir%/paramdemo.cc \
+  %reldir%/polynomial2.m \
+  %reldir%/standalone.cc \
+  %reldir%/standalonebuiltin.cc \
+  %reldir%/stringdemo.cc \
+  %reldir%/structdemo.cc \
+  %reldir%/unwinddemo.cc
+
+%canon_reldir%_EXTRA_DIST += \
+  $(%canon_reldir%_SRC)
+
+EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
+
+CLEANFILES += $(%canon_reldir%_CLEANFILES)
+DISTCLEANFILES += $(%canon_reldir%_DISTCLEANFILES)
+MAINTAINERCLEANFILES += $(%canon_reldir%_MAINTAINERCLEANFILES)
+
+examples-clean:
+	rm -f $(%canon_reldir%_CLEANFILES)
+
+examples-distclean: examples-clean
+	rm -f $(%canon_reldir%_DISTCLEANFILES)
+
+examples-maintainer-clean: examples-distclean
+	rm -f $(%canon_reldir%_MAINTAINERCLEANFILES)
--- a/examples/code/polynomial2.m	Sun May 16 09:43:43 2021 +0200
+++ b/examples/code/polynomial2.m	Sun May 16 09:44:35 2021 +0200
@@ -5,10 +5,6 @@
 
   methods
     function p = polynomial2 (a)
-      if (nargin > 1)
-        print_usage ();
-      endif
-
       if (nargin == 1)
         if (isa (a, "polynomial2"))
           p.poly = a.poly;
--- a/examples/code/unwinddemo.cc	Sun May 16 09:43:43 2021 +0200
+++ b/examples/code/unwinddemo.cc	Sun May 16 09:44:35 2021 +0200
@@ -21,14 +21,16 @@
   NDArray a = args(0).array_value ();
   NDArray b = args(1).array_value ();
 
-  // Declare unwind_protect frame which lasts as long as
-  // the variable frame has scope.
-  octave::unwind_protect frame;
-  frame.add_fcn (set_liboctave_warning_handler,
-                 current_liboctave_warning_handler);
+  // Create unwind_action objects.  At the end of the enclosing scope,
+  // destructors for these objects will call the given functions with
+  // the specified arguments.
 
-  frame.add_fcn (set_liboctave_warning_with_id_handler,
-                 current_liboctave_warning_with_id_handler);
+  octave::unwind_action restore_warning_handler
+    (set_liboctave_warning_handler, current_liboctave_warning_handler);
+
+  octave::unwind_action restore_warning_with_id_handler
+    (set_liboctave_warning_with_id_handler,
+     current_liboctave_warning_with_id_handler);
 
   set_liboctave_warning_handler (my_err_handler);
   set_liboctave_warning_with_id_handler (my_err_with_id_handler);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/data/README	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,51 @@
+* penny data file:
+
+  See the discussion here:
+  https://savannah.gnu.org/patch/?func=detailitem&item_id=8472
+
+* west0479 data file:
+
+  Chemical engineering plant models Eight stage column section, all
+  rigorous from set CHEMWEST, from the Harwell-Boeing Collection.
+
+  west0479.mtx: original file obtained from from
+  https://math.nist.gov/MatrixMarket/data/Harwell-Boeing/chemwest/west0479.html
+
+  west0479.mat: generated from west0479.mtx as follows:
+
+    x = load ("west0479.mtx");
+    nr = x(1,1);
+    nc = x(1,2);
+    i = x(2:end,1);
+    j = x(2:end,2);
+    sv = x(2:end,3);
+    west0479 = sparse(i, j, sv, nr, nc);
+    save -text west0479.mat west0479
+
+  Note that the original file has 1910 entries but 22 of them are exact
+  zeros:
+
+    384 86  0.0000000000000e+00
+    360 116  0.0000000000000e+00
+    361 117  0.0000000000000e+00
+    362 118  0.0000000000000e+00
+    238 224  0.0000000000000e+00
+    239 225  0.0000000000000e+00
+    240 226  0.0000000000000e+00
+    250 240  0.0000000000000e+00
+    251 241  0.0000000000000e+00
+    252 242  0.0000000000000e+00
+    272 259  0.0000000000000e+00
+    273 260  0.0000000000000e+00
+    274 261  0.0000000000000e+00
+    294 278  0.0000000000000e+00
+    295 279  0.0000000000000e+00
+    296 280  0.0000000000000e+00
+    316 297  0.0000000000000e+00
+    317 298  0.0000000000000e+00
+    318 299  0.0000000000000e+00
+    338 316  0.0000000000000e+00
+    339 317  0.0000000000000e+00
+    340 318  0.0000000000000e+00
+
+  These are not explicitly included in the west0479.mat file.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/data/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,15 @@
+%canon_reldir%_EXTRA_DIST =
+
+%canon_reldir%_DAT = \
+  %reldir%/penny.mat \
+  %reldir%/west0479.mat
+
+%canon_reldir%_EXTRA_DIST += \
+  $(%canon_reldir%_DAT) \
+  %reldir%/README \
+  %reldir%/west0479.mtx
+
+octdata_DATA += \
+  $(%canon_reldir%_DAT)
+
+EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/data/west0479.mat	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1896 @@
+# Created by Octave 5.2.0, Thu Jun 04 22:49:15 2020 EDT <jwe@devnull>
+# name: west0479
+# type: sparse matrix
+# nnz: 1888
+# rows: 479
+# columns: 479
+25 1 1
+31 1 -0.037648130000000002
+87 1 -0.34423959999999998
+26 2 1
+31 2 -0.024522619999999998
+88 2 -0.3737086
+27 3 1
+31 3 -0.036613039999999999
+89 3 -0.83693790000000001
+28 4 130
+29 4 -2.433767
+29 5 1
+30 5 -1.6140909999999999
+30 6 1.6140909999999999
+31 6 -0.21873210000000001
+87 6 -1
+88 6 -1
+89 6 -1
+32 7 -1.138352
+43 7 0.036694280000000003
+111 7 0.099316360000000006
+112 7 0.099316360000000006
+113 7 0.099316360000000006
+33 8 -0.5
+43 8 0.016117289999999999
+111 8 0.087245760000000006
+34 9 -0.36119180000000001
+43 9 0.01164286
+112 9 0.1050415
+35 10 -0.3218876
+43 10 0.01037591
+113 10 0.1404166
+36 11 -0.43624160000000001
+37 11 -0.76804249999999996
+38 11 -0.14302790000000001
+39 11 -0.15938859999999999
+37 12 1
+43 12 -0.048560819999999998
+111 12 -0.2628684
+38 13 1
+43 13 -0.030925950000000001
+112 13 -0.27901280000000001
+39 14 1
+43 14 -0.046123589999999999
+113 14 -0.62418819999999997
+40 15 5.2824359999999997
+42 15 -0.61239209999999999
+41 16 0.2886822
+42 16 -0.2163815
+42 17 1.3287739999999999
+43 17 -0.36946859999999998
+111 17 -1
+112 17 -1
+113 17 -1
+2 18 48.176470000000002
+8 18 -1
+11 18 -3.3474840000000003e-05
+3 19 83.5
+9 19 -1
+12 19 -4.1365390000000001e-05
+4 20 171.94120000000001
+10 20 -1
+13 20 -8.4843450000000005e-05
+5 21 96.651380000000003
+8 21 2.5
+11 21 3.3474840000000003e-05
+6 22 168.2706
+9 22 2.5
+12 22 4.1365390000000001e-05
+7 23 347.5872
+10 23 2.5
+13 23 8.4843450000000005e-05
+8 24 1
+17 24 -0.1106967
+27 24 1.605232
+9 25 1
+17 25 -0.089808520000000003
+10 26 1
+17 26 -0.15173690000000001
+11 27 1.0104550000000001
+18 27 -0.5
+12 28 1.005978
+18 28 -0.29999999999999999
+13 29 1.002885
+18 29 -0.20000000000000001
+14 30 1
+17 30 -0.1811855
+15 31 1
+17 31 -0.24002390000000001
+16 32 1
+17 32 -0.22654840000000001
+17 33 1
+19 33 -1
+30 33 1.5
+42 33 0.5
+18 34 1
+20 34 -316220
+23 34 -12323.690000000001
+24 34 -1
+30 34 -35226.800000000003
+41 34 18449.02
+19 35 5.2983390000000004
+21 35 0.0024526869999999998
+20 36 1080.8589999999999
+21 36 -0.2050215
+21 37 0.14419199999999999
+22 37 63.05986
+30 37 -0.1159299
+22 38 -18449.02
+24 38 0.84533389999999997
+40 38 -18449.02
+41 38 -15595.58
+23 39 1
+30 39 0.20204929999999999
+42 39 -0.88547100000000001
+24 40 0.0001000234
+30 40 2.4483389999999998
+42 40 0.81611299999999998
+68 41 1
+74 41 -0.0002278669
+99 41 -0.26243949999999999
+69 42 1
+74 42 -0.00041887629999999999
+100 42 -0.32161960000000001
+70 43 1
+74 43 -0.001576933
+101 43 -0.72647609999999996
+71 44 300
+72 44 -2.8518910000000002
+72 45 1
+73 45 -0.28701589999999999
+73 46 0.28701589999999999
+74 46 -0.0043413219999999999
+99 46 -1
+100 46 -1
+101 46 -1
+75 47 -1.138352
+86 47 0.042002860000000003
+123 47 0.9414806
+124 47 0.9414806
+125 47 0.9414806
+76 48 -0.3218876
+86 48 0.011877
+123 48 1.3310949999999999
+77 49 -0.36119180000000001
+86 49 0.013327240000000001
+124 49 0.99575290000000005
+78 50 -0.5
+86 50 0.01844898
+125 50 0.82705600000000001
+79 51 -1
+80 51 -19.239999999999998
+81 51 -3.8029999999999999
+82 51 -9.4809999999999999
+80 52 1
+86 52 -0.00088757840000000001
+123 52 -0.099473919999999993
+81 53 1
+86 53 -0.0013313680000000001
+124 53 -0.099473919999999993
+82 54 1
+86 54 -0.0022189459999999999
+125 54 -0.099473919999999993
+83 55 1.177613
+85 55 -3.1089630000000001
+84 56 0.99194249999999995
+85 56 -2.640056
+85 57 3.1921119999999998
+86 57 -0.044613630000000001
+123 57 -1
+124 57 -1
+125 57 -1
+45 58 109.86879999999999
+51 58 -1
+54 58 -3.3081099999999997e-05
+46 59 191.38460000000001
+52 59 -1
+55 59 -4.1084670000000001e-05
+47 60 395.4796
+53 60 -1
+56 60 -8.456383e-05
+48 61 221.73390000000001
+51 61 2.5
+54 61 3.3081099999999997e-05
+49 62 387.00920000000002
+52 62 2.5
+55 62 4.1084670000000001e-05
+50 63 800.81650000000002
+53 63 2.5
+56 63 8.456383e-05
+51 64 1
+60 64 -0.0091702290000000002
+52 65 1
+60 65 -0.046441099999999999
+53 66 1
+60 66 -0.48999189999999998
+54 67 1.0045299999999999
+61 67 -0.20000000000000001
+55 68 1.002591
+61 68 -0.29999999999999999
+56 69 1.00125
+61 69 -0.5
+57 70 1
+60 70 -0.037500529999999997
+58 71 1
+60 71 -0.124143
+59 72 1
+60 72 -0.29275319999999999
+60 73 1
+62 73 -1
+73 73 0.18537329999999999
+85 73 0.06179109
+61 74 1
+63 74 -316220
+66 74 -16364.190000000001
+67 74 -1
+73 74 -4696.7820000000002
+84 74 131.85400000000001
+62 75 22.12913
+64 75 0.95375259999999995
+63 76 2494.29
+64 76 -1.021587
+64 77 0.88782810000000001
+65 77 1.0400419999999999
+73 77 -2.640056
+65 78 -131.85400000000001
+67 78 0.0080574700000000006
+83 78 -131.85400000000001
+84 78 -1.0624089999999999
+66 79 1
+73 79 0.1016426
+85 79 -0.06179109
+67 80 0.0076452569999999999
+73 80 23.098949999999999
+85 80 7.699649
+31 81 1
+244 81 1
+43 82 1
+1 83 1
+17 83 -3.850231
+18 83 -8.4599350000000005e-05
+31 83 2.0159099999999999
+35 83 1
+43 83 1.596171
+243 83 -0.78975119999999999
+74 84 1
+388 84 0.88175619999999999
+86 85 1
+44 86 1
+60 86 -2.7937599999999998
+61 86 -8.4458229999999999e-05
+74 86 2.0156649999999998
+78 86 1
+86 86 1.5939939999999999
+387 86 -0.96191499999999996
+385 87 0.002424669
+386 87 0.030362779999999999
+387 87 0.67304509999999995
+388 87 1.45936
+96 88 0.016896609999999999
+97 88 0.034848030000000002
+98 88 -0.060080179999999997
+120 88 -0.55527170000000003
+121 88 -0.47703980000000001
+122 88 -0.1858293
+141 88 -1
+142 88 -1
+143 88 -1
+185 88 -55.188569999999999
+186 88 -95.676860000000005
+187 88 -215.83770000000001
+389 88 1
+438 88 1
+439 88 1
+440 88 1
+441 88 1
+442 88 1
+443 88 1
+450 88 -0.0018907559999999999
+451 88 -0.0015311400000000001
+452 88 -0.001013726
+455 88 2.5
+456 88 26.063700000000001
+458 88 1
+459 88 -1.5
+461 88 -9.6031809999999993
+462 88 -9.4541850000000007
+463 88 -9.4376809999999995
+464 88 -48.295720000000003
+472 88 0.90759219999999996
+473 88 -4.3759670000000002
+474 88 -8.997992
+475 88 -8.8819579999999991
+476 88 1
+182 89 1
+183 89 1
+184 89 1
+391 89 1
+455 89 -1
+456 89 -26.063700000000001
+458 89 -1
+468 89 1
+388 90 -1.45936
+467 90 1
+479 91 1
+203 92 -1
+204 92 -1
+205 92 -1
+209 92 1
+210 92 1
+211 92 1
+382 92 56.953099999999999
+385 92 0.70583249999999997
+437 92 1
+453 92 -0.64913719999999997
+454 92 -3.2948409999999999e-05
+467 92 0.53807479999999996
+469 92 1
+479 92 0.082471119999999995
+203 93 -1
+204 93 -1
+205 93 -1
+209 93 1
+210 93 1
+211 93 1
+383 93 11.58384
+386 93 0.70583249999999997
+437 93 1
+453 93 -1.021542
+454 93 -4.0990330000000002e-05
+467 93 -0.36302479999999998
+470 93 1
+479 93 0.069522609999999999
+203 94 -1
+204 94 -1
+205 94 -1
+209 94 1
+210 94 1
+211 94 1
+384 94 0.3209631
+387 94 0.70583249999999997
+437 94 1
+453 94 -2.049007
+454 94 -8.4470029999999998e-05
+467 94 0.91353620000000002
+471 94 1
+479 94 0.83976379999999995
+241 95 0.55083519999999997
+242 95 0.4489223
+243 95 0.0002425203
+244 95 0.40528330000000001
+108 96 -0.067276619999999995
+109 96 -0.15700610000000001
+110 96 -0.097475699999999998
+132 96 -0.25060070000000001
+133 96 -0.2802617
+134 96 0.1008491
+245 96 -1
+395 96 1
+396 96 1
+397 96 1
+398 96 1
+399 96 1
+400 96 1
+407 96 -0.0028636019999999998
+408 96 -0.0023162590000000002
+409 96 -0.00153089
+412 96 2.5
+413 96 11.5878
+415 96 1
+416 96 -1.101224
+418 96 -1.3644320000000001
+419 96 -1.2188209999999999
+420 96 -1.2108589999999999
+421 96 -34.621049999999997
+429 96 0.60313589999999995
+430 96 -0.59963840000000002
+431 96 -1.403392
+432 96 -1.3703860000000001
+433 96 1
+246 97 1
+412 97 -1
+413 97 -11.5878
+415 97 -1
+425 97 1
+244 98 -0.40528330000000001
+424 98 1
+436 99 1
+160 100 -0.85938400000000004
+161 100 -0.773339
+162 100 -0.79517400000000005
+238 100 -1
+241 100 1
+394 100 1
+410 100 -1.623659
+411 100 -3.3032779999999999e-05
+424 100 3.5720350000000001
+426 100 1
+436 100 0.92435319999999999
+160 101 -1.171821
+161 101 -1.277352
+162 101 -1.250508
+239 101 -1
+242 101 1
+394 101 1
+410 101 -2.4602889999999999
+411 101 -4.1050809999999997e-05
+424 101 -2.1785329999999998
+427 101 1
+436 101 0.65098420000000001
+160 102 -2.3280470000000002
+161 102 -2.4161549999999998
+162 102 -2.5121660000000001
+240 102 -1
+243 102 1
+394 102 1
+410 102 -4.7536199999999997
+411 102 -8.45305e-05
+424 102 6.1671399999999998
+428 102 1
+436 102 3.3966910000000001
+241 103 0.043736570000000002
+242 103 0.57396460000000005
+243 103 0.15834899999999999
+244 103 0.18781249999999999
+253 103 -0.044344130000000002
+254 103 -0.58193779999999995
+255 103 -0.16054869999999999
+256 103 -1
+135 104 -1
+136 104 -1
+137 104 -1
+151 104 -62.680900000000001
+152 104 -123.89
+153 104 -464.35550000000001
+245 104 1
+248 104 -0.051646549999999999
+249 104 -0.32417620000000003
+148 105 1
+149 105 1
+150 105 1
+247 105 1
+244 106 -0.18781249999999999
+248 106 1
+256 106 1
+249 107 1
+147 108 1
+169 108 -1
+170 108 -1
+171 108 -1
+175 108 1
+176 108 1
+177 108 1
+238 108 9.7738750000000003
+241 108 0.77605020000000002
+248 108 7.2528309999999996
+249 108 0.78041000000000005
+253 108 -0.78683060000000005
+147 109 1
+169 109 -1
+170 109 -1
+171 109 -1
+175 109 1
+176 109 1
+177 109 1
+239 109 0.60698209999999997
+242 109 0.77605020000000002
+248 109 -2.3895080000000002
+249 109 0.68493979999999999
+254 109 -0.78683060000000005
+147 110 1
+169 110 -1
+170 110 -1
+171 110 -1
+175 110 1
+176 110 1
+177 110 1
+240 110 0.001188564
+243 110 0.77605020000000002
+248 110 11.55883
+249 110 2.2026439999999998
+255 110 -0.78683060000000005
+363 111 -0.17051479999999999
+364 111 -0.43429630000000002
+365 111 -0.26674209999999998
+366 111 -2.609302
+385 111 0.1956447
+386 111 0.49830160000000001
+387 111 0.30605369999999998
+388 111 0.42239599999999999
+215 112 1
+216 112 1
+217 112 1
+218 112 1
+219 112 1
+220 112 1
+227 112 -0.0018907559999999999
+228 112 -0.0015311400000000001
+229 112 -0.001013726
+232 112 2.5
+233 112 16.672409999999999
+235 112 1
+236 112 -1.5
+389 112 -1
+392 112 -0.46212130000000001
+393 112 -0.1234962
+232 113 -1
+233 113 -16.672409999999999
+235 113 -1
+368 113 -1
+369 113 -1
+390 113 1
+366 114 2.609302
+388 114 -0.42239599999999999
+392 114 1
+393 115 1
+181 116 1
+194 116 -0.58697619999999995
+195 116 -0.50651550000000001
+196 116 -0.5139918
+230 116 -1.0366850000000001
+231 116 -3.2948409999999999e-05
+363 116 -0.87155309999999997
+382 116 -1
+385 116 1
+392 116 2.63998
+393 116 0.55742069999999999
+181 117 1
+194 117 -0.80016370000000003
+195 117 -0.83640899999999996
+196 117 -0.8081026
+230 117 -1.6376949999999999
+231 117 -4.0990330000000002e-05
+364 117 -0.87155309999999997
+383 117 -1
+386 117 1
+392 117 -1.7736780000000001
+393 117 0.40754220000000002
+181 118 1
+194 118 -1.5893889999999999
+195 118 -1.5818110000000001
+196 118 -1.6231180000000001
+230 118 -3.205686
+231 118 -8.4470029999999998e-05
+365 118 -0.87155309999999997
+384 118 -1
+387 118 1
+392 118 4.4676090000000004
+393 118 2.2475290000000001
+93 119 -1
+96 119 -1
+248 119 -0.40421560000000001
+262 119 -0.1818777
+284 119 -0.1563455
+306 119 -0.15456990000000001
+328 119 -0.1521778
+350 119 -0.091905799999999996
+372 119 -0.0078705370000000004
+94 120 -1
+97 120 -1
+248 120 -1.8091710000000001
+262 120 -3.1896550000000001
+284 120 -3.3490190000000002
+306 120 -3.358644
+328 120 -3.3085849999999999
+350 120 -1.96787
+372 120 -0.11333559999999999
+95 121 -1
+98 121 -1
+248 121 -2.4566020000000002
+262 121 -4.1011280000000001
+284 121 -4.2908920000000004
+306 121 -4.3026030000000004
+328 121 -4.2541469999999997
+350 121 -2.9523890000000002
+372 121 -1.157365
+93 122 -0.0081214960000000006
+96 122 -0.016896609999999999
+248 122 -0.0045387600000000002
+262 122 -0.00217052
+284 122 -0.0018740689999999999
+306 122 -0.0018533180000000001
+328 122 -0.0018248369999999999
+350 122 -0.001106561
+372 122 -0.0001054494
+94 123 -0.016749989999999999
+97 123 -0.034848030000000002
+248 123 -0.041896919999999997
+262 123 -0.078506679999999995
+284 123 -0.082793510000000001
+306 123 -0.083055320000000002
+328 123 -0.081826380000000004
+350 123 -0.048866050000000001
+372 123 -0.0031317319999999999
+95 124 -0.028878029999999999
+98 124 -0.060080179999999997
+248 124 -0.098082240000000001
+262 124 -0.17402809999999999
+284 124 -0.18288550000000001
+306 124 -0.1834374
+328 124 -0.18139140000000001
+350 124 -0.12639719999999999
+372 124 -0.055136770000000002
+105 125 -1
+108 125 -1
+264 125 -0.76362319999999995
+286 125 -0.5413211
+308 125 -0.52907530000000003
+330 125 -0.52832599999999996
+352 125 -0.52965340000000005
+374 125 -0.59901059999999995
+392 125 -0.57467679999999999
+106 126 -1
+109 126 -1
+264 126 -1.4679789999999999
+286 126 -1.289806
+308 126 -1.279992
+330 126 -1.279385
+352 126 -1.2801739999999999
+374 126 -1.3601430000000001
+392 126 -0.71491899999999997
+107 127 -1
+110 127 -1
+264 127 -0.0043708569999999997
+286 127 -0.0039541009999999998
+308 127 -0.0039318030000000002
+330 127 -0.0039476679999999997
+352 127 -0.0047490229999999998
+374 127 -0.072455389999999995
+392 127 -1.6023639999999999
+105 128 -0.1122933
+108 128 -0.067276619999999995
+264 128 -0.054601370000000003
+286 128 -0.038877219999999997
+308 128 -0.03800866
+330 128 -0.037958989999999998
+352 128 -0.038208859999999997
+374 128 -0.048085490000000002
+392 128 -0.05817862
+106 129 -0.2620633
+109 129 -0.15700610000000001
+264 129 -0.24496080000000001
+286 129 -0.2161806
+308 129 -0.21459739999999999
+330 129 -0.21451909999999999
+352 129 -0.21552299999999999
+374 129 -0.25480999999999998
+392 129 -0.16890749999999999
+107 130 -0.1626995
+110 130 -0.097475699999999998
+264 130 -0.00045281759999999999
+286 130 -0.00041145290000000001
+308 130 -0.00040925029999999999
+330 130 -0.0004109467
+352 130 -0.00049637369999999995
+374 130 -0.0084271850000000002
+392 130 -0.2350352
+117 131 -1
+120 131 -1
+249 131 -0.069702840000000002
+263 131 -0.019243320000000001
+285 131 -0.01583793
+307 131 -0.01561791
+329 131 -0.01558321
+351 131 -0.01471856
+373 131 -0.0057599519999999996
+118 132 -1
+121 132 -1
+249 132 -0.74171359999999997
+263 132 -0.80234939999999999
+285 132 -0.80658470000000004
+307 132 -0.80682860000000001
+329 132 -0.80550310000000003
+351 132 -0.74926979999999999
+373 132 -0.19719700000000001
+119 133 -1
+122 133 -1
+249 133 -0.51275979999999999
+263 133 -0.52522530000000001
+285 133 -0.52614130000000003
+307 133 -0.52622449999999998
+329 133 -0.52730270000000001
+351 133 -0.57231860000000001
+373 133 -1.025242
+117 134 -0.46575929999999999
+120 134 -0.96900310000000001
+249 134 -0.044884880000000002
+263 134 -0.01317012
+285 134 -0.01088739
+307 134 -0.010739240000000001
+329 134 -0.01071655
+351 134 -0.01016303
+373 134 -0.0044257189999999998
+118 135 -0.57440230000000003
+121 135 -1.195033
+249 135 -0.58903419999999995
+263 135 -0.67721739999999997
+285 135 -0.68380180000000002
+307 135 -0.68420530000000002
+329 135 -0.68315610000000004
+351 135 -0.63804399999999994
+373 135 -0.18686159999999999
+119 136 -0.2292285
+122 136 -0.47690549999999998
+249 136 -0.1625065
+263 136 -0.17691419999999999
+285 136 -0.1780062
+307 136 -0.17808560000000001
+329 136 -0.17846999999999999
+351 136 -0.19449250000000001
+373 136 -0.38770260000000001
+129 137 -1
+132 137 -1
+265 137 -0.34272789999999997
+287 137 -0.2911376
+309 137 -0.2876937
+331 137 -0.28748889999999999
+353 137 -0.28823179999999998
+375 137 -0.30269869999999999
+393 137 -0.17507890000000001
+130 138 -1
+133 138 -1
+265 138 -1.0623339999999999
+287 138 -1.118506
+309 138 -1.1222529999999999
+331 138 -1.122512
+353 138 -1.1232850000000001
+375 138 -1.1082339999999999
+393 138 -0.35118640000000001
+131 139 -1
+134 139 -1
+265 139 -0.0023999820000000002
+287 139 -0.00260173
+309 139 -0.0026156270000000001
+331 139 -0.0026280330000000001
+353 139 -0.0031617350000000002
+375 139 -0.044793810000000003
+393 139 -0.59723090000000001
+129 140 -2.0182530000000001
+132 140 -1.209166
+265 140 -0.44044889999999998
+287 140 -0.3758029
+309 140 -0.37146430000000003
+331 140 -0.37124049999999997
+353 140 -0.37371090000000001
+375 140 -0.43672879999999997
+393 140 -0.31856279999999998
+130 141 -2.5626880000000001
+133 141 -1.535345
+265 141 -1.7335130000000001
+287 141 -1.833245
+309 141 -1.839915
+331 141 -1.840541
+353 141 -1.849286
+375 141 -2.0302660000000001
+393 141 -0.81137049999999999
+131 142 -0.92554289999999995
+134 142 -0.55450670000000002
+265 142 -0.0014144089999999999
+287 142 -0.001540086
+309 142 -0.0015487579999999999
+331 142 -0.0015562740000000001
+353 142 -0.001879925
+375 142 -0.029637400000000001
+393 142 -0.49833870000000002
+135 143 -1.4338919999999999
+141 143 -2.1577039999999998
+266 143 -1.523971
+288 143 -1.530708
+310 143 -1.531148
+332 143 -1.5313159999999999
+354 143 -1.537533
+376 143 -1.710928
+136 144 -0.94320599999999999
+142 144 -1.4193260000000001
+267 144 -1.0024599999999999
+289 144 -1.006891
+311 144 -1.0071810000000001
+333 144 -1.0072909999999999
+355 144 -1.0113810000000001
+377 144 -1.1254390000000001
+137 145 -0.59645269999999995
+143 145 -0.89753530000000004
+268 145 -0.63392269999999995
+290 145 -0.63672519999999999
+312 145 -0.63690829999999998
+334 145 -0.63697809999999999
+356 145 -0.63956420000000003
+378 145 -0.71169090000000002
+135 146 -1
+141 146 -1
+266 146 -1
+288 146 -1
+310 146 -1
+332 146 -1
+354 146 -1
+376 146 -1
+136 147 -1
+142 147 -1
+267 147 -1
+289 147 -1
+311 147 -1
+333 147 -1
+355 147 -1
+377 147 -1
+137 148 -1
+143 148 -1
+268 148 -1
+290 148 -1
+312 148 -1
+334 148 -1
+356 148 -1
+378 148 -1
+138 149 -1
+148 149 1
+238 149 0.55083519999999997
+139 150 -1
+149 150 1.6474949999999999
+239 150 0.73959730000000001
+140 151 -1
+150 151 841.35159999999996
+240 151 0.2040448
+144 152 -1
+182 152 1
+382 152 0.1956447
+145 153 -1
+183 153 1
+383 153 0.49830160000000001
+146 154 -1
+184 154 3.1156220000000001
+384 154 0.95354779999999995
+395 155 66.224919999999997
+401 155 -1
+404 155 -3.3282569999999997e-05
+396 156 115.06229999999999
+402 156 -1
+405 156 -4.122831e-05
+397 157 237.33869999999999
+403 157 -1
+406 157 -8.4706899999999994e-05
+398 158 133.245
+401 158 2.5
+404 158 3.3282569999999997e-05
+399 159 232.26390000000001
+402 159 2.5
+405 159 4.122831e-05
+400 160 480.18209999999999
+403 160 2.5
+406 160 8.4706899999999994e-05
+160 161 -0.47337899999999999
+401 161 1
+410 161 -0.2116876
+161 162 -0.57343169999999999
+402 162 1
+410 162 -0.31667149999999999
+162 163 -0.00060925110000000003
+403 163 1
+410 163 -3.511874e-07
+163 164 -4575.0039999999999
+404 164 1.0075620000000001
+411 164 -0.55083519999999997
+164 165 -3681.4160000000002
+405 165 1.004324
+411 165 -0.4489223
+165 166 -1787.818
+406 166 1.002087
+411 166 -0.0002425203
+160 167 -0.52605639999999998
+161 167 -0.42598229999999998
+407 167 1
+410 167 -0.47048839999999997
+160 168 -0.00056459870000000005
+162 168 -0.4380098
+408 168 1
+410 168 -0.00050495930000000002
+161 169 -0.00058596669999999996
+162 169 -0.56138089999999996
+409 169 1
+410 169 -0.00064718760000000001
+163 170 -1
+164 170 -1
+165 170 -1
+410 170 1
+412 170 -1
+423 170 0.061444209999999999
+435 170 0.0204814
+157 171 -1
+163 171 4124.0600000000004
+164 171 4124.0600000000004
+165 171 4124.0600000000004
+411 171 1
+413 171 -316220
+416 171 -20034.240000000002
+417 171 -1
+423 171 -2625.6570000000002
+434 171 222.12899999999999
+412 172 18.737269999999999
+414 172 0.94488159999999999
+413 173 1494.367
+414 173 -1.02078
+158 174 -0.99186010000000002
+163 174 -17.922339999999998
+164 174 -17.922339999999998
+165 174 -17.922339999999998
+414 174 0.86282899999999996
+415 174 1.0497190000000001
+423 174 -0.73414950000000001
+157 175 0.0081398600000000005
+415 175 -222.12899999999999
+417 175 0.0081398600000000005
+433 175 -222.12899999999999
+434 175 -1.8080989999999999
+163 176 -1.0913280000000001
+164 176 -1.629397
+165 176 -1.4448529999999999
+416 176 1
+423 176 0.047364059999999999
+435 176 -0.027898139999999998
+417 177 0.0045385340000000003
+423 177 7.5792400000000004
+435 177 2.5264129999999998
+148 178 -1
+178 178 -1
+149 179 -1
+179 179 -1
+150 180 -1
+180 180 -1
+148 181 1.0266459999999999
+166 181 -1
+149 182 1.0737239999999999
+167 182 -1
+150 183 1.2081470000000001
+168 183 -1
+148 184 -1
+154 184 -1
+149 185 -1
+155 185 -1
+150 186 -1
+156 186 -1
+215 187 99.149730000000005
+221 187 -1
+224 187 -3.311398e-05
+216 188 172.6396
+222 188 -1
+225 188 -4.1108120000000002e-05
+217 189 356.63979999999998
+223 189 -1
+226 189 -8.4587179999999994e-05
+218 190 200.0008
+221 190 2.5
+224 190 3.311398e-05
+219 191 349.00330000000002
+222 191 2.5
+225 191 4.1108120000000002e-05
+220 192 722.06780000000003
+223 192 2.5
+226 192 8.4587179999999994e-05
+194 193 -0.1148388
+221 193 1
+230 193 -0.011645920000000001
+195 194 -0.41678389999999998
+222 194 1
+230 194 -0.17006160000000001
+196 195 -0.49676140000000002
+223 195 1
+230 195 -0.2436893
+197 196 -5276.8620000000001
+224 196 1.0050250000000001
+231 196 -0.1956447
+198 197 -4241.5910000000003
+225 197 1.002874
+231 197 -0.49830160000000001
+199 198 -2058.2939999999999
+226 198 1.001387
+231 198 -0.30605369999999998
+194 199 -0.39872279999999999
+195 199 -0.099097089999999999
+227 199 1
+230 199 -0.080869759999999999
+194 200 -0.48643839999999999
+196 200 -0.1005598
+228 200 1
+230 200 -0.098660410000000004
+195 201 -0.48411900000000002
+196 201 -0.4026788
+229 201 1
+230 201 -0.39507300000000001
+197 202 -1
+198 202 -1
+199 202 -1
+230 202 1
+232 202 -1
+191 203 -1
+197 203 3297.623
+198 203 3297.623
+199 203 3297.623
+231 203 1
+233 203 -316220
+236 203 -18966.66
+237 203 -1
+232 204 22.66987
+234 204 0.95486020000000005
+233 205 2248.7060000000001
+234 205 -1.0206550000000001
+192 206 -0.99229509999999999
+197 206 -21.898569999999999
+198 206 -21.898569999999999
+199 206 -21.898569999999999
+234 206 0.89000959999999996
+235 206 1.0392049999999999
+191 207 0.0077048969999999996
+235 207 -146.1362
+237 207 0.0077048969999999996
+197 208 -0.65890519999999997
+198 208 -1.1064970000000001
+199 208 -1.000909
+236 208 1
+237 209 0.0068956570000000003
+182 210 -1
+212 210 -1
+183 211 -1
+213 211 -1
+184 212 -1
+214 212 -1
+182 213 1
+200 213 -1
+183 214 1.0226759999999999
+201 214 -1
+184 215 1.091418
+202 215 -1
+182 216 -1
+188 216 -1
+183 217 -1
+189 217 -1
+184 218 -1
+190 218 -1
+241 219 -0.19969609999999999
+242 219 -0.78596160000000004
+243 219 -0.00064128229999999996
+244 219 0.40690409999999999
+253 219 0.20247019999999999
+254 219 0.79687960000000002
+255 219 0.00065019060000000002
+256 219 -2.166544
+257 220 -1
+264 220 -0.30001499999999998
+265 220 -0.40746149999999998
+246 221 -1
+247 221 -1
+258 221 1
+244 222 0.40690409999999999
+256 222 -2.166544
+264 222 1
+265 223 1
+241 224 -0.98629889999999998
+250 224 -1
+253 224 1
+261 224 1
+264 224 3.5018579999999999
+265 224 1.241884
+242 225 -0.98629889999999998
+251 225 -1
+254 225 1
+261 225 1
+264 225 -2.149559
+265 225 0.93602390000000002
+243 226 -0.98629889999999998
+252 226 -1
+255 226 1
+261 226 1
+264 226 6.0259859999999996
+265 226 4.0868380000000002
+253 227 0.0119553
+254 227 0.61475029999999997
+255 227 0.1605955
+256 227 0.59918099999999996
+275 227 -0.011949680000000001
+276 227 -0.61446120000000004
+277 227 -0.16052
+278 227 -1
+257 228 1
+262 228 -0.093350859999999994
+263 228 -0.34681810000000002
+266 228 -1
+267 228 -1
+268 228 -1
+259 229 1
+256 230 -0.59918099999999996
+262 230 1
+278 230 1
+263 231 1
+250 232 13.33342
+253 232 0.78730109999999998
+260 232 1
+262 232 12.12026
+263 232 0.77025089999999996
+275 232 -0.78693089999999999
+251 233 1.020551
+254 233 0.78730109999999998
+260 233 1
+262 233 -3.9843989999999998
+263 233 0.681342
+276 233 -0.78693089999999999
+252 234 0.0031874849999999999
+255 234 0.78730109999999998
+260 234 1
+262 234 19.25216
+263 234 2.236907
+277 234 -0.78693089999999999
+253 235 -0.17008129999999999
+254 235 -0.82969219999999999
+255 235 -0.00069701409999999996
+256 235 2.5673629999999998
+275 235 0.1700014
+276 235 0.82930199999999998
+277 235 0.00069668629999999996
+278 235 -4.2847869999999997
+279 236 -1
+286 236 -0.25546930000000001
+287 236 -0.41224569999999999
+258 237 -1
+259 237 -1
+280 237 1
+256 238 2.5673629999999998
+278 238 -4.2847869999999997
+286 238 1
+287 239 1
+253 240 -1.0004710000000001
+272 240 -1
+275 240 1
+283 240 1
+286 240 2.9555289999999999
+287 240 1.2544139999999999
+254 241 -1.0004710000000001
+273 241 -1
+276 241 1
+283 241 1
+286 241 -1.8159689999999999
+287 241 0.94521189999999999
+255 242 -1.0004710000000001
+274 242 -1
+277 242 1
+283 242 1
+286 242 5.0849970000000004
+287 242 4.1364789999999996
+250 243 0.20247019999999999
+269 243 -1
+251 244 0.79687960000000002
+270 244 -1
+252 245 0.20398230000000001
+271 245 -1
+275 246 0.0098180809999999993
+276 246 0.61664169999999996
+278 246 0.95579440000000004
+297 246 -0.0098175689999999999
+298 246 -0.61660959999999998
+299 246 -0.16051480000000001
+300 246 -1
+279 247 1
+284 247 -0.098217899999999997
+285 247 -0.34856389999999998
+288 247 -1
+289 247 -1
+290 247 -1
+281 248 1
+278 249 -0.95579440000000004
+284 249 1
+300 249 1
+285 250 1
+272 251 13.626709999999999
+275 251 0.78698299999999999
+282 251 1
+284 251 12.68233
+285 251 0.76942869999999997
+297 251 -0.78694200000000003
+273 252 1.058389
+276 252 0.78698299999999999
+282 252 1
+284 252 -4.1684890000000001
+285 252 0.68102850000000004
+298 252 -0.78694200000000003
+274 253 0.0034155829999999998
+277 253 0.78698299999999999
+282 253 1
+284 253 20.139959999999999
+285 253 2.2394150000000002
+299 253 -0.78694200000000003
+275 254 -0.16786980000000001
+276 254 -0.83148250000000001
+277 254 -0.00069990470000000002
+278 254 4.3289929999999996
+297 254 0.16786100000000001
+298 254 0.83143909999999999
+299 254 0.00069986820000000004
+300 254 -4.5292089999999998
+301 255 -1
+308 255 -0.2530153
+309 255 -0.4125625
+280 256 -1
+281 256 -1
+302 256 1
+278 257 4.3289929999999996
+300 257 -4.5292089999999998
+308 257 1
+309 258 1
+275 259 -1.0000519999999999
+294 259 -1
+297 259 1
+305 259 1
+308 259 2.9254359999999999
+309 259 1.2552490000000001
+276 260 -1.0000519999999999
+295 260 -1
+298 260 1
+305 260 1
+308 260 -1.797593
+309 260 0.94582429999999995
+277 261 -1.0000519999999999
+296 261 -1
+299 261 1
+305 261 1
+308 261 5.0331659999999996
+309 261 4.1397830000000004
+272 262 0.1700014
+291 262 -1
+273 263 0.82930199999999998
+292 263 -1
+274 264 0.20397290000000001
+293 264 -1
+297 265 0.0096798500000000003
+298 265 0.61671089999999995
+299 265 0.1605181
+300 265 0.99729840000000003
+319 265 -0.0096801700000000001
+320 265 -0.61673129999999998
+321 265 -0.16052340000000001
+322 265 -1
+301 266 1
+306 266 -0.09852872
+307 266 -0.34867100000000001
+310 266 -1
+311 266 -1
+312 266 -1
+303 267 1
+300 268 -0.99729840000000003
+306 268 1
+322 268 1
+307 269 1
+294 270 13.64601
+297 270 0.78690890000000002
+304 270 1
+306 270 12.716189999999999
+307 270 0.7693586
+319 270 -0.78693489999999999
+295 271 1.060897
+298 271 0.78690890000000002
+304 271 1
+306 271 -4.1795749999999998
+307 271 0.68099359999999998
+320 271 -0.78693489999999999
+296 272 0.003430968
+299 272 0.78690890000000002
+304 272 1
+306 272 20.19341
+307 272 2.2395320000000001
+321 272 -0.78693489999999999
+297 273 -0.16772329999999999
+298 273 -0.83154050000000002
+299 273 -0.00070311129999999996
+300 273 4.531911
+319 273 0.16772880000000001
+320 273 0.83156799999999997
+321 273 0.0007031346
+322 273 -4.5441880000000001
+323 274 -1
+330 274 -0.25288909999999998
+331 274 -0.41262900000000002
+302 275 -1
+303 275 -1
+324 275 1
+300 276 4.531911
+322 276 -4.5441880000000001
+330 276 1
+331 277 1
+297 278 -0.99996689999999999
+316 278 -1
+319 278 1
+327 278 1
+330 278 2.9235699999999998
+331 278 1.2552939999999999
+298 279 -0.99996689999999999
+317 279 -1
+320 279 1
+327 279 1
+330 279 -1.7964899999999999
+331 279 0.94585160000000001
+299 280 -0.99996689999999999
+318 280 -1
+321 280 1
+327 280 1
+330 280 5.029935
+331 280 4.1401399999999997
+294 281 0.16786100000000001
+313 281 -1
+295 282 0.83143909999999999
+314 282 -1
+296 283 0.20398559999999999
+315 283 -1
+319 284 0.0096473500000000007
+320 284 0.61499680000000001
+321 284 0.1606638
+322 284 1.012275
+341 284 -0.0096630710000000005
+342 284 -0.61599899999999996
+343 284 -0.1609257
+344 284 -1
+323 285 1
+328 285 -0.097740149999999998
+329 285 -0.348389
+332 285 -1
+333 285 -1
+334 285 -1
+325 286 1
+322 287 -1.012275
+328 287 1
+344 287 1
+329 288 1
+316 289 13.653370000000001
+319 289 0.78530800000000001
+326 289 1
+328 289 12.53604
+329 289 0.76861380000000001
+341 289 -0.7865877
+317 290 1.0618540000000001
+320 290 0.78530800000000001
+326 290 1
+328 290 -4.1203450000000004
+329 290 0.68034459999999997
+342 290 -0.7865877
+318 291 0.0034368480000000002
+321 291 0.78530800000000001
+326 291 1
+328 291 19.9072
+329 291 2.2374860000000001
+343 291 -0.7865877
+319 292 -0.16769600000000001
+320 292 -0.8298335
+321 292 -0.00084358209999999998
+322 292 4.5319130000000003
+341 292 0.16796929999999999
+342 292 0.83118579999999997
+343 292 0.00084495670000000003
+344 292 -4.4769569999999996
+345 293 -1
+352 293 -0.25422820000000002
+353 293 -0.41467850000000001
+324 294 -1
+325 294 -1
+346 294 1
+322 295 4.5319120000000002
+344 295 -4.4769569999999996
+352 295 1
+353 296 1
+319 297 -0.99837310000000001
+338 297 -1
+341 297 1
+349 297 1
+352 297 2.9258000000000002
+353 297 1.2548710000000001
+320 298 -0.99837310000000001
+339 298 -1
+342 298 1
+349 298 1
+352 298 -1.799474
+353 298 0.94529589999999997
+321 299 -0.99837310000000001
+340 299 -1
+343 299 1
+349 299 1
+352 299 5.032978
+353 299 4.1465319999999997
+316 300 0.16772880000000001
+335 300 -1
+317 301 0.83156799999999997
+336 301 -1
+318 302 0.20458699999999999
+337 302 -1
+341 303 0.0089580030000000008
+342 303 0.56239150000000004
+343 303 0.17143159999999999
+344 303 1.5349870000000001
+363 303 -0.0093684010000000002
+364 303 -0.58815669999999998
+365 303 -0.17928549999999999
+366 303 -1
+345 304 1
+350 304 -0.076424569999999997
+351 304 -0.33630700000000002
+354 304 -1
+355 304 -1
+356 304 -1
+347 305 1
+344 306 -1.5349870000000001
+350 306 1
+366 306 1
+351 307 1
+338 308 13.9277
+341 308 0.74278120000000003
+348 308 1
+350 308 7.7124139999999999
+351 308 0.73754050000000004
+363 308 -0.77681060000000002
+339 309 1.0977920000000001
+342 309 0.74278120000000003
+348 309 1
+350 309 -2.5345339999999998
+351 309 0.65320800000000001
+364 309 -0.77681060000000002
+340 310 0.00366104
+343 310 0.74278120000000003
+348 310 1
+350 310 12.244490000000001
+351 310 2.151386
+365 310 -0.77681060000000002
+341 311 -0.1672642
+342 311 -0.77757829999999994
+343 311 -0.01135093
+344 311 3.9419710000000001
+363 311 0.1749272
+364 311 0.81320190000000003
+365 311 0.01187095
+366 311 -2.568082
+367 312 -1
+374 312 -0.31132270000000001
+375 312 -0.45572679999999999
+346 313 -1
+347 313 -1
+368 313 1
+344 314 3.9419710000000001
+366 314 -2.568082
+374 314 1
+375 315 1
+341 316 -0.95619350000000003
+360 316 -1
+363 316 1
+371 316 1
+374 316 3.149454
+375 316 1.212998
+342 317 -0.95619350000000003
+361 317 -1
+364 317 1
+371 317 1
+374 317 -1.985919
+375 317 0.9070684
+343 318 -0.95619350000000003
+362 318 -1
+365 318 1
+371 318 1
+374 318 5.3936869999999999
+375 318 4.2274630000000002
+338 319 0.16796929999999999
+357 319 -1
+339 320 0.83118579999999997
+358 320 -1
+340 321 0.2307969
+359 321 -1
+363 322 0.0049560029999999996
+364 322 0.2092511
+365 322 0.4341566
+366 322 6.177384
+385 322 -0.0056864039999999999
+386 322 -0.24008989999999999
+387 322 -0.49814130000000001
+388 322 -1
+367 323 1
+372 323 -0.051899590000000002
+373 323 -0.22819929999999999
+376 323 -1
+377 323 -1
+378 323 -1
+369 324 1
+366 325 -6.177384
+372 325 1
+388 325 1
+373 326 1
+360 327 22.88466
+363 327 0.64836369999999999
+370 327 1
+372 327 1.04345
+373 327 0.42175859999999998
+385 327 -0.74391759999999996
+361 328 2.5197029999999998
+364 328 0.64836369999999999
+370 328 1
+372 328 -0.3414664
+373 328 0.3798898
+386 328 -0.74391759999999996
+362 329 0.017727920000000001
+365 329 0.64836369999999999
+370 329 1
+372 329 1.6460520000000001
+373 329 1.3054760000000001
+387 329 -0.74391759999999996
+360 330 0.1749272
+379 330 -1
+361 331 0.81320190000000003
+380 331 -1
+362 332 0.66961899999999996
+381 332 -1
+87 333 6.3180579999999997
+93 333 1.008121
+88 334 2.1016520000000001
+94 334 0.98324999999999996
+89 335 10.216340000000001
+95 335 0.97112200000000004
+90 336 4.7715329999999998
+96 336 1.0168969999999999
+91 337 1.5445530000000001
+97 337 0.96515200000000001
+92 338 7.4032580000000001
+98 338 0.93991979999999997
+99 339 276.76479999999998
+105 339 0.88770669999999996
+100 340 192.19040000000001
+106 340 1.2620629999999999
+101 341 465.29739999999998
+107 341 0.8373005
+102 342 402.63529999999997
+108 342 0.93272339999999998
+103 343 243.95160000000001
+109 343 1.157006
+104 344 694.42570000000001
+110 344 0.90252429999999995
+111 345 2.1471689999999999
+117 345 0.73310410000000004
+112 346 1.830354
+118 346 0.77070689999999997
+113 347 5.4194959999999996
+119 347 0.91067969999999998
+114 348 1.5934600000000001
+120 348 0.44472830000000002
+115 349 1.5193589999999999
+121 349 0.52296010000000004
+116 350 5.9272710000000002
+122 350 0.81417070000000002
+123 351 8.6013230000000007
+129 351 0.58171510000000004
+124 352 6.1974850000000004
+130 352 0.53220719999999999
+125 353 37.67033
+131 353 1.1683300000000001
+126 354 10.955349999999999
+132 354 0.74939929999999999
+127 355 8.2864269999999998
+133 355 0.71973830000000005
+128 356 35.092930000000003
+134 356 1.100849
+135 357 0.4338919
+138 357 2.2797130000000001
+136 358 0.1137572
+139 358 0.60698209999999997
+137 359 0.4035473
+140 359 0.0080049890000000005
+141 360 1.1577040000000001
+144 360 4.0422279999999997
+142 361 0.41932589999999997
+145 361 2.449611
+143 362 0.10246470000000001
+146 362 0.36475180000000001
+151 363 172.5745
+154 363 14.91761
+152 364 161.58449999999999
+155 364 12.0938
+153 365 145.31450000000001
+156 365 5.7400960000000003
+157 366 0.0045018890000000002
+158 366 0.95263589999999998
+159 366 -1
+158 367 0.94488159999999999
+163 367 19.882059999999999
+164 367 15.998699999999999
+165 367 7.7694989999999997
+159 368 1.00814
+163 368 98.828980000000001
+164 368 147.5558
+165 368 130.84370000000001
+160 369 1
+163 369 1.8011980000000001
+161 370 1
+164 370 2.196221
+162 371 1
+165 371 2.0607380000000002
+163 372 19.882059999999999
+166 372 0.9740453
+164 373 15.998699999999999
+167 373 0.93133779999999999
+165 374 7.7694989999999997
+168 374 0.82771399999999995
+169 375 -1
+172 375 -1
+175 375 0.056357909999999997
+176 375 0.056357909999999997
+177 375 0.056357909999999997
+170 376 -1
+173 376 -1
+175 376 0.73959730000000001
+176 376 0.73959730000000001
+177 376 0.73959730000000001
+171 377 -1
+174 377 -1
+175 377 0.2040448
+176 377 0.2040448
+177 377 0.2040448
+172 378 1
+175 378 -1
+173 379 1
+176 379 -1
+174 380 1
+177 380 -1
+175 381 1
+178 381 1
+176 382 1
+179 382 1
+177 383 1
+180 383 1
+102 384 -19.453890000000001
+418 384 1
+424 384 -0.09530421
+103 385 -22.090309999999999
+419 385 1
+424 385 -0.088197620000000004
+104 386 -49.563589999999998
+420 386 1
+424 386 -0.00010690420000000001
+421 387 179.7345
+422 387 -2.5957400000000002
+422 388 1
+423 388 -0.09621652
+102 389 -1
+103 389 -1
+104 389 -1
+423 389 0.09621652
+424 389 -0.0088937280000000001
+126 390 0.93082790000000004
+127 390 0.93082790000000004
+128 390 0.93082790000000004
+425 390 -1.138352
+436 390 0.095341780000000001
+126 391 0.81769789999999998
+426 391 -0.55083519999999997
+436 391 0.04613478
+127 392 0.81769789999999998
+427 392 -0.4489223
+436 392 0.037599149999999998
+128 393 6.8068650000000002
+428 393 -0.0020188419999999999
+436 393 0.0001690866
+429 394 -0.60313589999999995
+430 394 -1.1914260000000001
+431 394 -0.2090101
+432 394 -0.2323664
+126 395 -1.5881989999999999
+430 395 1
+436 395 -0.089606729999999996
+127 396 -1.7894779999999999
+431 396 1
+436 396 -0.082283250000000002
+128 397 -4.012804
+432 397 1
+436 397 -9.9680419999999997e-05
+433 398 1.186874
+435 398 -0.87134319999999998
+434 399 0.99186010000000002
+435 399 -0.73414950000000001
+126 400 -1
+127 400 -1
+128 400 -1
+435 400 0.89782490000000004
+436 400 -0.1024269
+185 401 263.30250000000001
+188 401 16.710229999999999
+186 402 252.3125
+189 402 15.091379999999999
+187 403 236.04249999999999
+190 403 11.440289999999999
+191 404 0.0068429329999999998
+192 404 0.96227439999999997
+193 404 -1
+192 405 0.95486020000000005
+197 405 35.042119999999997
+198 405 28.167190000000002
+199 405 13.66854
+193 406 1.0077050000000001
+197 406 85.846760000000003
+198 406 144.16210000000001
+199 406 130.40539999999999
+194 407 1
+197 407 1.6589050000000001
+195 408 1
+198 408 2.1064970000000001
+196 409 1
+199 409 2.000909
+197 410 35.042119999999997
+200 410 1
+198 411 28.167190000000002
+201 411 0.97782690000000005
+199 412 13.66854
+202 412 0.91623940000000004
+203 413 -1
+206 413 -1
+209 413 0.0034351899999999999
+210 413 0.0034351899999999999
+211 413 0.0034351899999999999
+204 414 -1
+207 414 -1
+209 414 0.043016970000000002
+210 414 0.043016970000000002
+211 414 0.043016970000000002
+205 415 -1
+208 415 -1
+209 415 0.95354779999999995
+210 415 0.95354779999999995
+211 415 0.95354779999999995
+206 416 1
+209 416 -1
+207 417 1
+210 417 -1
+208 418 1
+211 418 -1
+209 419 1
+212 419 1
+210 420 1
+213 420 1
+211 421 1
+214 421 1
+90 422 -0.047613129999999997
+461 422 1
+467 422 -2.3334699999999999e-05
+91 423 -0.057464349999999997
+462 423 1
+467 423 -0.00035266559999999999
+92 424 -0.12956039999999999
+463 424 1
+467 424 -0.017625419999999999
+464 425 270.46249999999998
+465 425 -2.8000669999999999
+465 426 1
+466 426 -1.6856930000000001
+90 427 -1
+91 427 -1
+92 427 -1
+466 427 1.6856930000000001
+467 427 -0.1426674
+114 428 0.12149740000000001
+115 428 0.12149740000000001
+116 428 0.12149740000000001
+468 428 -1.138352
+479 428 0.021230519999999999
+114 429 0.60555749999999997
+469 429 -0.019490179999999999
+479 429 0.00036349629999999998
+115 430 0.3357927
+470 430 -0.13533829999999999
+479 430 0.0025240900000000001
+116 431 0.1067309
+471 431 -0.95354779999999995
+479 431 0.017783879999999998
+472 432 -0.90759219999999996
+473 432 -5.7118219999999997
+474 432 -0.93568410000000002
+475 432 -1.0346550000000001
+114 433 -0.043240929999999997
+473 433 1
+479 433 -2.5956110000000001e-05
+115 434 -0.052174909999999998
+474 434 1
+479 434 -0.00039218899999999998
+116 435 -0.1176314
+475 435 1
+479 435 -0.019600159999999998
+476 436 5.3140780000000003
+478 436 -1.002184
+477 437 0.34483720000000001
+478 437 -0.26478620000000003
+114 438 -1
+115 438 -1
+116 438 -1
+478 438 1.7669710000000001
+479 438 -0.1747406
+438 439 99.149730000000005
+444 439 -1
+447 439 -3.311398e-05
+439 440 172.6396
+445 440 -1
+448 440 -4.1108120000000002e-05
+440 441 356.63979999999998
+446 441 -1
+449 441 -8.4587179999999994e-05
+441 442 200.0008
+444 442 2.5
+447 442 3.311398e-05
+442 443 349.00330000000002
+445 443 2.5
+448 443 4.1108120000000002e-05
+443 444 722.06780000000003
+446 444 2.5
+449 444 8.4587179999999994e-05
+444 445 1
+453 445 -1.4485650000000001e-06
+445 446 1
+453 446 -0.0005113292
+446 447 1
+453 447 -0.95438869999999998
+447 448 1.0050250000000001
+454 448 -0.0034351899999999999
+448 449 1.002874
+454 449 -0.043016970000000002
+449 450 1.001387
+454 450 -0.95354779999999995
+450 451 1
+453 451 -4.9455600000000001e-05
+451 452 1
+453 452 -0.0021775570000000001
+452 453 1
+453 453 -0.042871529999999998
+453 454 1
+455 454 -1
+466 454 1.5
+478 454 0.5
+454 455 1
+456 455 -316220
+459 455 -12132.58
+460 455 -1
+466 455 -20451.810000000001
+477 455 9152.7510000000002
+455 456 9.1463570000000001
+457 456 0.0037734919999999998
+456 457 2248.7060000000001
+457 457 -0.12505330000000001
+457 458 0.067588380000000003
+458 458 65.087119999999999
+466 458 -0.18859039999999999
+458 459 -9152.7510000000002
+460 459 0.75439429999999996
+476 459 -9152.7510000000002
+477 459 -6904.7830000000004
+459 460 1
+466 460 0.18569289999999999
+478 460 -0.5
+460 461 0.00019167939999999999
+466 461 2.6684519999999998
+478 461 0.88948400000000005
+266 462 0.52397099999999996
+269 462 2.5902729999999998
+267 463 0.1209036
+270 463 1
+268 464 0.36607729999999999
+271 464 0.018323329999999999
+288 465 0.53070830000000002
+291 465 2.6120320000000001
+289 466 0.12143809999999999
+292 466 1
+290 467 0.36327480000000001
+293 467 0.019398479999999999
+310 468 0.53114850000000002
+313 468 2.6134469999999999
+311 469 0.1214731
+314 469 1
+312 470 0.36309170000000002
+315 470 0.01947045
+332 471 0.53131620000000002
+335 471 2.6139860000000001
+333 472 0.12148639999999999
+336 472 1
+334 473 0.36302190000000001
+337 473 0.01949793
+354 474 0.53753340000000005
+357 474 2.63388
+355 475 0.12197959999999999
+358 475 1
+356 476 0.36043579999999997
+359 476 0.020538460000000001
+376 477 0.71092829999999996
+379 477 3.1304669999999999
+377 478 0.13573579999999999
+380 478 1
+378 479 0.28830909999999998
+381 479 0.071489880000000006
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/data/west0479.mtx	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1912 @@
+%%MatrixMarket matrix coordinate real general
+479 479 1910
+25 1  1.0000000000000e+00
+31 1 -3.7648130000000e-02
+87 1 -3.4423960000000e-01
+26 2  1.0000000000000e+00
+31 2 -2.4522620000000e-02
+88 2 -3.7370860000000e-01
+27 3  1.0000000000000e+00
+31 3 -3.6613040000000e-02
+89 3 -8.3693790000000e-01
+28 4  1.3000000000000e+02
+29 4 -2.4337670000000e+00
+29 5  1.0000000000000e+00
+30 5 -1.6140910000000e+00
+30 6  1.6140910000000e+00
+31 6 -2.1873210000000e-01
+87 6 -1.0000000000000e+00
+88 6 -1.0000000000000e+00
+89 6 -1.0000000000000e+00
+32 7 -1.1383520000000e+00
+43 7  3.6694280000000e-02
+111 7  9.9316360000000e-02
+112 7  9.9316360000000e-02
+113 7  9.9316360000000e-02
+33 8 -5.0000000000000e-01
+43 8  1.6117290000000e-02
+111 8  8.7245760000000e-02
+34 9 -3.6119180000000e-01
+43 9  1.1642860000000e-02
+112 9  1.0504150000000e-01
+35 10 -3.2188760000000e-01
+43 10  1.0375910000000e-02
+113 10  1.4041660000000e-01
+36 11 -4.3624160000000e-01
+37 11 -7.6804250000000e-01
+38 11 -1.4302790000000e-01
+39 11 -1.5938860000000e-01
+37 12  1.0000000000000e+00
+43 12 -4.8560820000000e-02
+111 12 -2.6286840000000e-01
+38 13  1.0000000000000e+00
+43 13 -3.0925950000000e-02
+112 13 -2.7901280000000e-01
+39 14  1.0000000000000e+00
+43 14 -4.6123590000000e-02
+113 14 -6.2418820000000e-01
+40 15  5.2824360000000e+00
+42 15 -6.1239210000000e-01
+41 16  2.8868220000000e-01
+42 16 -2.1638150000000e-01
+42 17  1.3287740000000e+00
+43 17 -3.6946860000000e-01
+111 17 -1.0000000000000e+00
+112 17 -1.0000000000000e+00
+113 17 -1.0000000000000e+00
+2 18  4.8176470000000e+01
+8 18 -1.0000000000000e+00
+11 18 -3.3474840000000e-05
+3 19  8.3500000000000e+01
+9 19 -1.0000000000000e+00
+12 19 -4.1365390000000e-05
+4 20  1.7194120000000e+02
+10 20 -1.0000000000000e+00
+13 20 -8.4843450000000e-05
+5 21  9.6651380000000e+01
+8 21  2.5000000000000e+00
+11 21  3.3474840000000e-05
+6 22  1.6827060000000e+02
+9 22  2.5000000000000e+00
+12 22  4.1365390000000e-05
+7 23  3.4758720000000e+02
+10 23  2.5000000000000e+00
+13 23  8.4843450000000e-05
+8 24  1.0000000000000e+00
+17 24 -1.1069670000000e-01
+27 24  1.6052320000000e+00
+9 25  1.0000000000000e+00
+17 25 -8.9808520000000e-02
+10 26  1.0000000000000e+00
+17 26 -1.5173690000000e-01
+11 27  1.0104550000000e+00
+18 27 -5.0000000000000e-01
+12 28  1.0059780000000e+00
+18 28 -3.0000000000000e-01
+13 29  1.0028850000000e+00
+18 29 -2.0000000000000e-01
+14 30  1.0000000000000e+00
+17 30 -1.8118550000000e-01
+15 31  1.0000000000000e+00
+17 31 -2.4002390000000e-01
+16 32  1.0000000000000e+00
+17 32 -2.2654840000000e-01
+17 33  1.0000000000000e+00
+19 33 -1.0000000000000e+00
+30 33  1.5000000000000e+00
+42 33  5.0000000000000e-01
+18 34  1.0000000000000e+00
+20 34 -3.1622000000000e+05
+23 34 -1.2323690000000e+04
+24 34 -1.0000000000000e+00
+30 34 -3.5226800000000e+04
+41 34  1.8449020000000e+04
+19 35  5.2983390000000e+00
+21 35  2.4526870000000e-03
+20 36  1.0808590000000e+03
+21 36 -2.0502150000000e-01
+21 37  1.4419200000000e-01
+22 37  6.3059860000000e+01
+30 37 -1.1592990000000e-01
+22 38 -1.8449020000000e+04
+24 38  8.4533390000000e-01
+40 38 -1.8449020000000e+04
+41 38 -1.5595580000000e+04
+23 39  1.0000000000000e+00
+30 39  2.0204930000000e-01
+42 39 -8.8547100000000e-01
+24 40  1.0002340000000e-04
+30 40  2.4483390000000e+00
+42 40  8.1611300000000e-01
+68 41  1.0000000000000e+00
+74 41 -2.2786690000000e-04
+99 41 -2.6243950000000e-01
+69 42  1.0000000000000e+00
+74 42 -4.1887630000000e-04
+100 42 -3.2161960000000e-01
+70 43  1.0000000000000e+00
+74 43 -1.5769330000000e-03
+101 43 -7.2647610000000e-01
+71 44  3.0000000000000e+02
+72 44 -2.8518910000000e+00
+72 45  1.0000000000000e+00
+73 45 -2.8701590000000e-01
+73 46  2.8701590000000e-01
+74 46 -4.3413220000000e-03
+99 46 -1.0000000000000e+00
+100 46 -1.0000000000000e+00
+101 46 -1.0000000000000e+00
+75 47 -1.1383520000000e+00
+86 47  4.2002860000000e-02
+123 47  9.4148060000000e-01
+124 47  9.4148060000000e-01
+125 47  9.4148060000000e-01
+76 48 -3.2188760000000e-01
+86 48  1.1877000000000e-02
+123 48  1.3310950000000e+00
+77 49 -3.6119180000000e-01
+86 49  1.3327240000000e-02
+124 49  9.9575290000000e-01
+78 50 -5.0000000000000e-01
+86 50  1.8448980000000e-02
+125 50  8.2705600000000e-01
+79 51 -1.0000000000000e+00
+80 51 -1.9240000000000e+01
+81 51 -3.8030000000000e+00
+82 51 -9.4810000000000e+00
+80 52  1.0000000000000e+00
+86 52 -8.8757840000000e-04
+123 52 -9.9473920000000e-02
+81 53  1.0000000000000e+00
+86 53 -1.3313680000000e-03
+124 53 -9.9473920000000e-02
+82 54  1.0000000000000e+00
+86 54 -2.2189460000000e-03
+125 54 -9.9473920000000e-02
+83 55  1.1776130000000e+00
+85 55 -3.1089630000000e+00
+84 56  9.9194250000000e-01
+85 56 -2.6400560000000e+00
+85 57  3.1921120000000e+00
+86 57 -4.4613630000000e-02
+123 57 -1.0000000000000e+00
+124 57 -1.0000000000000e+00
+125 57 -1.0000000000000e+00
+45 58  1.0986880000000e+02
+51 58 -1.0000000000000e+00
+54 58 -3.3081100000000e-05
+46 59  1.9138460000000e+02
+52 59 -1.0000000000000e+00
+55 59 -4.1084670000000e-05
+47 60  3.9547960000000e+02
+53 60 -1.0000000000000e+00
+56 60 -8.4563830000000e-05
+48 61  2.2173390000000e+02
+51 61  2.5000000000000e+00
+54 61  3.3081100000000e-05
+49 62  3.8700920000000e+02
+52 62  2.5000000000000e+00
+55 62  4.1084670000000e-05
+50 63  8.0081650000000e+02
+53 63  2.5000000000000e+00
+56 63  8.4563830000000e-05
+51 64  1.0000000000000e+00
+60 64 -9.1702290000000e-03
+52 65  1.0000000000000e+00
+60 65 -4.6441100000000e-02
+53 66  1.0000000000000e+00
+60 66 -4.8999190000000e-01
+54 67  1.0045300000000e+00
+61 67 -2.0000000000000e-01
+55 68  1.0025910000000e+00
+61 68 -3.0000000000000e-01
+56 69  1.0012500000000e+00
+61 69 -5.0000000000000e-01
+57 70  1.0000000000000e+00
+60 70 -3.7500530000000e-02
+58 71  1.0000000000000e+00
+60 71 -1.2414300000000e-01
+59 72  1.0000000000000e+00
+60 72 -2.9275320000000e-01
+60 73  1.0000000000000e+00
+62 73 -1.0000000000000e+00
+73 73  1.8537330000000e-01
+85 73  6.1791090000000e-02
+61 74  1.0000000000000e+00
+63 74 -3.1622000000000e+05
+66 74 -1.6364190000000e+04
+67 74 -1.0000000000000e+00
+73 74 -4.6967820000000e+03
+84 74  1.3185400000000e+02
+62 75  2.2129130000000e+01
+64 75  9.5375260000000e-01
+63 76  2.4942900000000e+03
+64 76 -1.0215870000000e+00
+64 77  8.8782810000000e-01
+65 77  1.0400420000000e+00
+73 77 -2.6400560000000e+00
+65 78 -1.3185400000000e+02
+67 78  8.0574700000000e-03
+83 78 -1.3185400000000e+02
+84 78 -1.0624090000000e+00
+66 79  1.0000000000000e+00
+73 79  1.0164260000000e-01
+85 79 -6.1791090000000e-02
+67 80  7.6452570000000e-03
+73 80  2.3098950000000e+01
+85 80  7.6996490000000e+00
+31 81  1.0000000000000e+00
+244 81  1.0000000000000e+00
+43 82  1.0000000000000e+00
+1 83  1.0000000000000e+00
+17 83 -3.8502310000000e+00
+18 83 -8.4599350000000e-05
+31 83  2.0159100000000e+00
+35 83  1.0000000000000e+00
+43 83  1.5961710000000e+00
+243 83 -7.8975120000000e-01
+74 84  1.0000000000000e+00
+388 84  8.8175620000000e-01
+86 85  1.0000000000000e+00
+44 86  1.0000000000000e+00
+60 86 -2.7937600000000e+00
+61 86 -8.4458230000000e-05
+74 86  2.0156650000000e+00
+78 86  1.0000000000000e+00
+86 86  1.5939940000000e+00
+384 86  0.0000000000000e+00
+387 86 -9.6191500000000e-01
+385 87  2.4246690000000e-03
+386 87  3.0362780000000e-02
+387 87  6.7304510000000e-01
+388 87  1.4593600000000e+00
+96 88  1.6896610000000e-02
+97 88  3.4848030000000e-02
+98 88 -6.0080180000000e-02
+120 88 -5.5527170000000e-01
+121 88 -4.7703980000000e-01
+122 88 -1.8582930000000e-01
+141 88 -1.0000000000000e+00
+142 88 -1.0000000000000e+00
+143 88 -1.0000000000000e+00
+185 88 -5.5188570000000e+01
+186 88 -9.5676860000000e+01
+187 88 -2.1583770000000e+02
+389 88  1.0000000000000e+00
+438 88  1.0000000000000e+00
+439 88  1.0000000000000e+00
+440 88  1.0000000000000e+00
+441 88  1.0000000000000e+00
+442 88  1.0000000000000e+00
+443 88  1.0000000000000e+00
+450 88 -1.8907560000000e-03
+451 88 -1.5311400000000e-03
+452 88 -1.0137260000000e-03
+455 88  2.5000000000000e+00
+456 88  2.6063700000000e+01
+458 88  1.0000000000000e+00
+459 88 -1.5000000000000e+00
+461 88 -9.6031810000000e+00
+462 88 -9.4541850000000e+00
+463 88 -9.4376810000000e+00
+464 88 -4.8295720000000e+01
+472 88  9.0759220000000e-01
+473 88 -4.3759670000000e+00
+474 88 -8.9979920000000e+00
+475 88 -8.8819580000000e+00
+476 88  1.0000000000000e+00
+182 89  1.0000000000000e+00
+183 89  1.0000000000000e+00
+184 89  1.0000000000000e+00
+391 89  1.0000000000000e+00
+455 89 -1.0000000000000e+00
+456 89 -2.6063700000000e+01
+458 89 -1.0000000000000e+00
+468 89  1.0000000000000e+00
+388 90 -1.4593600000000e+00
+467 90  1.0000000000000e+00
+479 91  1.0000000000000e+00
+203 92 -1.0000000000000e+00
+204 92 -1.0000000000000e+00
+205 92 -1.0000000000000e+00
+209 92  1.0000000000000e+00
+210 92  1.0000000000000e+00
+211 92  1.0000000000000e+00
+382 92  5.6953100000000e+01
+385 92  7.0583250000000e-01
+437 92  1.0000000000000e+00
+453 92 -6.4913720000000e-01
+454 92 -3.2948410000000e-05
+467 92  5.3807480000000e-01
+469 92  1.0000000000000e+00
+479 92  8.2471120000000e-02
+203 93 -1.0000000000000e+00
+204 93 -1.0000000000000e+00
+205 93 -1.0000000000000e+00
+209 93  1.0000000000000e+00
+210 93  1.0000000000000e+00
+211 93  1.0000000000000e+00
+383 93  1.1583840000000e+01
+386 93  7.0583250000000e-01
+437 93  1.0000000000000e+00
+453 93 -1.0215420000000e+00
+454 93 -4.0990330000000e-05
+467 93 -3.6302480000000e-01
+470 93  1.0000000000000e+00
+479 93  6.9522610000000e-02
+203 94 -1.0000000000000e+00
+204 94 -1.0000000000000e+00
+205 94 -1.0000000000000e+00
+209 94  1.0000000000000e+00
+210 94  1.0000000000000e+00
+211 94  1.0000000000000e+00
+384 94  3.2096310000000e-01
+387 94  7.0583250000000e-01
+437 94  1.0000000000000e+00
+453 94 -2.0490070000000e+00
+454 94 -8.4470030000000e-05
+467 94  9.1353620000000e-01
+471 94  1.0000000000000e+00
+479 94  8.3976380000000e-01
+241 95  5.5083520000000e-01
+242 95  4.4892230000000e-01
+243 95  2.4252030000000e-04
+244 95  4.0528330000000e-01
+108 96 -6.7276620000000e-02
+109 96 -1.5700610000000e-01
+110 96 -9.7475700000000e-02
+132 96 -2.5060070000000e-01
+133 96 -2.8026170000000e-01
+134 96  1.0084910000000e-01
+245 96 -1.0000000000000e+00
+395 96  1.0000000000000e+00
+396 96  1.0000000000000e+00
+397 96  1.0000000000000e+00
+398 96  1.0000000000000e+00
+399 96  1.0000000000000e+00
+400 96  1.0000000000000e+00
+407 96 -2.8636020000000e-03
+408 96 -2.3162590000000e-03
+409 96 -1.5308900000000e-03
+412 96  2.5000000000000e+00
+413 96  1.1587800000000e+01
+415 96  1.0000000000000e+00
+416 96 -1.1012240000000e+00
+418 96 -1.3644320000000e+00
+419 96 -1.2188210000000e+00
+420 96 -1.2108590000000e+00
+421 96 -3.4621050000000e+01
+429 96  6.0313590000000e-01
+430 96 -5.9963840000000e-01
+431 96 -1.4033920000000e+00
+432 96 -1.3703860000000e+00
+433 96  1.0000000000000e+00
+246 97  1.0000000000000e+00
+412 97 -1.0000000000000e+00
+413 97 -1.1587800000000e+01
+415 97 -1.0000000000000e+00
+425 97  1.0000000000000e+00
+244 98 -4.0528330000000e-01
+424 98  1.0000000000000e+00
+436 99  1.0000000000000e+00
+160 100 -8.5938400000000e-01
+161 100 -7.7333900000000e-01
+162 100 -7.9517400000000e-01
+238 100 -1.0000000000000e+00
+241 100  1.0000000000000e+00
+394 100  1.0000000000000e+00
+410 100 -1.6236590000000e+00
+411 100 -3.3032780000000e-05
+424 100  3.5720350000000e+00
+426 100  1.0000000000000e+00
+436 100  9.2435320000000e-01
+160 101 -1.1718210000000e+00
+161 101 -1.2773520000000e+00
+162 101 -1.2505080000000e+00
+239 101 -1.0000000000000e+00
+242 101  1.0000000000000e+00
+394 101  1.0000000000000e+00
+410 101 -2.4602890000000e+00
+411 101 -4.1050810000000e-05
+424 101 -2.1785330000000e+00
+427 101  1.0000000000000e+00
+436 101  6.5098420000000e-01
+160 102 -2.3280470000000e+00
+161 102 -2.4161550000000e+00
+162 102 -2.5121660000000e+00
+240 102 -1.0000000000000e+00
+243 102  1.0000000000000e+00
+394 102  1.0000000000000e+00
+410 102 -4.7536200000000e+00
+411 102 -8.4530500000000e-05
+424 102  6.1671400000000e+00
+428 102  1.0000000000000e+00
+436 102  3.3966910000000e+00
+241 103  4.3736570000000e-02
+242 103  5.7396460000000e-01
+243 103  1.5834900000000e-01
+244 103  1.8781250000000e-01
+253 103 -4.4344130000000e-02
+254 103 -5.8193780000000e-01
+255 103 -1.6054870000000e-01
+256 103 -1.0000000000000e+00
+135 104 -1.0000000000000e+00
+136 104 -1.0000000000000e+00
+137 104 -1.0000000000000e+00
+151 104 -6.2680900000000e+01
+152 104 -1.2389000000000e+02
+153 104 -4.6435550000000e+02
+245 104  1.0000000000000e+00
+248 104 -5.1646550000000e-02
+249 104 -3.2417620000000e-01
+148 105  1.0000000000000e+00
+149 105  1.0000000000000e+00
+150 105  1.0000000000000e+00
+247 105  1.0000000000000e+00
+244 106 -1.8781250000000e-01
+248 106  1.0000000000000e+00
+256 106  1.0000000000000e+00
+249 107  1.0000000000000e+00
+147 108  1.0000000000000e+00
+169 108 -1.0000000000000e+00
+170 108 -1.0000000000000e+00
+171 108 -1.0000000000000e+00
+175 108  1.0000000000000e+00
+176 108  1.0000000000000e+00
+177 108  1.0000000000000e+00
+238 108  9.7738750000000e+00
+241 108  7.7605020000000e-01
+248 108  7.2528310000000e+00
+249 108  7.8041000000000e-01
+253 108 -7.8683060000000e-01
+147 109  1.0000000000000e+00
+169 109 -1.0000000000000e+00
+170 109 -1.0000000000000e+00
+171 109 -1.0000000000000e+00
+175 109  1.0000000000000e+00
+176 109  1.0000000000000e+00
+177 109  1.0000000000000e+00
+239 109  6.0698210000000e-01
+242 109  7.7605020000000e-01
+248 109 -2.3895080000000e+00
+249 109  6.8493980000000e-01
+254 109 -7.8683060000000e-01
+147 110  1.0000000000000e+00
+169 110 -1.0000000000000e+00
+170 110 -1.0000000000000e+00
+171 110 -1.0000000000000e+00
+175 110  1.0000000000000e+00
+176 110  1.0000000000000e+00
+177 110  1.0000000000000e+00
+240 110  1.1885640000000e-03
+243 110  7.7605020000000e-01
+248 110  1.1558830000000e+01
+249 110  2.2026440000000e+00
+255 110 -7.8683060000000e-01
+363 111 -1.7051480000000e-01
+364 111 -4.3429630000000e-01
+365 111 -2.6674210000000e-01
+366 111 -2.6093020000000e+00
+385 111  1.9564470000000e-01
+386 111  4.9830160000000e-01
+387 111  3.0605370000000e-01
+388 111  4.2239600000000e-01
+215 112  1.0000000000000e+00
+216 112  1.0000000000000e+00
+217 112  1.0000000000000e+00
+218 112  1.0000000000000e+00
+219 112  1.0000000000000e+00
+220 112  1.0000000000000e+00
+227 112 -1.8907560000000e-03
+228 112 -1.5311400000000e-03
+229 112 -1.0137260000000e-03
+232 112  2.5000000000000e+00
+233 112  1.6672410000000e+01
+235 112  1.0000000000000e+00
+236 112 -1.5000000000000e+00
+389 112 -1.0000000000000e+00
+392 112 -4.6212130000000e-01
+393 112 -1.2349620000000e-01
+232 113 -1.0000000000000e+00
+233 113 -1.6672410000000e+01
+235 113 -1.0000000000000e+00
+368 113 -1.0000000000000e+00
+369 113 -1.0000000000000e+00
+390 113  1.0000000000000e+00
+366 114  2.6093020000000e+00
+388 114 -4.2239600000000e-01
+392 114  1.0000000000000e+00
+393 115  1.0000000000000e+00
+181 116  1.0000000000000e+00
+194 116 -5.8697620000000e-01
+195 116 -5.0651550000000e-01
+196 116 -5.1399180000000e-01
+230 116 -1.0366850000000e+00
+231 116 -3.2948410000000e-05
+360 116  0.0000000000000e+00
+363 116 -8.7155310000000e-01
+382 116 -1.0000000000000e+00
+385 116  1.0000000000000e+00
+392 116  2.6399800000000e+00
+393 116  5.5742070000000e-01
+181 117  1.0000000000000e+00
+194 117 -8.0016370000000e-01
+195 117 -8.3640900000000e-01
+196 117 -8.0810260000000e-01
+230 117 -1.6376950000000e+00
+231 117 -4.0990330000000e-05
+361 117  0.0000000000000e+00
+364 117 -8.7155310000000e-01
+383 117 -1.0000000000000e+00
+386 117  1.0000000000000e+00
+392 117 -1.7736780000000e+00
+393 117  4.0754220000000e-01
+181 118  1.0000000000000e+00
+194 118 -1.5893890000000e+00
+195 118 -1.5818110000000e+00
+196 118 -1.6231180000000e+00
+230 118 -3.2056860000000e+00
+231 118 -8.4470030000000e-05
+362 118  0.0000000000000e+00
+365 118 -8.7155310000000e-01
+384 118 -1.0000000000000e+00
+387 118  1.0000000000000e+00
+392 118  4.4676090000000e+00
+393 118  2.2475290000000e+00
+93 119 -1.0000000000000e+00
+96 119 -1.0000000000000e+00
+248 119 -4.0421560000000e-01
+262 119 -1.8187770000000e-01
+284 119 -1.5634550000000e-01
+306 119 -1.5456990000000e-01
+328 119 -1.5217780000000e-01
+350 119 -9.1905800000000e-02
+372 119 -7.8705370000000e-03
+94 120 -1.0000000000000e+00
+97 120 -1.0000000000000e+00
+248 120 -1.8091710000000e+00
+262 120 -3.1896550000000e+00
+284 120 -3.3490190000000e+00
+306 120 -3.3586440000000e+00
+328 120 -3.3085850000000e+00
+350 120 -1.9678700000000e+00
+372 120 -1.1333560000000e-01
+95 121 -1.0000000000000e+00
+98 121 -1.0000000000000e+00
+248 121 -2.4566020000000e+00
+262 121 -4.1011280000000e+00
+284 121 -4.2908920000000e+00
+306 121 -4.3026030000000e+00
+328 121 -4.2541470000000e+00
+350 121 -2.9523890000000e+00
+372 121 -1.1573650000000e+00
+93 122 -8.1214960000000e-03
+96 122 -1.6896610000000e-02
+248 122 -4.5387600000000e-03
+262 122 -2.1705200000000e-03
+284 122 -1.8740690000000e-03
+306 122 -1.8533180000000e-03
+328 122 -1.8248370000000e-03
+350 122 -1.1065610000000e-03
+372 122 -1.0544940000000e-04
+94 123 -1.6749990000000e-02
+97 123 -3.4848030000000e-02
+248 123 -4.1896920000000e-02
+262 123 -7.8506680000000e-02
+284 123 -8.2793510000000e-02
+306 123 -8.3055320000000e-02
+328 123 -8.1826380000000e-02
+350 123 -4.8866050000000e-02
+372 123 -3.1317320000000e-03
+95 124 -2.8878030000000e-02
+98 124 -6.0080180000000e-02
+248 124 -9.8082240000000e-02
+262 124 -1.7402810000000e-01
+284 124 -1.8288550000000e-01
+306 124 -1.8343740000000e-01
+328 124 -1.8139140000000e-01
+350 124 -1.2639720000000e-01
+372 124 -5.5136770000000e-02
+105 125 -1.0000000000000e+00
+108 125 -1.0000000000000e+00
+264 125 -7.6362320000000e-01
+286 125 -5.4132110000000e-01
+308 125 -5.2907530000000e-01
+330 125 -5.2832600000000e-01
+352 125 -5.2965340000000e-01
+374 125 -5.9901060000000e-01
+392 125 -5.7467680000000e-01
+106 126 -1.0000000000000e+00
+109 126 -1.0000000000000e+00
+264 126 -1.4679790000000e+00
+286 126 -1.2898060000000e+00
+308 126 -1.2799920000000e+00
+330 126 -1.2793850000000e+00
+352 126 -1.2801740000000e+00
+374 126 -1.3601430000000e+00
+392 126 -7.1491900000000e-01
+107 127 -1.0000000000000e+00
+110 127 -1.0000000000000e+00
+264 127 -4.3708570000000e-03
+286 127 -3.9541010000000e-03
+308 127 -3.9318030000000e-03
+330 127 -3.9476680000000e-03
+352 127 -4.7490230000000e-03
+374 127 -7.2455390000000e-02
+392 127 -1.6023640000000e+00
+105 128 -1.1229330000000e-01
+108 128 -6.7276620000000e-02
+264 128 -5.4601370000000e-02
+286 128 -3.8877220000000e-02
+308 128 -3.8008660000000e-02
+330 128 -3.7958990000000e-02
+352 128 -3.8208860000000e-02
+374 128 -4.8085490000000e-02
+392 128 -5.8178620000000e-02
+106 129 -2.6206330000000e-01
+109 129 -1.5700610000000e-01
+264 129 -2.4496080000000e-01
+286 129 -2.1618060000000e-01
+308 129 -2.1459740000000e-01
+330 129 -2.1451910000000e-01
+352 129 -2.1552300000000e-01
+374 129 -2.5481000000000e-01
+392 129 -1.6890750000000e-01
+107 130 -1.6269950000000e-01
+110 130 -9.7475700000000e-02
+264 130 -4.5281760000000e-04
+286 130 -4.1145290000000e-04
+308 130 -4.0925030000000e-04
+330 130 -4.1094670000000e-04
+352 130 -4.9637370000000e-04
+374 130 -8.4271850000000e-03
+392 130 -2.3503520000000e-01
+117 131 -1.0000000000000e+00
+120 131 -1.0000000000000e+00
+249 131 -6.9702840000000e-02
+263 131 -1.9243320000000e-02
+285 131 -1.5837930000000e-02
+307 131 -1.5617910000000e-02
+329 131 -1.5583210000000e-02
+351 131 -1.4718560000000e-02
+373 131 -5.7599520000000e-03
+118 132 -1.0000000000000e+00
+121 132 -1.0000000000000e+00
+249 132 -7.4171360000000e-01
+263 132 -8.0234940000000e-01
+285 132 -8.0658470000000e-01
+307 132 -8.0682860000000e-01
+329 132 -8.0550310000000e-01
+351 132 -7.4926980000000e-01
+373 132 -1.9719700000000e-01
+119 133 -1.0000000000000e+00
+122 133 -1.0000000000000e+00
+249 133 -5.1275980000000e-01
+263 133 -5.2522530000000e-01
+285 133 -5.2614130000000e-01
+307 133 -5.2622450000000e-01
+329 133 -5.2730270000000e-01
+351 133 -5.7231860000000e-01
+373 133 -1.0252420000000e+00
+117 134 -4.6575930000000e-01
+120 134 -9.6900310000000e-01
+249 134 -4.4884880000000e-02
+263 134 -1.3170120000000e-02
+285 134 -1.0887390000000e-02
+307 134 -1.0739240000000e-02
+329 134 -1.0716550000000e-02
+351 134 -1.0163030000000e-02
+373 134 -4.4257190000000e-03
+118 135 -5.7440230000000e-01
+121 135 -1.1950330000000e+00
+249 135 -5.8903420000000e-01
+263 135 -6.7721740000000e-01
+285 135 -6.8380180000000e-01
+307 135 -6.8420530000000e-01
+329 135 -6.8315610000000e-01
+351 135 -6.3804400000000e-01
+373 135 -1.8686160000000e-01
+119 136 -2.2922850000000e-01
+122 136 -4.7690550000000e-01
+249 136 -1.6250650000000e-01
+263 136 -1.7691420000000e-01
+285 136 -1.7800620000000e-01
+307 136 -1.7808560000000e-01
+329 136 -1.7847000000000e-01
+351 136 -1.9449250000000e-01
+373 136 -3.8770260000000e-01
+129 137 -1.0000000000000e+00
+132 137 -1.0000000000000e+00
+265 137 -3.4272790000000e-01
+287 137 -2.9113760000000e-01
+309 137 -2.8769370000000e-01
+331 137 -2.8748890000000e-01
+353 137 -2.8823180000000e-01
+375 137 -3.0269870000000e-01
+393 137 -1.7507890000000e-01
+130 138 -1.0000000000000e+00
+133 138 -1.0000000000000e+00
+265 138 -1.0623340000000e+00
+287 138 -1.1185060000000e+00
+309 138 -1.1222530000000e+00
+331 138 -1.1225120000000e+00
+353 138 -1.1232850000000e+00
+375 138 -1.1082340000000e+00
+393 138 -3.5118640000000e-01
+131 139 -1.0000000000000e+00
+134 139 -1.0000000000000e+00
+265 139 -2.3999820000000e-03
+287 139 -2.6017300000000e-03
+309 139 -2.6156270000000e-03
+331 139 -2.6280330000000e-03
+353 139 -3.1617350000000e-03
+375 139 -4.4793810000000e-02
+393 139 -5.9723090000000e-01
+129 140 -2.0182530000000e+00
+132 140 -1.2091660000000e+00
+265 140 -4.4044890000000e-01
+287 140 -3.7580290000000e-01
+309 140 -3.7146430000000e-01
+331 140 -3.7124050000000e-01
+353 140 -3.7371090000000e-01
+375 140 -4.3672880000000e-01
+393 140 -3.1856280000000e-01
+130 141 -2.5626880000000e+00
+133 141 -1.5353450000000e+00
+265 141 -1.7335130000000e+00
+287 141 -1.8332450000000e+00
+309 141 -1.8399150000000e+00
+331 141 -1.8405410000000e+00
+353 141 -1.8492860000000e+00
+375 141 -2.0302660000000e+00
+393 141 -8.1137050000000e-01
+131 142 -9.2554290000000e-01
+134 142 -5.5450670000000e-01
+265 142 -1.4144090000000e-03
+287 142 -1.5400860000000e-03
+309 142 -1.5487580000000e-03
+331 142 -1.5562740000000e-03
+353 142 -1.8799250000000e-03
+375 142 -2.9637400000000e-02
+393 142 -4.9833870000000e-01
+135 143 -1.4338920000000e+00
+141 143 -2.1577040000000e+00
+266 143 -1.5239710000000e+00
+288 143 -1.5307080000000e+00
+310 143 -1.5311480000000e+00
+332 143 -1.5313160000000e+00
+354 143 -1.5375330000000e+00
+376 143 -1.7109280000000e+00
+136 144 -9.4320600000000e-01
+142 144 -1.4193260000000e+00
+267 144 -1.0024600000000e+00
+289 144 -1.0068910000000e+00
+311 144 -1.0071810000000e+00
+333 144 -1.0072910000000e+00
+355 144 -1.0113810000000e+00
+377 144 -1.1254390000000e+00
+137 145 -5.9645270000000e-01
+143 145 -8.9753530000000e-01
+268 145 -6.3392270000000e-01
+290 145 -6.3672520000000e-01
+312 145 -6.3690830000000e-01
+334 145 -6.3697810000000e-01
+356 145 -6.3956420000000e-01
+378 145 -7.1169090000000e-01
+135 146 -1.0000000000000e+00
+141 146 -1.0000000000000e+00
+266 146 -1.0000000000000e+00
+288 146 -1.0000000000000e+00
+310 146 -1.0000000000000e+00
+332 146 -1.0000000000000e+00
+354 146 -1.0000000000000e+00
+376 146 -1.0000000000000e+00
+136 147 -1.0000000000000e+00
+142 147 -1.0000000000000e+00
+267 147 -1.0000000000000e+00
+289 147 -1.0000000000000e+00
+311 147 -1.0000000000000e+00
+333 147 -1.0000000000000e+00
+355 147 -1.0000000000000e+00
+377 147 -1.0000000000000e+00
+137 148 -1.0000000000000e+00
+143 148 -1.0000000000000e+00
+268 148 -1.0000000000000e+00
+290 148 -1.0000000000000e+00
+312 148 -1.0000000000000e+00
+334 148 -1.0000000000000e+00
+356 148 -1.0000000000000e+00
+378 148 -1.0000000000000e+00
+138 149 -1.0000000000000e+00
+148 149  1.0000000000000e+00
+238 149  5.5083520000000e-01
+139 150 -1.0000000000000e+00
+149 150  1.6474950000000e+00
+239 150  7.3959730000000e-01
+140 151 -1.0000000000000e+00
+150 151  8.4135160000000e+02
+240 151  2.0404480000000e-01
+144 152 -1.0000000000000e+00
+182 152  1.0000000000000e+00
+382 152  1.9564470000000e-01
+145 153 -1.0000000000000e+00
+183 153  1.0000000000000e+00
+383 153  4.9830160000000e-01
+146 154 -1.0000000000000e+00
+184 154  3.1156220000000e+00
+384 154  9.5354780000000e-01
+395 155  6.6224920000000e+01
+401 155 -1.0000000000000e+00
+404 155 -3.3282570000000e-05
+396 156  1.1506230000000e+02
+402 156 -1.0000000000000e+00
+405 156 -4.1228310000000e-05
+397 157  2.3733870000000e+02
+403 157 -1.0000000000000e+00
+406 157 -8.4706900000000e-05
+398 158  1.3324500000000e+02
+401 158  2.5000000000000e+00
+404 158  3.3282570000000e-05
+399 159  2.3226390000000e+02
+402 159  2.5000000000000e+00
+405 159  4.1228310000000e-05
+400 160  4.8018210000000e+02
+403 160  2.5000000000000e+00
+406 160  8.4706900000000e-05
+160 161 -4.7337900000000e-01
+401 161  1.0000000000000e+00
+410 161 -2.1168760000000e-01
+161 162 -5.7343170000000e-01
+402 162  1.0000000000000e+00
+410 162 -3.1667150000000e-01
+162 163 -6.0925110000000e-04
+403 163  1.0000000000000e+00
+410 163 -3.5118740000000e-07
+163 164 -4.5750040000000e+03
+404 164  1.0075620000000e+00
+411 164 -5.5083520000000e-01
+164 165 -3.6814160000000e+03
+405 165  1.0043240000000e+00
+411 165 -4.4892230000000e-01
+165 166 -1.7878180000000e+03
+406 166  1.0020870000000e+00
+411 166 -2.4252030000000e-04
+160 167 -5.2605640000000e-01
+161 167 -4.2598230000000e-01
+407 167  1.0000000000000e+00
+410 167 -4.7048840000000e-01
+160 168 -5.6459870000000e-04
+162 168 -4.3800980000000e-01
+408 168  1.0000000000000e+00
+410 168 -5.0495930000000e-04
+161 169 -5.8596670000000e-04
+162 169 -5.6138090000000e-01
+409 169  1.0000000000000e+00
+410 169 -6.4718760000000e-04
+163 170 -1.0000000000000e+00
+164 170 -1.0000000000000e+00
+165 170 -1.0000000000000e+00
+410 170  1.0000000000000e+00
+412 170 -1.0000000000000e+00
+423 170  6.1444210000000e-02
+435 170  2.0481400000000e-02
+157 171 -1.0000000000000e+00
+163 171  4.1240600000000e+03
+164 171  4.1240600000000e+03
+165 171  4.1240600000000e+03
+411 171  1.0000000000000e+00
+413 171 -3.1622000000000e+05
+416 171 -2.0034240000000e+04
+417 171 -1.0000000000000e+00
+423 171 -2.6256570000000e+03
+434 171  2.2212900000000e+02
+412 172  1.8737270000000e+01
+414 172  9.4488160000000e-01
+413 173  1.4943670000000e+03
+414 173 -1.0207800000000e+00
+158 174 -9.9186010000000e-01
+163 174 -1.7922340000000e+01
+164 174 -1.7922340000000e+01
+165 174 -1.7922340000000e+01
+414 174  8.6282900000000e-01
+415 174  1.0497190000000e+00
+423 174 -7.3414950000000e-01
+157 175  8.1398600000000e-03
+415 175 -2.2212900000000e+02
+417 175  8.1398600000000e-03
+433 175 -2.2212900000000e+02
+434 175 -1.8080990000000e+00
+163 176 -1.0913280000000e+00
+164 176 -1.6293970000000e+00
+165 176 -1.4448530000000e+00
+416 176  1.0000000000000e+00
+423 176  4.7364060000000e-02
+435 176 -2.7898140000000e-02
+417 177  4.5385340000000e-03
+423 177  7.5792400000000e+00
+435 177  2.5264130000000e+00
+148 178 -1.0000000000000e+00
+178 178 -1.0000000000000e+00
+149 179 -1.0000000000000e+00
+179 179 -1.0000000000000e+00
+150 180 -1.0000000000000e+00
+180 180 -1.0000000000000e+00
+148 181  1.0266460000000e+00
+166 181 -1.0000000000000e+00
+149 182  1.0737240000000e+00
+167 182 -1.0000000000000e+00
+150 183  1.2081470000000e+00
+168 183 -1.0000000000000e+00
+148 184 -1.0000000000000e+00
+154 184 -1.0000000000000e+00
+149 185 -1.0000000000000e+00
+155 185 -1.0000000000000e+00
+150 186 -1.0000000000000e+00
+156 186 -1.0000000000000e+00
+215 187  9.9149730000000e+01
+221 187 -1.0000000000000e+00
+224 187 -3.3113980000000e-05
+216 188  1.7263960000000e+02
+222 188 -1.0000000000000e+00
+225 188 -4.1108120000000e-05
+217 189  3.5663980000000e+02
+223 189 -1.0000000000000e+00
+226 189 -8.4587180000000e-05
+218 190  2.0000080000000e+02
+221 190  2.5000000000000e+00
+224 190  3.3113980000000e-05
+219 191  3.4900330000000e+02
+222 191  2.5000000000000e+00
+225 191  4.1108120000000e-05
+220 192  7.2206780000000e+02
+223 192  2.5000000000000e+00
+226 192  8.4587180000000e-05
+194 193 -1.1483880000000e-01
+221 193  1.0000000000000e+00
+230 193 -1.1645920000000e-02
+195 194 -4.1678390000000e-01
+222 194  1.0000000000000e+00
+230 194 -1.7006160000000e-01
+196 195 -4.9676140000000e-01
+223 195  1.0000000000000e+00
+230 195 -2.4368930000000e-01
+197 196 -5.2768620000000e+03
+224 196  1.0050250000000e+00
+231 196 -1.9564470000000e-01
+198 197 -4.2415910000000e+03
+225 197  1.0028740000000e+00
+231 197 -4.9830160000000e-01
+199 198 -2.0582940000000e+03
+226 198  1.0013870000000e+00
+231 198 -3.0605370000000e-01
+194 199 -3.9872280000000e-01
+195 199 -9.9097090000000e-02
+227 199  1.0000000000000e+00
+230 199 -8.0869760000000e-02
+194 200 -4.8643840000000e-01
+196 200 -1.0055980000000e-01
+228 200  1.0000000000000e+00
+230 200 -9.8660410000000e-02
+195 201 -4.8411900000000e-01
+196 201 -4.0267880000000e-01
+229 201  1.0000000000000e+00
+230 201 -3.9507300000000e-01
+197 202 -1.0000000000000e+00
+198 202 -1.0000000000000e+00
+199 202 -1.0000000000000e+00
+230 202  1.0000000000000e+00
+232 202 -1.0000000000000e+00
+191 203 -1.0000000000000e+00
+197 203  3.2976230000000e+03
+198 203  3.2976230000000e+03
+199 203  3.2976230000000e+03
+231 203  1.0000000000000e+00
+233 203 -3.1622000000000e+05
+236 203 -1.8966660000000e+04
+237 203 -1.0000000000000e+00
+232 204  2.2669870000000e+01
+234 204  9.5486020000000e-01
+233 205  2.2487060000000e+03
+234 205 -1.0206550000000e+00
+192 206 -9.9229510000000e-01
+197 206 -2.1898570000000e+01
+198 206 -2.1898570000000e+01
+199 206 -2.1898570000000e+01
+234 206  8.9000960000000e-01
+235 206  1.0392050000000e+00
+191 207  7.7048970000000e-03
+235 207 -1.4613620000000e+02
+237 207  7.7048970000000e-03
+197 208 -6.5890520000000e-01
+198 208 -1.1064970000000e+00
+199 208 -1.0009090000000e+00
+236 208  1.0000000000000e+00
+237 209  6.8956570000000e-03
+182 210 -1.0000000000000e+00
+212 210 -1.0000000000000e+00
+183 211 -1.0000000000000e+00
+213 211 -1.0000000000000e+00
+184 212 -1.0000000000000e+00
+214 212 -1.0000000000000e+00
+182 213  1.0000000000000e+00
+200 213 -1.0000000000000e+00
+183 214  1.0226760000000e+00
+201 214 -1.0000000000000e+00
+184 215  1.0914180000000e+00
+202 215 -1.0000000000000e+00
+182 216 -1.0000000000000e+00
+188 216 -1.0000000000000e+00
+183 217 -1.0000000000000e+00
+189 217 -1.0000000000000e+00
+184 218 -1.0000000000000e+00
+190 218 -1.0000000000000e+00
+241 219 -1.9969610000000e-01
+242 219 -7.8596160000000e-01
+243 219 -6.4128230000000e-04
+244 219  4.0690410000000e-01
+253 219  2.0247020000000e-01
+254 219  7.9687960000000e-01
+255 219  6.5019060000000e-04
+256 219 -2.1665440000000e+00
+257 220 -1.0000000000000e+00
+264 220 -3.0001500000000e-01
+265 220 -4.0746150000000e-01
+246 221 -1.0000000000000e+00
+247 221 -1.0000000000000e+00
+258 221  1.0000000000000e+00
+244 222  4.0690410000000e-01
+256 222 -2.1665440000000e+00
+264 222  1.0000000000000e+00
+265 223  1.0000000000000e+00
+238 224  0.0000000000000e+00
+241 224 -9.8629890000000e-01
+250 224 -1.0000000000000e+00
+253 224  1.0000000000000e+00
+261 224  1.0000000000000e+00
+264 224  3.5018580000000e+00
+265 224  1.2418840000000e+00
+239 225  0.0000000000000e+00
+242 225 -9.8629890000000e-01
+251 225 -1.0000000000000e+00
+254 225  1.0000000000000e+00
+261 225  1.0000000000000e+00
+264 225 -2.1495590000000e+00
+265 225  9.3602390000000e-01
+240 226  0.0000000000000e+00
+243 226 -9.8629890000000e-01
+252 226 -1.0000000000000e+00
+255 226  1.0000000000000e+00
+261 226  1.0000000000000e+00
+264 226  6.0259860000000e+00
+265 226  4.0868380000000e+00
+253 227  1.1955300000000e-02
+254 227  6.1475030000000e-01
+255 227  1.6059550000000e-01
+256 227  5.9918100000000e-01
+275 227 -1.1949680000000e-02
+276 227 -6.1446120000000e-01
+277 227 -1.6052000000000e-01
+278 227 -1.0000000000000e+00
+257 228  1.0000000000000e+00
+262 228 -9.3350860000000e-02
+263 228 -3.4681810000000e-01
+266 228 -1.0000000000000e+00
+267 228 -1.0000000000000e+00
+268 228 -1.0000000000000e+00
+259 229  1.0000000000000e+00
+256 230 -5.9918100000000e-01
+262 230  1.0000000000000e+00
+278 230  1.0000000000000e+00
+263 231  1.0000000000000e+00
+250 232  1.3333420000000e+01
+253 232  7.8730110000000e-01
+260 232  1.0000000000000e+00
+262 232  1.2120260000000e+01
+263 232  7.7025090000000e-01
+275 232 -7.8693090000000e-01
+251 233  1.0205510000000e+00
+254 233  7.8730110000000e-01
+260 233  1.0000000000000e+00
+262 233 -3.9843990000000e+00
+263 233  6.8134200000000e-01
+276 233 -7.8693090000000e-01
+252 234  3.1874850000000e-03
+255 234  7.8730110000000e-01
+260 234  1.0000000000000e+00
+262 234  1.9252160000000e+01
+263 234  2.2369070000000e+00
+277 234 -7.8693090000000e-01
+253 235 -1.7008130000000e-01
+254 235 -8.2969220000000e-01
+255 235 -6.9701410000000e-04
+256 235  2.5673630000000e+00
+275 235  1.7000140000000e-01
+276 235  8.2930200000000e-01
+277 235  6.9668630000000e-04
+278 235 -4.2847870000000e+00
+279 236 -1.0000000000000e+00
+286 236 -2.5546930000000e-01
+287 236 -4.1224570000000e-01
+258 237 -1.0000000000000e+00
+259 237 -1.0000000000000e+00
+280 237  1.0000000000000e+00
+256 238  2.5673630000000e+00
+278 238 -4.2847870000000e+00
+286 238  1.0000000000000e+00
+287 239  1.0000000000000e+00
+250 240  0.0000000000000e+00
+253 240 -1.0004710000000e+00
+272 240 -1.0000000000000e+00
+275 240  1.0000000000000e+00
+283 240  1.0000000000000e+00
+286 240  2.9555290000000e+00
+287 240  1.2544140000000e+00
+251 241  0.0000000000000e+00
+254 241 -1.0004710000000e+00
+273 241 -1.0000000000000e+00
+276 241  1.0000000000000e+00
+283 241  1.0000000000000e+00
+286 241 -1.8159690000000e+00
+287 241  9.4521190000000e-01
+252 242  0.0000000000000e+00
+255 242 -1.0004710000000e+00
+274 242 -1.0000000000000e+00
+277 242  1.0000000000000e+00
+283 242  1.0000000000000e+00
+286 242  5.0849970000000e+00
+287 242  4.1364790000000e+00
+250 243  2.0247020000000e-01
+269 243 -1.0000000000000e+00
+251 244  7.9687960000000e-01
+270 244 -1.0000000000000e+00
+252 245  2.0398230000000e-01
+271 245 -1.0000000000000e+00
+275 246  9.8180810000000e-03
+276 246  6.1664170000000e-01
+278 246  9.5579440000000e-01
+297 246 -9.8175690000000e-03
+298 246 -6.1660960000000e-01
+299 246 -1.6051480000000e-01
+300 246 -1.0000000000000e+00
+279 247  1.0000000000000e+00
+284 247 -9.8217900000000e-02
+285 247 -3.4856390000000e-01
+288 247 -1.0000000000000e+00
+289 247 -1.0000000000000e+00
+290 247 -1.0000000000000e+00
+281 248  1.0000000000000e+00
+278 249 -9.5579440000000e-01
+284 249  1.0000000000000e+00
+300 249  1.0000000000000e+00
+285 250  1.0000000000000e+00
+272 251  1.3626710000000e+01
+275 251  7.8698300000000e-01
+282 251  1.0000000000000e+00
+284 251  1.2682330000000e+01
+285 251  7.6942870000000e-01
+297 251 -7.8694200000000e-01
+273 252  1.0583890000000e+00
+276 252  7.8698300000000e-01
+282 252  1.0000000000000e+00
+284 252 -4.1684890000000e+00
+285 252  6.8102850000000e-01
+298 252 -7.8694200000000e-01
+274 253  3.4155830000000e-03
+277 253  7.8698300000000e-01
+282 253  1.0000000000000e+00
+284 253  2.0139960000000e+01
+285 253  2.2394150000000e+00
+299 253 -7.8694200000000e-01
+275 254 -1.6786980000000e-01
+276 254 -8.3148250000000e-01
+277 254 -6.9990470000000e-04
+278 254  4.3289930000000e+00
+297 254  1.6786100000000e-01
+298 254  8.3143910000000e-01
+299 254  6.9986820000000e-04
+300 254 -4.5292090000000e+00
+301 255 -1.0000000000000e+00
+308 255 -2.5301530000000e-01
+309 255 -4.1256250000000e-01
+280 256 -1.0000000000000e+00
+281 256 -1.0000000000000e+00
+302 256  1.0000000000000e+00
+278 257  4.3289930000000e+00
+300 257 -4.5292090000000e+00
+308 257  1.0000000000000e+00
+309 258  1.0000000000000e+00
+272 259  0.0000000000000e+00
+275 259 -1.0000520000000e+00
+294 259 -1.0000000000000e+00
+297 259  1.0000000000000e+00
+305 259  1.0000000000000e+00
+308 259  2.9254360000000e+00
+309 259  1.2552490000000e+00
+273 260  0.0000000000000e+00
+276 260 -1.0000520000000e+00
+295 260 -1.0000000000000e+00
+298 260  1.0000000000000e+00
+305 260  1.0000000000000e+00
+308 260 -1.7975930000000e+00
+309 260  9.4582430000000e-01
+274 261  0.0000000000000e+00
+277 261 -1.0000520000000e+00
+296 261 -1.0000000000000e+00
+299 261  1.0000000000000e+00
+305 261  1.0000000000000e+00
+308 261  5.0331660000000e+00
+309 261  4.1397830000000e+00
+272 262  1.7000140000000e-01
+291 262 -1.0000000000000e+00
+273 263  8.2930200000000e-01
+292 263 -1.0000000000000e+00
+274 264  2.0397290000000e-01
+293 264 -1.0000000000000e+00
+297 265  9.6798500000000e-03
+298 265  6.1671090000000e-01
+299 265  1.6051810000000e-01
+300 265  9.9729840000000e-01
+319 265 -9.6801700000000e-03
+320 265 -6.1673130000000e-01
+321 265 -1.6052340000000e-01
+322 265 -1.0000000000000e+00
+301 266  1.0000000000000e+00
+306 266 -9.8528720000000e-02
+307 266 -3.4867100000000e-01
+310 266 -1.0000000000000e+00
+311 266 -1.0000000000000e+00
+312 266 -1.0000000000000e+00
+303 267  1.0000000000000e+00
+300 268 -9.9729840000000e-01
+306 268  1.0000000000000e+00
+322 268  1.0000000000000e+00
+307 269  1.0000000000000e+00
+294 270  1.3646010000000e+01
+297 270  7.8690890000000e-01
+304 270  1.0000000000000e+00
+306 270  1.2716190000000e+01
+307 270  7.6935860000000e-01
+319 270 -7.8693490000000e-01
+295 271  1.0608970000000e+00
+298 271  7.8690890000000e-01
+304 271  1.0000000000000e+00
+306 271 -4.1795750000000e+00
+307 271  6.8099360000000e-01
+320 271 -7.8693490000000e-01
+296 272  3.4309680000000e-03
+299 272  7.8690890000000e-01
+304 272  1.0000000000000e+00
+306 272  2.0193410000000e+01
+307 272  2.2395320000000e+00
+321 272 -7.8693490000000e-01
+297 273 -1.6772330000000e-01
+298 273 -8.3154050000000e-01
+299 273 -7.0311130000000e-04
+300 273  4.5319110000000e+00
+319 273  1.6772880000000e-01
+320 273  8.3156800000000e-01
+321 273  7.0313460000000e-04
+322 273 -4.5441880000000e+00
+323 274 -1.0000000000000e+00
+330 274 -2.5288910000000e-01
+331 274 -4.1262900000000e-01
+302 275 -1.0000000000000e+00
+303 275 -1.0000000000000e+00
+324 275  1.0000000000000e+00
+300 276  4.5319110000000e+00
+322 276 -4.5441880000000e+00
+330 276  1.0000000000000e+00
+331 277  1.0000000000000e+00
+294 278  0.0000000000000e+00
+297 278 -9.9996690000000e-01
+316 278 -1.0000000000000e+00
+319 278  1.0000000000000e+00
+327 278  1.0000000000000e+00
+330 278  2.9235700000000e+00
+331 278  1.2552940000000e+00
+295 279  0.0000000000000e+00
+298 279 -9.9996690000000e-01
+317 279 -1.0000000000000e+00
+320 279  1.0000000000000e+00
+327 279  1.0000000000000e+00
+330 279 -1.7964900000000e+00
+331 279  9.4585160000000e-01
+296 280  0.0000000000000e+00
+299 280 -9.9996690000000e-01
+318 280 -1.0000000000000e+00
+321 280  1.0000000000000e+00
+327 280  1.0000000000000e+00
+330 280  5.0299350000000e+00
+331 280  4.1401400000000e+00
+294 281  1.6786100000000e-01
+313 281 -1.0000000000000e+00
+295 282  8.3143910000000e-01
+314 282 -1.0000000000000e+00
+296 283  2.0398560000000e-01
+315 283 -1.0000000000000e+00
+319 284  9.6473500000000e-03
+320 284  6.1499680000000e-01
+321 284  1.6066380000000e-01
+322 284  1.0122750000000e+00
+341 284 -9.6630710000000e-03
+342 284 -6.1599900000000e-01
+343 284 -1.6092570000000e-01
+344 284 -1.0000000000000e+00
+323 285  1.0000000000000e+00
+328 285 -9.7740150000000e-02
+329 285 -3.4838900000000e-01
+332 285 -1.0000000000000e+00
+333 285 -1.0000000000000e+00
+334 285 -1.0000000000000e+00
+325 286  1.0000000000000e+00
+322 287 -1.0122750000000e+00
+328 287  1.0000000000000e+00
+344 287  1.0000000000000e+00
+329 288  1.0000000000000e+00
+316 289  1.3653370000000e+01
+319 289  7.8530800000000e-01
+326 289  1.0000000000000e+00
+328 289  1.2536040000000e+01
+329 289  7.6861380000000e-01
+341 289 -7.8658770000000e-01
+317 290  1.0618540000000e+00
+320 290  7.8530800000000e-01
+326 290  1.0000000000000e+00
+328 290 -4.1203450000000e+00
+329 290  6.8034460000000e-01
+342 290 -7.8658770000000e-01
+318 291  3.4368480000000e-03
+321 291  7.8530800000000e-01
+326 291  1.0000000000000e+00
+328 291  1.9907200000000e+01
+329 291  2.2374860000000e+00
+343 291 -7.8658770000000e-01
+319 292 -1.6769600000000e-01
+320 292 -8.2983350000000e-01
+321 292 -8.4358210000000e-04
+322 292  4.5319130000000e+00
+341 292  1.6796930000000e-01
+342 292  8.3118580000000e-01
+343 292  8.4495670000000e-04
+344 292 -4.4769570000000e+00
+345 293 -1.0000000000000e+00
+352 293 -2.5422820000000e-01
+353 293 -4.1467850000000e-01
+324 294 -1.0000000000000e+00
+325 294 -1.0000000000000e+00
+346 294  1.0000000000000e+00
+322 295  4.5319120000000e+00
+344 295 -4.4769570000000e+00
+352 295  1.0000000000000e+00
+353 296  1.0000000000000e+00
+316 297  0.0000000000000e+00
+319 297 -9.9837310000000e-01
+338 297 -1.0000000000000e+00
+341 297  1.0000000000000e+00
+349 297  1.0000000000000e+00
+352 297  2.9258000000000e+00
+353 297  1.2548710000000e+00
+317 298  0.0000000000000e+00
+320 298 -9.9837310000000e-01
+339 298 -1.0000000000000e+00
+342 298  1.0000000000000e+00
+349 298  1.0000000000000e+00
+352 298 -1.7994740000000e+00
+353 298  9.4529590000000e-01
+318 299  0.0000000000000e+00
+321 299 -9.9837310000000e-01
+340 299 -1.0000000000000e+00
+343 299  1.0000000000000e+00
+349 299  1.0000000000000e+00
+352 299  5.0329780000000e+00
+353 299  4.1465320000000e+00
+316 300  1.6772880000000e-01
+335 300 -1.0000000000000e+00
+317 301  8.3156800000000e-01
+336 301 -1.0000000000000e+00
+318 302  2.0458700000000e-01
+337 302 -1.0000000000000e+00
+341 303  8.9580030000000e-03
+342 303  5.6239150000000e-01
+343 303  1.7143160000000e-01
+344 303  1.5349870000000e+00
+363 303 -9.3684010000000e-03
+364 303 -5.8815670000000e-01
+365 303 -1.7928550000000e-01
+366 303 -1.0000000000000e+00
+345 304  1.0000000000000e+00
+350 304 -7.6424570000000e-02
+351 304 -3.3630700000000e-01
+354 304 -1.0000000000000e+00
+355 304 -1.0000000000000e+00
+356 304 -1.0000000000000e+00
+347 305  1.0000000000000e+00
+344 306 -1.5349870000000e+00
+350 306  1.0000000000000e+00
+366 306  1.0000000000000e+00
+351 307  1.0000000000000e+00
+338 308  1.3927700000000e+01
+341 308  7.4278120000000e-01
+348 308  1.0000000000000e+00
+350 308  7.7124140000000e+00
+351 308  7.3754050000000e-01
+363 308 -7.7681060000000e-01
+339 309  1.0977920000000e+00
+342 309  7.4278120000000e-01
+348 309  1.0000000000000e+00
+350 309 -2.5345340000000e+00
+351 309  6.5320800000000e-01
+364 309 -7.7681060000000e-01
+340 310  3.6610400000000e-03
+343 310  7.4278120000000e-01
+348 310  1.0000000000000e+00
+350 310  1.2244490000000e+01
+351 310  2.1513860000000e+00
+365 310 -7.7681060000000e-01
+341 311 -1.6726420000000e-01
+342 311 -7.7757830000000e-01
+343 311 -1.1350930000000e-02
+344 311  3.9419710000000e+00
+363 311  1.7492720000000e-01
+364 311  8.1320190000000e-01
+365 311  1.1870950000000e-02
+366 311 -2.5680820000000e+00
+367 312 -1.0000000000000e+00
+374 312 -3.1132270000000e-01
+375 312 -4.5572680000000e-01
+346 313 -1.0000000000000e+00
+347 313 -1.0000000000000e+00
+368 313  1.0000000000000e+00
+344 314  3.9419710000000e+00
+366 314 -2.5680820000000e+00
+374 314  1.0000000000000e+00
+375 315  1.0000000000000e+00
+338 316  0.0000000000000e+00
+341 316 -9.5619350000000e-01
+360 316 -1.0000000000000e+00
+363 316  1.0000000000000e+00
+371 316  1.0000000000000e+00
+374 316  3.1494540000000e+00
+375 316  1.2129980000000e+00
+339 317  0.0000000000000e+00
+342 317 -9.5619350000000e-01
+361 317 -1.0000000000000e+00
+364 317  1.0000000000000e+00
+371 317  1.0000000000000e+00
+374 317 -1.9859190000000e+00
+375 317  9.0706840000000e-01
+340 318  0.0000000000000e+00
+343 318 -9.5619350000000e-01
+362 318 -1.0000000000000e+00
+365 318  1.0000000000000e+00
+371 318  1.0000000000000e+00
+374 318  5.3936870000000e+00
+375 318  4.2274630000000e+00
+338 319  1.6796930000000e-01
+357 319 -1.0000000000000e+00
+339 320  8.3118580000000e-01
+358 320 -1.0000000000000e+00
+340 321  2.3079690000000e-01
+359 321 -1.0000000000000e+00
+363 322  4.9560030000000e-03
+364 322  2.0925110000000e-01
+365 322  4.3415660000000e-01
+366 322  6.1773840000000e+00
+385 322 -5.6864040000000e-03
+386 322 -2.4008990000000e-01
+387 322 -4.9814130000000e-01
+388 322 -1.0000000000000e+00
+367 323  1.0000000000000e+00
+372 323 -5.1899590000000e-02
+373 323 -2.2819930000000e-01
+376 323 -1.0000000000000e+00
+377 323 -1.0000000000000e+00
+378 323 -1.0000000000000e+00
+369 324  1.0000000000000e+00
+366 325 -6.1773840000000e+00
+372 325  1.0000000000000e+00
+388 325  1.0000000000000e+00
+373 326  1.0000000000000e+00
+360 327  2.2884660000000e+01
+363 327  6.4836370000000e-01
+370 327  1.0000000000000e+00
+372 327  1.0434500000000e+00
+373 327  4.2175860000000e-01
+385 327 -7.4391760000000e-01
+361 328  2.5197030000000e+00
+364 328  6.4836370000000e-01
+370 328  1.0000000000000e+00
+372 328 -3.4146640000000e-01
+373 328  3.7988980000000e-01
+386 328 -7.4391760000000e-01
+362 329  1.7727920000000e-02
+365 329  6.4836370000000e-01
+370 329  1.0000000000000e+00
+372 329  1.6460520000000e+00
+373 329  1.3054760000000e+00
+387 329 -7.4391760000000e-01
+360 330  1.7492720000000e-01
+379 330 -1.0000000000000e+00
+361 331  8.1320190000000e-01
+380 331 -1.0000000000000e+00
+362 332  6.6961900000000e-01
+381 332 -1.0000000000000e+00
+87 333  6.3180580000000e+00
+93 333  1.0081210000000e+00
+88 334  2.1016520000000e+00
+94 334  9.8325000000000e-01
+89 335  1.0216340000000e+01
+95 335  9.7112200000000e-01
+90 336  4.7715330000000e+00
+96 336  1.0168970000000e+00
+91 337  1.5445530000000e+00
+97 337  9.6515200000000e-01
+92 338  7.4032580000000e+00
+98 338  9.3991980000000e-01
+99 339  2.7676480000000e+02
+105 339  8.8770670000000e-01
+100 340  1.9219040000000e+02
+106 340  1.2620630000000e+00
+101 341  4.6529740000000e+02
+107 341  8.3730050000000e-01
+102 342  4.0263530000000e+02
+108 342  9.3272340000000e-01
+103 343  2.4395160000000e+02
+109 343  1.1570060000000e+00
+104 344  6.9442570000000e+02
+110 344  9.0252430000000e-01
+111 345  2.1471690000000e+00
+117 345  7.3310410000000e-01
+112 346  1.8303540000000e+00
+118 346  7.7070690000000e-01
+113 347  5.4194960000000e+00
+119 347  9.1067970000000e-01
+114 348  1.5934600000000e+00
+120 348  4.4472830000000e-01
+115 349  1.5193590000000e+00
+121 349  5.2296010000000e-01
+116 350  5.9272710000000e+00
+122 350  8.1417070000000e-01
+123 351  8.6013230000000e+00
+129 351  5.8171510000000e-01
+124 352  6.1974850000000e+00
+130 352  5.3220720000000e-01
+125 353  3.7670330000000e+01
+131 353  1.1683300000000e+00
+126 354  1.0955350000000e+01
+132 354  7.4939930000000e-01
+127 355  8.2864270000000e+00
+133 355  7.1973830000000e-01
+128 356  3.5092930000000e+01
+134 356  1.1008490000000e+00
+135 357  4.3389190000000e-01
+138 357  2.2797130000000e+00
+136 358  1.1375720000000e-01
+139 358  6.0698210000000e-01
+137 359  4.0354730000000e-01
+140 359  8.0049890000000e-03
+141 360  1.1577040000000e+00
+144 360  4.0422280000000e+00
+142 361  4.1932590000000e-01
+145 361  2.4496110000000e+00
+143 362  1.0246470000000e-01
+146 362  3.6475180000000e-01
+151 363  1.7257450000000e+02
+154 363  1.4917610000000e+01
+152 364  1.6158450000000e+02
+155 364  1.2093800000000e+01
+153 365  1.4531450000000e+02
+156 365  5.7400960000000e+00
+157 366  4.5018890000000e-03
+158 366  9.5263590000000e-01
+159 366 -1.0000000000000e+00
+158 367  9.4488160000000e-01
+163 367  1.9882060000000e+01
+164 367  1.5998700000000e+01
+165 367  7.7694990000000e+00
+159 368  1.0081400000000e+00
+163 368  9.8828980000000e+01
+164 368  1.4755580000000e+02
+165 368  1.3084370000000e+02
+160 369  1.0000000000000e+00
+163 369  1.8011980000000e+00
+161 370  1.0000000000000e+00
+164 370  2.1962210000000e+00
+162 371  1.0000000000000e+00
+165 371  2.0607380000000e+00
+163 372  1.9882060000000e+01
+166 372  9.7404530000000e-01
+164 373  1.5998700000000e+01
+167 373  9.3133780000000e-01
+165 374  7.7694990000000e+00
+168 374  8.2771400000000e-01
+169 375 -1.0000000000000e+00
+172 375 -1.0000000000000e+00
+175 375  5.6357910000000e-02
+176 375  5.6357910000000e-02
+177 375  5.6357910000000e-02
+170 376 -1.0000000000000e+00
+173 376 -1.0000000000000e+00
+175 376  7.3959730000000e-01
+176 376  7.3959730000000e-01
+177 376  7.3959730000000e-01
+171 377 -1.0000000000000e+00
+174 377 -1.0000000000000e+00
+175 377  2.0404480000000e-01
+176 377  2.0404480000000e-01
+177 377  2.0404480000000e-01
+172 378  1.0000000000000e+00
+175 378 -1.0000000000000e+00
+173 379  1.0000000000000e+00
+176 379 -1.0000000000000e+00
+174 380  1.0000000000000e+00
+177 380 -1.0000000000000e+00
+175 381  1.0000000000000e+00
+178 381  1.0000000000000e+00
+176 382  1.0000000000000e+00
+179 382  1.0000000000000e+00
+177 383  1.0000000000000e+00
+180 383  1.0000000000000e+00
+102 384 -1.9453890000000e+01
+418 384  1.0000000000000e+00
+424 384 -9.5304210000000e-02
+103 385 -2.2090310000000e+01
+419 385  1.0000000000000e+00
+424 385 -8.8197620000000e-02
+104 386 -4.9563590000000e+01
+420 386  1.0000000000000e+00
+424 386 -1.0690420000000e-04
+421 387  1.7973450000000e+02
+422 387 -2.5957400000000e+00
+422 388  1.0000000000000e+00
+423 388 -9.6216520000000e-02
+102 389 -1.0000000000000e+00
+103 389 -1.0000000000000e+00
+104 389 -1.0000000000000e+00
+423 389  9.6216520000000e-02
+424 389 -8.8937280000000e-03
+126 390  9.3082790000000e-01
+127 390  9.3082790000000e-01
+128 390  9.3082790000000e-01
+425 390 -1.1383520000000e+00
+436 390  9.5341780000000e-02
+126 391  8.1769790000000e-01
+426 391 -5.5083520000000e-01
+436 391  4.6134780000000e-02
+127 392  8.1769790000000e-01
+427 392 -4.4892230000000e-01
+436 392  3.7599150000000e-02
+128 393  6.8068650000000e+00
+428 393 -2.0188420000000e-03
+436 393  1.6908660000000e-04
+429 394 -6.0313590000000e-01
+430 394 -1.1914260000000e+00
+431 394 -2.0901010000000e-01
+432 394 -2.3236640000000e-01
+126 395 -1.5881990000000e+00
+430 395  1.0000000000000e+00
+436 395 -8.9606730000000e-02
+127 396 -1.7894780000000e+00
+431 396  1.0000000000000e+00
+436 396 -8.2283250000000e-02
+128 397 -4.0128040000000e+00
+432 397  1.0000000000000e+00
+436 397 -9.9680420000000e-05
+433 398  1.1868740000000e+00
+435 398 -8.7134320000000e-01
+434 399  9.9186010000000e-01
+435 399 -7.3414950000000e-01
+126 400 -1.0000000000000e+00
+127 400 -1.0000000000000e+00
+128 400 -1.0000000000000e+00
+435 400  8.9782490000000e-01
+436 400 -1.0242690000000e-01
+185 401  2.6330250000000e+02
+188 401  1.6710230000000e+01
+186 402  2.5231250000000e+02
+189 402  1.5091380000000e+01
+187 403  2.3604250000000e+02
+190 403  1.1440290000000e+01
+191 404  6.8429330000000e-03
+192 404  9.6227440000000e-01
+193 404 -1.0000000000000e+00
+192 405  9.5486020000000e-01
+197 405  3.5042120000000e+01
+198 405  2.8167190000000e+01
+199 405  1.3668540000000e+01
+193 406  1.0077050000000e+00
+197 406  8.5846760000000e+01
+198 406  1.4416210000000e+02
+199 406  1.3040540000000e+02
+194 407  1.0000000000000e+00
+197 407  1.6589050000000e+00
+195 408  1.0000000000000e+00
+198 408  2.1064970000000e+00
+196 409  1.0000000000000e+00
+199 409  2.0009090000000e+00
+197 410  3.5042120000000e+01
+200 410  1.0000000000000e+00
+198 411  2.8167190000000e+01
+201 411  9.7782690000000e-01
+199 412  1.3668540000000e+01
+202 412  9.1623940000000e-01
+203 413 -1.0000000000000e+00
+206 413 -1.0000000000000e+00
+209 413  3.4351900000000e-03
+210 413  3.4351900000000e-03
+211 413  3.4351900000000e-03
+204 414 -1.0000000000000e+00
+207 414 -1.0000000000000e+00
+209 414  4.3016970000000e-02
+210 414  4.3016970000000e-02
+211 414  4.3016970000000e-02
+205 415 -1.0000000000000e+00
+208 415 -1.0000000000000e+00
+209 415  9.5354780000000e-01
+210 415  9.5354780000000e-01
+211 415  9.5354780000000e-01
+206 416  1.0000000000000e+00
+209 416 -1.0000000000000e+00
+207 417  1.0000000000000e+00
+210 417 -1.0000000000000e+00
+208 418  1.0000000000000e+00
+211 418 -1.0000000000000e+00
+209 419  1.0000000000000e+00
+212 419  1.0000000000000e+00
+210 420  1.0000000000000e+00
+213 420  1.0000000000000e+00
+211 421  1.0000000000000e+00
+214 421  1.0000000000000e+00
+90 422 -4.7613130000000e-02
+461 422  1.0000000000000e+00
+467 422 -2.3334700000000e-05
+91 423 -5.7464350000000e-02
+462 423  1.0000000000000e+00
+467 423 -3.5266560000000e-04
+92 424 -1.2956040000000e-01
+463 424  1.0000000000000e+00
+467 424 -1.7625420000000e-02
+464 425  2.7046250000000e+02
+465 425 -2.8000670000000e+00
+465 426  1.0000000000000e+00
+466 426 -1.6856930000000e+00
+90 427 -1.0000000000000e+00
+91 427 -1.0000000000000e+00
+92 427 -1.0000000000000e+00
+466 427  1.6856930000000e+00
+467 427 -1.4266740000000e-01
+114 428  1.2149740000000e-01
+115 428  1.2149740000000e-01
+116 428  1.2149740000000e-01
+468 428 -1.1383520000000e+00
+479 428  2.1230520000000e-02
+114 429  6.0555750000000e-01
+469 429 -1.9490180000000e-02
+479 429  3.6349630000000e-04
+115 430  3.3579270000000e-01
+470 430 -1.3533830000000e-01
+479 430  2.5240900000000e-03
+116 431  1.0673090000000e-01
+471 431 -9.5354780000000e-01
+479 431  1.7783880000000e-02
+472 432 -9.0759220000000e-01
+473 432 -5.7118220000000e+00
+474 432 -9.3568410000000e-01
+475 432 -1.0346550000000e+00
+114 433 -4.3240930000000e-02
+473 433  1.0000000000000e+00
+479 433 -2.5956110000000e-05
+115 434 -5.2174910000000e-02
+474 434  1.0000000000000e+00
+479 434 -3.9218900000000e-04
+116 435 -1.1763140000000e-01
+475 435  1.0000000000000e+00
+479 435 -1.9600160000000e-02
+476 436  5.3140780000000e+00
+478 436 -1.0021840000000e+00
+477 437  3.4483720000000e-01
+478 437 -2.6478620000000e-01
+114 438 -1.0000000000000e+00
+115 438 -1.0000000000000e+00
+116 438 -1.0000000000000e+00
+478 438  1.7669710000000e+00
+479 438 -1.7474060000000e-01
+438 439  9.9149730000000e+01
+444 439 -1.0000000000000e+00
+447 439 -3.3113980000000e-05
+439 440  1.7263960000000e+02
+445 440 -1.0000000000000e+00
+448 440 -4.1108120000000e-05
+440 441  3.5663980000000e+02
+446 441 -1.0000000000000e+00
+449 441 -8.4587180000000e-05
+441 442  2.0000080000000e+02
+444 442  2.5000000000000e+00
+447 442  3.3113980000000e-05
+442 443  3.4900330000000e+02
+445 443  2.5000000000000e+00
+448 443  4.1108120000000e-05
+443 444  7.2206780000000e+02
+446 444  2.5000000000000e+00
+449 444  8.4587180000000e-05
+444 445  1.0000000000000e+00
+453 445 -1.4485650000000e-06
+445 446  1.0000000000000e+00
+453 446 -5.1132920000000e-04
+446 447  1.0000000000000e+00
+453 447 -9.5438870000000e-01
+447 448  1.0050250000000e+00
+454 448 -3.4351900000000e-03
+448 449  1.0028740000000e+00
+454 449 -4.3016970000000e-02
+449 450  1.0013870000000e+00
+454 450 -9.5354780000000e-01
+450 451  1.0000000000000e+00
+453 451 -4.9455600000000e-05
+451 452  1.0000000000000e+00
+453 452 -2.1775570000000e-03
+452 453  1.0000000000000e+00
+453 453 -4.2871530000000e-02
+453 454  1.0000000000000e+00
+455 454 -1.0000000000000e+00
+466 454  1.5000000000000e+00
+478 454  5.0000000000000e-01
+454 455  1.0000000000000e+00
+456 455 -3.1622000000000e+05
+459 455 -1.2132580000000e+04
+460 455 -1.0000000000000e+00
+466 455 -2.0451810000000e+04
+477 455  9.1527510000000e+03
+455 456  9.1463570000000e+00
+457 456  3.7734920000000e-03
+456 457  2.2487060000000e+03
+457 457 -1.2505330000000e-01
+457 458  6.7588380000000e-02
+458 458  6.5087120000000e+01
+466 458 -1.8859040000000e-01
+458 459 -9.1527510000000e+03
+460 459  7.5439430000000e-01
+476 459 -9.1527510000000e+03
+477 459 -6.9047830000000e+03
+459 460  1.0000000000000e+00
+466 460  1.8569290000000e-01
+478 460 -5.0000000000000e-01
+460 461  1.9167940000000e-04
+466 461  2.6684520000000e+00
+478 461  8.8948400000000e-01
+266 462  5.2397100000000e-01
+269 462  2.5902730000000e+00
+267 463  1.2090360000000e-01
+270 463  1.0000000000000e+00
+268 464  3.6607730000000e-01
+271 464  1.8323330000000e-02
+288 465  5.3070830000000e-01
+291 465  2.6120320000000e+00
+289 466  1.2143810000000e-01
+292 466  1.0000000000000e+00
+290 467  3.6327480000000e-01
+293 467  1.9398480000000e-02
+310 468  5.3114850000000e-01
+313 468  2.6134470000000e+00
+311 469  1.2147310000000e-01
+314 469  1.0000000000000e+00
+312 470  3.6309170000000e-01
+315 470  1.9470450000000e-02
+332 471  5.3131620000000e-01
+335 471  2.6139860000000e+00
+333 472  1.2148640000000e-01
+336 472  1.0000000000000e+00
+334 473  3.6302190000000e-01
+337 473  1.9497930000000e-02
+354 474  5.3753340000000e-01
+357 474  2.6338800000000e+00
+355 475  1.2197960000000e-01
+358 475  1.0000000000000e+00
+356 476  3.6043580000000e-01
+359 476  2.0538460000000e-02
+376 477  7.1092830000000e-01
+379 477  3.1304670000000e+00
+377 478  1.3573580000000e-01
+380 478  1.0000000000000e+00
+378 479  2.8830910000000e-01
+381 479  7.1489880000000e-02
--- a/examples/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/examples/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,84 +1,9 @@
 %canon_reldir%_EXTRA_DIST =
 
-%canon_reldir%_CLEANFILES =
-%canon_reldir%_DISTCLEANFILES =
-%canon_reldir%_MAINTAINERCLEANFILES =
-
-%canon_reldir%_data_SRC = \
-   %reldir%/data/penny.mat
-
-octdata_DATA += \
-  $(%canon_reldir%_data_SRC)
-
-%canon_reldir%_code_SRC = \
-  %reldir%/code/@FIRfilter/FIRfilter.m \
-  %reldir%/code/@FIRfilter/FIRfilter_aggregation.m \
-  %reldir%/code/@FIRfilter/display.m \
-  %reldir%/code/@FIRfilter/subsasgn.m \
-  %reldir%/code/@FIRfilter/subsref.m \
-  %reldir%/code/@polynomial/disp.m \
-  %reldir%/code/@polynomial/double.m \
-  %reldir%/code/@polynomial/end.m \
-  %reldir%/code/@polynomial/get.m \
-  %reldir%/code/@polynomial/mtimes.m \
-  %reldir%/code/@polynomial/numel.m \
-  %reldir%/code/@polynomial/plot.m \
-  %reldir%/code/@polynomial/polynomial.m \
-  %reldir%/code/@polynomial/polynomial_superiorto.m \
-  %reldir%/code/@polynomial/polyval.m \
-  %reldir%/code/@polynomial/roots.m \
-  %reldir%/code/@polynomial/set.m \
-  %reldir%/code/@polynomial/subsasgn.m \
-  %reldir%/code/@polynomial/subsref.m \
-  %reldir%/code/addtwomatrices.cc \
-  %reldir%/code/celldemo.cc \
-  %reldir%/code/embedded.cc \
-  %reldir%/code/fortrandemo.cc \
-  %reldir%/code/fortransub.f \
-  %reldir%/code/funcdemo.cc \
-  %reldir%/code/globaldemo.cc \
-  %reldir%/code/helloworld.cc \
-  %reldir%/code/make_int.cc \
-  %reldir%/code/mex_demo.c \
-  %reldir%/code/mycell.c \
-  %reldir%/code/myfeval.c \
-  %reldir%/code/myfevalf.f \
-  %reldir%/code/myfunc.c \
-  %reldir%/code/myhello.c \
-  %reldir%/code/mypow2.c \
-  %reldir%/code/myprop.c \
-  %reldir%/code/myset.c \
-  %reldir%/code/mysparse.c \
-  %reldir%/code/mystring.c \
-  %reldir%/code/mystruct.c \
-  %reldir%/code/oct_demo.cc \
-  %reldir%/code/oregonator.cc \
-  %reldir%/code/oregonator.m \
-  %reldir%/code/paramdemo.cc \
-  %reldir%/code/polynomial2.m \
-  %reldir%/code/standalone.cc \
-  %reldir%/code/standalonebuiltin.cc \
-  %reldir%/code/stringdemo.cc \
-  %reldir%/code/structdemo.cc \
-  %reldir%/code/unwinddemo.cc
+include %reldir%/code/module.mk
+include %reldir%/data/module.mk
 
 %canon_reldir%_EXTRA_DIST += \
-  $(%canon_reldir%_data_SRC) \
-  $(%canon_reldir%_code_SRC) \
-  %reldir%/code/COPYING \
-  %reldir%/module.mk
+  %reldir%/code/COPYING
 
 EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
-
-CLEANFILES += $(%canon_reldir%_CLEANFILES)
-DISTCLEANFILES += $(%canon_reldir%_DISTCLEANFILES)
-MAINTAINERCLEANFILES += $(%canon_reldir%_MAINTAINERCLEANFILES)
-
-examples-clean:
-	rm -f $(%canon_reldir%_CLEANFILES)
-
-examples-distclean: examples-clean
-	rm -f $(%canon_reldir%_DISTCLEANFILES)
-
-examples-maintainer-clean: examples-distclean
-	rm -f $(%canon_reldir%_MAINTAINERCLEANFILES)
--- a/libgui/default-qt-settings.in	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,559 +0,0 @@
-[General]
-customFileEditor=__default_custom_editor__
-
-[editor]
-showLineNumbers=true
-highlightCurrentLine=true
-codeCompletion=true
-longWindowTitle=false
-restoreSession=false
-savedSessionTabs=@Invalid()
-mru_file_list=@Invalid()
-
-[terminal]
-fontSize=__default_font_size__
-fontName=__default_font__
-cursorType=ibeam
-
-[workspaceview]
-local_collapsed=false
-global_collapsed=false
-persistent_collapsed=false
-column_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2\x12\0\0\0\x5\x1\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x2\0\0\x1\x90\0\0\0\x4\0\0\0\0\0\0\0\x82\0\0\0\x1\0\0\0\0)
-
-[Scintilla]
-Octave\style0\color=0
-Octave\style0\eolfill=false
-Octave\style0\font=__default_font__, __default_font_size__, 0, 0, 0
-Octave\style0\paper=16777215
-Octave\style1\color=43520
-Octave\style1\eolfill=false
-Octave\style1\font=__default_font__, __default_font_size__, 0, 0, 0
-Octave\style1\paper=16777215
-Octave\style2\color=8355584
-Octave\style2\eolfill=false
-Octave\style2\font=__default_font__, __default_font_size__, 0, 0, 0
-Octave\style2\paper=16777215
-Octave\style3\color=11184640
-Octave\style3\eolfill=false
-Octave\style3\font=__default_font__, __default_font_size__, 0, 0, 0
-Octave\style3\paper=16777215
-Octave\style4\color=255
-Octave\style4\eolfill=false
-Octave\style4\font=__default_font__, __default_font_size__, 1, 0, 0
-Octave\style4\paper=16777215
-Octave\style5\color=16755200
-Octave\style5\eolfill=false
-Octave\style5\font=__default_font__, __default_font_size__, 0, 0, 0
-Octave\style5\paper=16777215
-Octave\style6\color=14483456
-Octave\style6\eolfill=false
-Octave\style6\font=__default_font__, __default_font_size__, 0, 0, 0
-Octave\style6\paper=16777215
-Octave\style7\color=0
-Octave\style7\eolfill=false
-Octave\style7\font=__default_font__, __default_font_size__, 0, 0, 0
-Octave\style7\paper=16777215
-Octave\style8\color=16755200
-Octave\style8\eolfill=false
-Octave\style8\font=__default_font__, __default_font_size__, 0, 0, 0
-Octave\style8\paper=16777215
-Octave\defaultcolor=0
-Octave\defaultpaper=16777215
-Octave\defaultfont=__default_font__, __default_font_size__, 0, 0, 0
-Octave\autoindentstyle=-1
-C%2B%2B\style0\color=0
-C%2B%2B\style0\eolfill=false
-C%2B%2B\style0\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style0\paper=16777215
-C%2B%2B\style1\color=43520
-C%2B%2B\style1\eolfill=false
-C%2B%2B\style1\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style1\paper=16777215
-C%2B%2B\style2\color=43520
-C%2B%2B\style2\eolfill=false
-C%2B%2B\style2\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style2\paper=16777215
-C%2B%2B\style3\color=4157503
-C%2B%2B\style3\eolfill=false
-C%2B%2B\style3\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style3\paper=16777215
-C%2B%2B\style4\color=11184640
-C%2B%2B\style4\eolfill=false
-C%2B%2B\style4\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style4\paper=16777215
-C%2B%2B\style5\color=255
-C%2B%2B\style5\eolfill=false
-C%2B%2B\style5\font=__default_font__, __default_font_size__, 1, 0, 0
-C%2B%2B\style5\paper=16777215
-C%2B%2B\style6\color=16733440
-C%2B%2B\style6\eolfill=false
-C%2B%2B\style6\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style6\paper=16777215
-C%2B%2B\style7\color=16733440
-C%2B%2B\style7\eolfill=false
-C%2B%2B\style7\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style7\paper=16777215
-C%2B%2B\style8\color=0
-C%2B%2B\style8\eolfill=false
-C%2B%2B\style8\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style8\paper=16777215
-C%2B%2B\style9\color=8355584
-C%2B%2B\style9\eolfill=false
-C%2B%2B\style9\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style9\paper=16777215
-C%2B%2B\style10\color=16711680
-C%2B%2B\style10\eolfill=false
-C%2B%2B\style10\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style10\paper=16777215
-C%2B%2B\style11\color=0
-C%2B%2B\style11\eolfill=false
-C%2B%2B\style11\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style11\paper=16777215
-C%2B%2B\style12\color=0
-C%2B%2B\style12\eolfill=true
-C%2B%2B\style12\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style12\paper=14729440
-C%2B%2B\style13\color=32512
-C%2B%2B\style13\eolfill=true
-C%2B%2B\style13\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style13\paper=14745568
-C%2B%2B\style14\color=4161343
-C%2B%2B\style14\eolfill=true
-C%2B%2B\style14\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style14\paper=14741728
-C%2B%2B\style15\color=4157503
-C%2B%2B\style15\eolfill=false
-C%2B%2B\style15\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style15\paper=16777215
-C%2B%2B\style16\color=0
-C%2B%2B\style16\eolfill=false
-C%2B%2B\style16\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style16\paper=16777215
-C%2B%2B\style17\color=3170464
-C%2B%2B\style17\eolfill=false
-C%2B%2B\style17\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style17\paper=16777215
-C%2B%2B\style18\color=8405024
-C%2B%2B\style18\eolfill=false
-C%2B%2B\style18\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style18\paper=16777215
-C%2B%2B\style19\color=0
-C%2B%2B\style19\eolfill=false
-C%2B%2B\style19\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style19\paper=16777215
-C%2B%2B\style20\color=8323199
-C%2B%2B\style20\eolfill=false
-C%2B%2B\style20\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style20\paper=16774143
-C%2B%2B\style40\color=11571376
-C%2B%2B\style40\eolfill=false
-C%2B%2B\style40\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style40\paper=16774143
-C%2B%2B\style64\color=12632256
-C%2B%2B\style64\eolfill=false
-C%2B%2B\style64\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style64\paper=16777215
-C%2B%2B\style65\color=9482384
-C%2B%2B\style65\eolfill=false
-C%2B%2B\style65\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style65\paper=16777215
-C%2B%2B\style66\color=9482384
-C%2B%2B\style66\eolfill=false
-C%2B%2B\style66\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style66\paper=16777215
-C%2B%2B\style67\color=13684944
-C%2B%2B\style67\eolfill=false
-C%2B%2B\style67\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style67\paper=16777215
-C%2B%2B\style68\color=9482384
-C%2B%2B\style68\eolfill=false
-C%2B%2B\style68\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style68\paper=16777215
-C%2B%2B\style69\color=9474224
-C%2B%2B\style69\eolfill=false
-C%2B%2B\style69\font=__default_font__, __default_font_size__, 1, 0, 0
-C%2B%2B\style69\paper=16777215
-C%2B%2B\style70\color=11571376
-C%2B%2B\style70\eolfill=false
-C%2B%2B\style70\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style70\paper=16777215
-C%2B%2B\style71\color=11571376
-C%2B%2B\style71\eolfill=false
-C%2B%2B\style71\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style71\paper=16777215
-C%2B%2B\style72\color=12632256
-C%2B%2B\style72\eolfill=false
-C%2B%2B\style72\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style72\paper=16777215
-C%2B%2B\style73\color=11579536
-C%2B%2B\style73\eolfill=false
-C%2B%2B\style73\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style73\paper=16777215
-C%2B%2B\style74\color=11579568
-C%2B%2B\style74\eolfill=false
-C%2B%2B\style74\font=__default_font__, __default_font_size__, 1, 0, 0
-C%2B%2B\style74\paper=16777215
-C%2B%2B\style75\color=11579568
-C%2B%2B\style75\eolfill=false
-C%2B%2B\style75\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style75\paper=16777215
-C%2B%2B\style76\color=0
-C%2B%2B\style76\eolfill=true
-C%2B%2B\style76\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style76\paper=14729440
-C%2B%2B\style77\color=9482384
-C%2B%2B\style77\eolfill=true
-C%2B%2B\style77\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style77\paper=14745568
-C%2B%2B\style78\color=8367999
-C%2B%2B\style78\eolfill=true
-C%2B%2B\style78\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style78\paper=14741728
-C%2B%2B\style79\color=12632256
-C%2B%2B\style79\eolfill=false
-C%2B%2B\style79\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style79\paper=16777215
-C%2B%2B\style80\color=12632256
-C%2B%2B\style80\eolfill=false
-C%2B%2B\style80\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style80\paper=16777215
-C%2B%2B\style81\color=12632256
-C%2B%2B\style81\eolfill=false
-C%2B%2B\style81\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style81\paper=16777215
-C%2B%2B\style82\color=12632256
-C%2B%2B\style82\eolfill=false
-C%2B%2B\style82\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style82\paper=16777215
-C%2B%2B\style83\color=11579568
-C%2B%2B\style83\eolfill=false
-C%2B%2B\style83\font=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\style83\paper=16777215
-C%2B%2B\properties\foldatelse=false
-C%2B%2B\properties\foldcomments=false
-C%2B%2B\properties\foldcompact=true
-C%2B%2B\properties\foldpreprocessor=true
-C%2B%2B\properties\stylepreprocessor=false
-C%2B%2B\properties\dollars=true
-C%2B%2B\properties\highlighthash=false
-C%2B%2B\properties\highlighttriple=false
-C%2B%2B\defaultcolor=0
-C%2B%2B\defaultpaper=16777215
-C%2B%2B\defaultfont=__default_font__, __default_font_size__, 0, 0, 0
-C%2B%2B\autoindentstyle=-1
-Perl\style0\color=8421504
-Perl\style0\eolfill=false
-Perl\style0\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style0\paper=16777215
-Perl\style1\color=16776960
-Perl\style1\eolfill=false
-Perl\style1\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style1\paper=16711680
-Perl\style2\color=43520
-Perl\style2\eolfill=false
-Perl\style2\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style2\paper=16777215
-Perl\style3\color=16384
-Perl\style3\eolfill=true
-Perl\style3\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style3\paper=14745568
-Perl\style4\color=11184640
-Perl\style4\eolfill=false
-Perl\style4\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style4\paper=16777215
-Perl\style5\color=127
-Perl\style5\eolfill=false
-Perl\style5\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style5\paper=16777215
-Perl\style6\color=16755200
-Perl\style6\eolfill=false
-Perl\style6\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style6\paper=16777215
-Perl\style7\color=16755200
-Perl\style7\eolfill=false
-Perl\style7\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style7\paper=16777215
-Perl\style10\color=16711680
-Perl\style10\eolfill=false
-Perl\style10\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style10\paper=16777215
-Perl\style11\color=0
-Perl\style11\eolfill=false
-Perl\style11\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style11\paper=16777215
-Perl\style12\color=0
-Perl\style12\eolfill=false
-Perl\style12\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style12\paper=16769248
-Perl\style13\color=0
-Perl\style13\eolfill=false
-Perl\style13\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style13\paper=16777184
-Perl\style14\color=0
-Perl\style14\eolfill=false
-Perl\style14\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style14\paper=16769279
-Perl\style15\color=0
-Perl\style15\eolfill=false
-Perl\style15\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style15\paper=14737632
-Perl\style17\color=0
-Perl\style17\eolfill=false
-Perl\style17\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style17\paper=10551200
-Perl\style18\color=0
-Perl\style18\eolfill=false
-Perl\style18\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style18\paper=15786112
-Perl\style20\color=16776960
-Perl\style20\eolfill=false
-Perl\style20\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style20\paper=10518656
-Perl\style21\color=6291456
-Perl\style21\eolfill=true
-Perl\style21\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style21\paper=16773336
-Perl\style22\color=0
-Perl\style22\eolfill=false
-Perl\style22\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style22\paper=14536925
-Perl\style23\color=8323199
-Perl\style23\eolfill=true
-Perl\style23\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style23\paper=14536925
-Perl\style24\color=8323199
-Perl\style24\eolfill=true
-Perl\style24\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style24\paper=14536925
-Perl\style25\color=8323199
-Perl\style25\eolfill=true
-Perl\style25\font=__default_font__, __default_font_size__, 0, 1, 0
-Perl\style25\paper=14536925
-Perl\style26\color=8323199
-Perl\style26\eolfill=false
-Perl\style26\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style26\paper=16777215
-Perl\style27\color=8323199
-Perl\style27\eolfill=false
-Perl\style27\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style27\paper=16777215
-Perl\style28\color=16776960
-Perl\style28\eolfill=false
-Perl\style28\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style28\paper=16777215
-Perl\style29\color=0
-Perl\style29\eolfill=false
-Perl\style29\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style29\paper=16777215
-Perl\style30\color=0
-Perl\style30\eolfill=false
-Perl\style30\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style30\paper=16777215
-Perl\style31\color=16384
-Perl\style31\eolfill=true
-Perl\style31\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style31\paper=12648384
-Perl\style40\color=0
-Perl\style40\eolfill=false
-Perl\style40\font=__default_font__, __default_font_size__, 0, 1, 0
-Perl\style40\paper=16777215
-Perl\style41\color=12583104
-Perl\style41\eolfill=false
-Perl\style41\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style41\paper=16777215
-Perl\style42\color=12583104
-Perl\style42\eolfill=true
-Perl\style42\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style42\paper=16773375
-Perl\style43\color=13631488
-Perl\style43\eolfill=false
-Perl\style43\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style43\paper=16777215
-Perl\style44\color=0
-Perl\style44\eolfill=false
-Perl\style44\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style44\paper=15786112
-Perl\style54\color=13631488
-Perl\style54\eolfill=false
-Perl\style54\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style54\paper=16777215
-Perl\style55\color=0
-Perl\style55\eolfill=false
-Perl\style55\font=__default_font__, __default_font_size__, 0, 0, 0
-Perl\style55\paper=15786112
-Perl\style57\color=13631488
-Perl\style57\eolfill=false
-Perl\style57\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style57\paper=10518656
-Perl\style61\color=13631488
-Perl\style61\eolfill=true
-Perl\style61\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style61\paper=14536925
-Perl\style62\color=13631488
-Perl\style62\eolfill=true
-Perl\style62\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style62\paper=14536925
-Perl\style64\color=13631488
-Perl\style64\eolfill=false
-Perl\style64\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style64\paper=16777215
-Perl\style65\color=13631488
-Perl\style65\eolfill=false
-Perl\style65\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style65\paper=10518656
-Perl\style66\color=13631488
-Perl\style66\eolfill=false
-Perl\style66\font=__default_font__, __default_font_size__, 1, 0, 0
-Perl\style66\paper=16777215
-Perl\properties\foldatelse=false
-Perl\properties\foldcomments=false
-Perl\properties\foldcompact=true
-Perl\properties\foldpackages=true
-Perl\properties\foldpodblocks=true
-Perl\defaultcolor=0
-Perl\defaultpaper=16777215
-Perl\defaultfont=__default_font__, __default_font_size__, 0, 0, 0
-Perl\autoindentstyle=-1
-Batch\style0\color=0
-Batch\style0\eolfill=false
-Batch\style0\font=__default_font__, __default_font_size__, 0, 0, 0
-Batch\style0\paper=16777215
-Batch\style1\color=43520
-Batch\style1\eolfill=false
-Batch\style1\font=__default_font__, __default_font_size__, 0, 0, 0
-Batch\style1\paper=16777215
-Batch\style2\color=255
-Batch\style2\eolfill=false
-Batch\style2\font=__default_font__, __default_font_size__, 1, 0, 0
-Batch\style2\paper=16777215
-Batch\style3\color=8323199
-Batch\style3\eolfill=true
-Batch\style3\font=__default_font__, __default_font_size__, 0, 0, 0
-Batch\style3\paper=6316128
-Batch\style4\color=8355584
-Batch\style4\eolfill=false
-Batch\style4\font=__default_font__, __default_font_size__, 0, 0, 0
-Batch\style4\paper=16777215
-Batch\style5\color=127
-Batch\style5\eolfill=false
-Batch\style5\font=__default_font__, __default_font_size__, 1, 0, 0
-Batch\style5\paper=16777215
-Batch\style6\color=8388736
-Batch\style6\eolfill=false
-Batch\style6\font=__default_font__, __default_font_size__, 0, 0, 0
-Batch\style6\paper=16777215
-Batch\style7\color=0
-Batch\style7\eolfill=false
-Batch\style7\font=__default_font__, __default_font_size__, 0, 0, 0
-Batch\style7\paper=16777215
-Batch\defaultcolor=0
-Batch\defaultpaper=16777215
-Batch\defaultfont=__default_font__, __default_font_size__, 0, 0, 0
-Batch\autoindentstyle=-1
-Diff\style0\color=0
-Diff\style0\eolfill=false
-Diff\style0\font=__default_font__, __default_font_size__, 0, 0, 0
-Diff\style0\paper=16777215
-Diff\style1\color=32512
-Diff\style1\eolfill=false
-Diff\style1\font=__default_font__, __default_font_size__, 0, 0, 0
-Diff\style1\paper=16777215
-Diff\style2\color=8355584
-Diff\style2\eolfill=false
-Diff\style2\font=__default_font__, __default_font_size__, 0, 0, 0
-Diff\style2\paper=16777215
-Diff\style3\color=8323072
-Diff\style3\eolfill=false
-Diff\style3\font=__default_font__, __default_font_size__, 0, 0, 0
-Diff\style3\paper=16777215
-Diff\style4\color=8323199
-Diff\style4\eolfill=false
-Diff\style4\font=__default_font__, __default_font_size__, 0, 0, 0
-Diff\style4\paper=16777215
-Diff\style5\color=32639
-Diff\style5\eolfill=false
-Diff\style5\font=__default_font__, __default_font_size__, 0, 0, 0
-Diff\style5\paper=16777215
-Diff\style6\color=127
-Diff\style6\eolfill=false
-Diff\style6\font=__default_font__, __default_font_size__, 0, 0, 0
-Diff\style6\paper=16777215
-Diff\style7\color=8355711
-Diff\style7\eolfill=false
-Diff\style7\font=__default_font__, __default_font_size__, 0, 0, 0
-Diff\style7\paper=16777215
-Diff\defaultcolor=0
-Diff\defaultpaper=16777215
-Diff\defaultfont=__default_font__, __default_font_size__, 0, 0, 0
-Diff\autoindentstyle=-1
-Bash\style0\color=8421504
-Bash\style0\eolfill=false
-Bash\style0\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style0\paper=16777215
-Bash\style1\color=16776960
-Bash\style1\eolfill=false
-Bash\style1\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style1\paper=16711680
-Bash\style2\color=32512
-Bash\style2\eolfill=false
-Bash\style2\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style2\paper=16777215
-Bash\style3\color=43647
-Bash\style3\eolfill=false
-Bash\style3\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style0\paper=16777215
-Bash\style4\color=127
-Bash\style4\eolfill=false
-Bash\style4\font=__default_font__, __default_font_size__, 1, 0, 0
-Bash\style4\paper=16777215
-Bash\style5\color=16755200
-Bash\style5\eolfill=false
-Bash\style5\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style5\paper=16777215
-Bash\style6\color=16755200
-Bash\style6\eolfill=false
-Bash\style6\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style6\paper=16777215
-Bash\style7\color=16711680
-Bash\style7\eolfill=false
-Bash\style7\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style7\paper=16777215
-Bash\style8\color=0
-Bash\style8\eolfill=false
-Bash\style8\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style8\paper=16777215
-Bash\style9\color=0
-Bash\style9\eolfill=false
-Bash\style9\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style9\paper=16769248
-Bash\style10\color=0
-Bash\style10\eolfill=false
-Bash\style10\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style10\paper=16777184
-Bash\style11\color=16776960
-Bash\style11\eolfill=false
-Bash\style11\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style11\paper=10518656
-Bash\style12\color=0
-Bash\style12\eolfill=false
-Bash\style12\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style12\paper=14536925
-Bash\style13\color=8323199
-Bash\style13\eolfill=true
-Bash\style13\font=__default_font__, __default_font_size__, 0, 0, 0
-Bash\style13\paper=14536925
-Bash\properties\foldcomments=false
-Bash\properties\foldcompact=true
-Bash\defaultcolor=0
-Bash\defaultpaper=16777215
-Bash\defaultfont=__default_font__, __default_font_size__, 0, 0, 0
-Bash\autoindentstyle=-1
-Text\style0\color=0
-Text\style0\eolfill=false
-Text\style0\font=__default_font__, __default_font_size__, 0, 0, 0
-Text\style0\paper=16777215
-Text\defaultcolor=0
-Text\defaultpaper=16777215
-Text\defaultfont=__default_font__, __default_font_size__, 0, 0, 0
-Text\autoindentstyle=-1
--- a/libgui/graphics/BaseControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/BaseControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -50,18 +50,30 @@
     if (props.style_is ("edit")
         || props.style_is ("listbox"))
       {
-        p.setColor (QPalette::Base,
-                    Utils::fromRgb (props.get_backgroundcolor_rgb ()));
-        p.setColor (QPalette::Text,
+        Matrix bg_color = props.get_backgroundcolor_rgb ();
+        // Matlab compatibility: Default color is ignored, and rendered as
+        // white ([1.0, 1.0, 1.0]).  See bug #58261.
+        if (bg_color(0) == bg_color(1) && bg_color(0) == bg_color(2)
+            && (std::abs (bg_color(1) - 0.94) < .005))
+          bg_color.fill (1.0);
+
+        p.setColor (QPalette::Active, QPalette::Base,
+                    Utils::fromRgb (bg_color));
+        p.setColor (QPalette::Inactive, QPalette::Base,
+                    Utils::fromRgb (bg_color));
+        p.setColor (QPalette::Active, QPalette::Text,
+                    Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::Text,
                     Utils::fromRgb (props.get_foregroundcolor_rgb ()));
       }
     else if (props.style_is ("popupmenu"))
       {
-        // popumenu (QComboBox) is a listbox with a button, so needs set colors for both
+        // popupmenu (QComboBox) is a listbox with a button.
+        // This requires setting colors for both.
         QColor bcol = Utils::fromRgb (props.get_backgroundcolor_rgb ());
         QColor fcol = Utils::fromRgb (props.get_foregroundcolor_rgb ());
-        QString qss = QString ("background: %1 none;\n"
-                               "color: %2;")
+        QString qss = QString (":enabled { background: %1 none;\n"
+                                          "color: %2; }")
                       .arg(bcol.name ()).arg (fcol.name ());
         w->setStyleSheet(qss);
         return;
@@ -69,9 +81,13 @@
     else if (props.style_is ("radiobutton")
              || props.style_is ("checkbox"))
       {
-        p.setColor (QPalette::Button,
+        p.setColor (QPalette::Active, QPalette::Button,
+                    Utils::fromRgb (props.get_backgroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::Button,
                     Utils::fromRgb (props.get_backgroundcolor_rgb ()));
-        p.setColor (QPalette::WindowText,
+        p.setColor (QPalette::Active, QPalette::WindowText,
+                    Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::WindowText,
                     Utils::fromRgb (props.get_foregroundcolor_rgb ()));
       }
     else if (props.style_is ("pushbutton")
@@ -79,17 +95,21 @@
       {
         QColor bcol = Utils::fromRgb (props.get_backgroundcolor_rgb ());
         QColor fcol = Utils::fromRgb (props.get_foregroundcolor_rgb ());
-        QString qss = QString ("background: %1 none;\n"
-                               "color: %2;")
+        QString qss = QString (":enabled { background: %1 none;\n"
+                                          "color: %2; }")
                       .arg(bcol.name ()).arg (fcol.name ());
         w->setStyleSheet(qss);
         return;
       }
     else
       {
-        p.setColor (QPalette::Window,
+        p.setColor (QPalette::Active, QPalette::Window,
+                    Utils::fromRgb (props.get_backgroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::Window,
                     Utils::fromRgb (props.get_backgroundcolor_rgb ()));
-        p.setColor (QPalette::WindowText,
+        p.setColor (QPalette::Active, QPalette::WindowText,
+                    Utils::fromRgb (props.get_foregroundcolor_rgb ()));
+        p.setColor (QPalette::Inactive, QPalette::WindowText,
                     Utils::fromRgb (props.get_foregroundcolor_rgb ()));
       }
 
@@ -119,7 +139,10 @@
                     octave::math::round (bb(2)), octave::math::round (bb(3)));
     w->setFont (Utils::computeFont<uicontrol> (up, bb(3)));
     updatePalette (up, w);
-    w->setEnabled (up.enable_is ("on"));
+    if (up.enable_is ("inactive"))
+      w->blockSignals (true);
+    else
+      w->setEnabled (up.enable_is ("on"));
     w->setToolTip (Utils::fromStdString (up.get_tooltipstring ()));
     w->setVisible (up.is_visible ());
     m_keyPressHandlerDefined = ! up.get_keypressfcn ().isempty ();
@@ -174,7 +197,16 @@
         break;
 
       case uicontrol::properties::ID_ENABLE:
-        w->setEnabled (up.enable_is ("on"));
+        if (up.enable_is ("inactive"))
+          {
+            w->blockSignals (true);
+            w->setEnabled (true);
+          }
+        else
+          {
+            w->blockSignals (false);
+            w->setEnabled (up.enable_is ("on"));
+          }
         break;
 
       case uicontrol::properties::ID_TOOLTIPSTRING:
--- a/libgui/graphics/ButtonControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ButtonControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -61,8 +61,8 @@
           btn->setChecked (true);
       }
 
-    connect (btn, SIGNAL (clicked (void)), SLOT (clicked (void)));
-    connect (btn, SIGNAL (toggled (bool)), SLOT (toggled (bool)));
+    connect (btn, &QAbstractButton::clicked, this, &ButtonControl::clicked);
+    connect (btn, &QAbstractButton::toggled, this, &ButtonControl::toggled);
   }
 
   ButtonControl::~ButtonControl (void)
--- a/libgui/graphics/ButtonGroup.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ButtonGroup.cc	Sun May 16 09:44:35 2021 +0200
@@ -46,9 +46,10 @@
 #include "qt-graphics-toolkit.h"
 
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 
 #include "interpreter.h"
-#include "ov-struct.h"
+#include "oct-map.h"
 
 namespace QtHandles
 {
@@ -175,14 +176,17 @@
 
     if (pp.is_visible ())
       {
-        QTimer::singleShot (0, frame, SLOT (show (void)));
+        QTimer::singleShot (0, frame, &QFrame::show);
+        // FIXME: What is the intent here?  QButtonGroup::show is not a
+        // member of QButtonGroup.
         QTimer::singleShot (0, buttongroup, SLOT (show (void)));
       }
     else
       frame->hide ();
 
-    connect (m_buttongroup, SIGNAL (buttonClicked (QAbstractButton*)),
-             SLOT (buttonClicked (QAbstractButton*)));
+    connect (m_buttongroup,
+             QOverload<QAbstractButton *>::of (&QButtonGroup::buttonClicked),
+             this, &ButtonGroup::buttonClicked);
   }
 
   ButtonGroup::~ButtonGroup (void)
@@ -464,7 +468,7 @@
   ButtonGroup::addButton (QAbstractButton *btn)
   {
     m_buttongroup->addButton (btn);
-    connect (btn, SIGNAL (toggled (bool)), SLOT (buttonToggled (bool)));
+    connect (btn, &QAbstractButton::toggled, this, &ButtonGroup::buttonToggled);
   }
 
   void
@@ -520,7 +524,7 @@
         eventData.setfield ("NewValue", newValue.as_octave_value ());
         eventData.setfield ("Source", bp.get___myhandle__ ().as_octave_value ());
         eventData.setfield ("EventName", "SelectionChanged");
-        octave_value selectionChangedEventObject (new octave_struct (eventData));
+        octave_value selectionChangedEventObject (eventData);
         emit gh_callback_event (m_handle, "selectionchangedfcn",
                                 selectionChangedEventObject);
       }
--- a/libgui/graphics/Canvas.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/Canvas.cc	Sun May 16 09:44:35 2021 +0200
@@ -371,11 +371,7 @@
 
             r.adjust (-5, -5, 5, 5);
 
-#if defined (HAVE_QMOUSEEVENT_LOCALPOS)
             bool rect_contains_pos = r.contains (event->localPos ());
-#else
-            bool rect_contains_pos = r.contains (event->posF ());
-#endif
             if (rect_contains_pos)
               {
                 currentObj = childObj;
@@ -429,11 +425,7 @@
                 // the axes and still select it.
                 r.adjust (-20, -20, 20, 20);
 
-#if defined (HAVE_QMOUSEEVENT_LOCALPOS)
                 bool rect_contains_pos = r.contains (event->localPos ());
-#else
-                bool rect_contains_pos = r.contains (event->posF ());
-#endif
                 if (rect_contains_pos)
                   axesObj = *it;
               }
@@ -885,7 +877,7 @@
                     props.prepend (figObj.get_handle ().as_octave_value ());
 
                     emit interpreter_event
-                      ([this, props] (octave::interpreter& interp)
+                      ([=] (octave::interpreter& interp)
                        {
                          // INTERPRETER THREAD
 
--- a/libgui/graphics/CheckBoxControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/CheckBoxControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -61,10 +61,37 @@
                                     const graphics_object& go, QCheckBox *box)
     : ButtonControl (oct_obj, interp, go, box)
   {
+    uicontrol::properties& up = properties<uicontrol> ();
+
     box->setAutoFillBackground (true);
+    if (up.enable_is ("inactive"))
+      box->setCheckable (false);
   }
 
   CheckBoxControl::~CheckBoxControl (void)
   { }
 
+  void
+  CheckBoxControl::update (int pId)
+  {
+    uicontrol::properties& up = properties<uicontrol> ();
+    QCheckBox *box = qWidget<QCheckBox> ();
+
+    switch (pId)
+      {
+      case uicontrol::properties::ID_ENABLE:
+        {
+          if (up.enable_is ("inactive"))
+            box->setCheckable (false);
+          else
+            box->setCheckable (true);
+          ButtonControl::update (pId);
+        }
+        break;
+
+      default:
+        ButtonControl::update (pId);
+        break;
+      }
+  }
 };
--- a/libgui/graphics/CheckBoxControl.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/CheckBoxControl.h	Sun May 16 09:44:35 2021 +0200
@@ -50,6 +50,9 @@
     static CheckBoxControl *
     create (octave::base_qobject& oct_qobj, octave::interpreter& interp,
             const graphics_object& go);
+
+  protected:
+    void update (int pId);
   };
 
 }
--- a/libgui/graphics/ContextMenu.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ContextMenu.cc	Sun May 16 09:44:35 2021 +0200
@@ -63,8 +63,8 @@
   {
     xmenu->setAutoFillBackground (true);
 
-    connect (xmenu, SIGNAL (aboutToShow (void)), SLOT (aboutToShow (void)));
-    connect (xmenu, SIGNAL (aboutToHide (void)), SLOT (aboutToHide (void)));
+    connect (xmenu, &QMenu::aboutToShow, this, &ContextMenu::aboutToShow);
+    connect (xmenu, &QMenu::aboutToHide, this, &ContextMenu::aboutToHide);
   }
 
   ContextMenu::~ContextMenu (void)
--- a/libgui/graphics/EditControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/EditControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -85,16 +85,20 @@
 
     uicontrol::properties& up = properties<uicontrol> ();
 
+    if (up.enable_is ("inactive"))
+      edit->setReadOnly (true);
+    else
+      edit->setEnabled (up.enable_is ("on"));
     edit->setText (Utils::fromStdString (up.get_string_string ()));
     edit->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
                                             up.get_verticalalignment ()));
 
-    connect (edit, SIGNAL (textEdited (const QString&)),
-             SLOT (textChanged (void)));
-    connect (edit, SIGNAL (editingFinished (void)),
-             SLOT (editingFinished (void)));
-    connect (edit, SIGNAL (returnPressed (void)),
-             SLOT (returnPressed (void)));
+    connect (edit, &QLineEdit::textEdited,
+             this, &EditControl::textChanged);
+    connect (edit, &QLineEdit::editingFinished,
+             this, &EditControl::editingFinished);
+    connect (edit, &QLineEdit::returnPressed,
+             this, &EditControl::returnPressed);
   }
 
   EditControl::EditControl (octave::base_qobject& oct_qobj,
@@ -117,16 +121,22 @@
 
     uicontrol::properties& up = properties<uicontrol> ();
 
+    if (up.enable_is ("inactive"))
+      edit->setReadOnly (true);
+    else
+      edit->setEnabled (up.enable_is ("on"));
     edit->setAcceptRichText (false);
     edit->setPlainText (Utils::fromStringVector
                         (up.get_string_vector ()).join ("\n"));
+    edit->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
+                                            up.get_verticalalignment ()));
 
-    connect (edit, SIGNAL (textChanged (void)),
-             SLOT (textChanged (void)));
-    connect (edit, SIGNAL (editingFinished (void)),
-             SLOT (editingFinished (void)));
-    connect (edit, SIGNAL (returnPressed (void)),
-             SLOT (returnPressed (void)));
+    connect (edit, &TextEdit::textChanged,
+             this, &EditControl::textChanged);
+    connect (edit, &TextEdit::editingFinished,
+             this, &EditControl::editingFinished);
+    connect (edit, &TextEdit::returnPressed,
+             this, &EditControl::returnPressed);
   }
 
   EditControl::~EditControl (void)
@@ -177,6 +187,16 @@
                                                 up.get_verticalalignment ()));
         return true;
 
+      case uicontrol::properties::ID_ENABLE:
+        if (up.enable_is ("inactive"))
+          edit->setReadOnly (true);
+        else
+          {
+            edit->setReadOnly (false);
+            edit->setEnabled (up.enable_is ("on"));
+          }
+        return true;
+
       case uicontrol::properties::ID_MIN:
       case uicontrol::properties::ID_MAX:
         if ((up.get_max () - up.get_min ()) > 1)
@@ -208,6 +228,22 @@
                             (up.get_string_vector ()).join ("\n"));
         return true;
 
+      case uicontrol::properties::ID_HORIZONTALALIGNMENT:
+      case uicontrol::properties::ID_VERTICALALIGNMENT:
+        edit->setAlignment (Utils::fromHVAlign (up.get_horizontalalignment (),
+                                                up.get_verticalalignment ()));
+        return true;
+
+      case uicontrol::properties::ID_ENABLE:
+        if (up.enable_is ("inactive"))
+          edit->setReadOnly (true);
+        else
+          {
+            edit->setReadOnly (false);
+            edit->setEnabled (up.enable_is ("on"));
+          }
+        return true;
+
       case uicontrol::properties::ID_MIN:
       case uicontrol::properties::ID_MAX:
         if ((up.get_max () - up.get_min ()) <= 1)
--- a/libgui/graphics/Figure.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/Figure.cc	Sun May 16 09:44:35 2021 +0200
@@ -180,13 +180,12 @@
     // Visibility
     update (figure::properties::ID_VISIBLE);
 
-    connect (this, SIGNAL (asyncUpdate (void)),
-             this, SLOT (updateContainer (void)));
+    connect (this, &Figure::asyncUpdate, this, &Figure::updateContainer);
 
     // Register for the signal that indicates when a window has moved
     // to a different screen
-    connect (win, SIGNAL (figureWindowShown ()),
-             this, SLOT (figureWindowShown ()));
+    connect (win, &FigureWindow::figureWindowShown,
+             this, &Figure::figureWindowShown);
 
     win->addReceiver (this);
     m_container->addReceiver (this);
@@ -406,7 +405,7 @@
       case figure::properties::ID_VISIBLE:
         if (fp.is_visible ())
           {
-            QTimer::singleShot (0, win, SLOT (show ()));
+            QTimer::singleShot (0, win, &QMainWindow::show);
             if (! fp.is___gl_window__ ())
               {
                 gh_manager& gh_mgr = m_interpreter.get_gh_manager ();
@@ -868,8 +867,7 @@
     figure::properties& fp = properties<figure> ();
     fp.set___device_pixel_ratio__ (screen->devicePixelRatio ());
 
-    connect (window, SIGNAL (screenChanged (QScreen*)),
-             this, SLOT (screenChanged (QScreen*)));
+    connect (window, &QWindow::screenChanged, this, &Figure::screenChanged);
 #endif
   }
 
--- a/libgui/graphics/FigureWindow.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/FigureWindow.cc	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
     : FigureWindowBase (xparent)
   {
     // set icon from application resources
-    setWindowIcon (QIcon (":/actions/icons/logo.png"));
+    setWindowIcon (QIcon (":/actions/icons/graphic_logo_Figure.png"));
   }
 
   FigureWindow::~FigureWindow (void)
--- a/libgui/graphics/GLCanvas.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/GLCanvas.cc	Sun May 16 09:44:35 2021 +0200
@@ -188,10 +188,9 @@
         catch (octave::execution_exception& ee)
           {
             emit interpreter_event
-              ([ee] (void)
+              ([=] (void)
                {
                  // INTERPRETER THREAD
-
                  throw ee;
                });
           }
--- a/libgui/graphics/ListBoxControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ListBoxControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -124,12 +124,12 @@
 
     list->viewport ()->installEventFilter (this);
 
-    connect (list, SIGNAL (itemSelectionChanged (void)),
-             SLOT (itemSelectionChanged (void)));
-    connect (list, SIGNAL (activated (const QModelIndex &)),
-             SLOT (itemActivated (const QModelIndex &)));
-    connect (list, SIGNAL (itemPressed (QListWidgetItem*)),
-             SLOT (itemPressed (QListWidgetItem*)));
+    connect (list, &QListWidget::itemSelectionChanged,
+             this, &ListBoxControl::itemSelectionChanged);
+    connect (list, &QListWidget::activated,
+             this, &ListBoxControl::itemActivated);
+    connect (list, &QListWidget::itemPressed,
+             this, &ListBoxControl::itemPressed);
   }
 
   ListBoxControl::~ListBoxControl (void)
--- a/libgui/graphics/Menu.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/Menu.cc	Sun May 16 09:44:35 2021 +0200
@@ -161,7 +161,7 @@
           }
       }
 
-    connect (action, SIGNAL (triggered (bool)), SLOT (actionTriggered (void)));
+    connect (action, &QAction::triggered, this, &Menu::actionTriggered);
   }
 
   Menu::~Menu (void)
@@ -281,8 +281,7 @@
         _menu = new QMenu (action->parentWidget ());
         action->setMenu (_menu);
         action->setShortcut (QKeySequence ());
-        connect (_menu, SIGNAL (aboutToShow (void)),
-                 this, SLOT (actionHovered (void)));
+        connect (_menu, &QMenu::aboutToShow, this, &Menu::actionHovered);
       }
 
     return _menu;
--- a/libgui/graphics/Object.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/Object.cc	Sun May 16 09:44:35 2021 +0200
@@ -71,8 +71,8 @@
       {
         m_qobject->setProperty ("QtHandles::Object",
                                 QVariant::fromValue<void*> (this));
-        connect (m_qobject, SIGNAL (destroyed (QObject*)),
-                 SLOT (objectDestroyed (QObject*)));
+        connect (m_qobject, &QObject::destroyed,
+                 this, &Object::objectDestroyed);
       }
   }
 
--- a/libgui/graphics/ObjectProxy.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ObjectProxy.cc	Sun May 16 09:44:35 2021 +0200
@@ -53,24 +53,24 @@
       {
         if (m_object)
           {
-            disconnect (this, SIGNAL (sendUpdate (int)),
-                        m_object, SLOT (slotUpdate (int)));
-            disconnect (this, SIGNAL (sendRedraw (void)),
-                        m_object, SLOT (slotRedraw (void)));
-            disconnect (this, SIGNAL (sendShow (void)),
-                        m_object, SLOT (slotShow (void)));
+            disconnect (this, &ObjectProxy::sendUpdate,
+                        m_object, &Object::slotUpdate);
+            disconnect (this, &ObjectProxy::sendRedraw,
+                        m_object, &Object::slotRedraw);
+            disconnect (this, &ObjectProxy::sendShow,
+                        m_object, &Object::slotShow);
           }
 
         m_object = obj;
 
         if (m_object)
           {
-            connect (this, SIGNAL (sendUpdate (int)),
-                     m_object, SLOT (slotUpdate (int)));
-            connect (this, SIGNAL (sendRedraw (void)),
-                     m_object, SLOT (slotRedraw (void)));
-            connect (this, SIGNAL (sendShow (void)),
-                     m_object, SLOT (slotShow (void)));
+            connect (this, &ObjectProxy::sendUpdate,
+                     m_object, &Object::slotUpdate);
+            connect (this, &ObjectProxy::sendRedraw,
+                     m_object, &Object::slotRedraw);
+            connect (this, &ObjectProxy::sendShow,
+                     m_object, &Object::slotShow);
           }
       }
   }
--- a/libgui/graphics/Panel.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/Panel.cc	Sun May 16 09:44:35 2021 +0200
@@ -164,7 +164,7 @@
       m_container->canvas (m_handle)->addEventMask (Canvas::KeyRelease);
 
     if (pp.is_visible ())
-      QTimer::singleShot (0, frame, SLOT (show (void)));
+      QTimer::singleShot (0, frame, &QFrame::show);
     else
       frame->hide ();
   }
--- a/libgui/graphics/PopupMenuControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/PopupMenuControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -34,6 +34,7 @@
 #include "QtHandlesUtils.h"
 
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 
 namespace QtHandles
 {
@@ -69,8 +70,8 @@
 
     update (uicontrol::properties::ID_VALUE);
 
-    connect (box, SIGNAL (activated (int)),
-             SLOT (currentIndexChanged (int)));
+    connect (box, QOverload<int>::of (&QComboBox::activated),
+             this, &PopupMenuControl::currentIndexChanged);
   }
 
   PopupMenuControl::~PopupMenuControl (void)
--- a/libgui/graphics/PushButtonControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/PushButtonControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -71,6 +71,7 @@
     QImage img = Utils::makeImageFromCData (cdat,
                                             cdat.columns (), cdat.rows ());
     btn->setIcon (QIcon (QPixmap::fromImage (img)));
+    btn->setIconSize (QSize (cdat.columns (), cdat.rows ()));
   }
 
   PushButtonControl::~PushButtonControl (void)
@@ -91,6 +92,7 @@
                                                   cdat.rows (),
                                                   cdat.columns ());
           btn->setIcon (QIcon (QPixmap::fromImage (img)));
+          btn->setIconSize (QSize (cdat.columns (), cdat.rows ()));
         }
         break;
 
--- a/libgui/graphics/PushTool.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/PushTool.cc	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
                       const graphics_object& go, QAction *action)
     : ToolBarButton<uipushtool> (oct_qobj, interp, go, action)
   {
-    connect (action, SIGNAL (triggered (bool)), this, SLOT (clicked (void)));
+    connect (action, &QAction::triggered, this, &PushTool::clicked);
   }
 
   PushTool::~PushTool (void)
--- a/libgui/graphics/QtHandlesUtils.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/QtHandlesUtils.cc	Sun May 16 09:44:35 2021 +0200
@@ -288,8 +288,12 @@
           int w = qMin (dv(1), static_cast<octave_idx_type> (width));
           int h = qMin (dv(0), static_cast<octave_idx_type> (height));
 
-          int x_off = (w < width ? (width - w) / 2 : 0);
-          int y_off = (h < height ? (height - h) / 2 : 0);
+          // If size mismatch, take data from center of CDATA and
+          // place in in center of QImage.
+          int x_img_off = (w < width ? (width - w) / 2 : 0);
+          int y_img_off = (h < height ? (height - h) / 2 : 0);
+          int x_cdat_off = (dv(1) > w ? (dv(1) - w) / 2 : 0);
+          int y_cdat_off = (dv(0) > h ? (dv(0) - h) / 2 : 0);
 
           QImage img (width, height, QImage::Format_ARGB32);
           img.fill (qRgba (0, 0, 0, 0));
@@ -298,23 +302,25 @@
             {
               uint8NDArray d = v.uint8_array_value ();
 
-              for (int i = 0; i < w; i++)
-                for (int j = 0; j < h; j++)
+              for (int i = x_cdat_off; i < w + x_cdat_off; i++)
+                for (int j = y_cdat_off; j < h + y_cdat_off; j++)
                   {
                     int r = d(j, i, 0);
                     int g = d(j, i, 1);
                     int b = d(j, i, 2);
                     int a = 255;
 
-                    img.setPixel (x_off + i, y_off + j, qRgba (r, g, b, a));
+                    img.setPixel (x_img_off + i - x_cdat_off,
+                                  y_img_off + j - y_cdat_off,
+                                  qRgba (r, g, b, a));
                   }
             }
           else if (v.is_single_type ())
             {
               FloatNDArray f = v.float_array_value ();
 
-              for (int i = 0; i < w; i++)
-                for (int j = 0; j < h; j++)
+              for (int i = x_cdat_off; i < w + x_cdat_off; i++)
+                for (int j = y_cdat_off; j < h + y_cdat_off; j++)
                   {
                     float r = f(j, i, 0);
                     float g = f(j, i, 1);
@@ -322,7 +328,8 @@
                     int a = (octave::math::isnan (r) || octave::math::isnan (g)
                              || octave::math::isnan (b) ? 0 : 255);
 
-                    img.setPixel (x_off + i, y_off + j,
+                    img.setPixel (x_img_off + i - x_cdat_off,
+                                  y_img_off + j - y_cdat_off,
                                   qRgba (octave::math::round (r * 255),
                                          octave::math::round (g * 255),
                                          octave::math::round (b * 255),
@@ -333,8 +340,8 @@
             {
               NDArray d = v.array_value ();
 
-              for (int i = 0; i < w; i++)
-                for (int j = 0; j < h; j++)
+              for (int i = x_cdat_off; i < w + x_cdat_off; i++)
+                for (int j = y_cdat_off; j < h + y_cdat_off; j++)
                   {
                     double r = d(j, i, 0);
                     double g = d(j, i, 1);
@@ -342,7 +349,8 @@
                     int a = (octave::math::isnan (r) || octave::math::isnan (g)
                              || octave::math::isnan (b) ? 0 : 255);
 
-                    img.setPixel (x_off + i, y_off + j,
+                    img.setPixel (x_img_off + i - x_cdat_off,
+                                  y_img_off + j - y_cdat_off,
                                   qRgba (octave::math::round (r * 255),
                                          octave::math::round (g * 255),
                                          octave::math::round (b * 255),
@@ -394,12 +402,7 @@
 
       // We assume a standard mouse with 15 degree steps and Qt returns
       // 1/8 of a degree.
-#if defined (HAVE_QWHEELEVENT_ANGLEDELTA)
       int ydelta = -(event->angleDelta().y ());
-#else
-      int ydelta = (event->orientation () == Qt::Vertical
-                    ? -(event->delta ()) : 0);
-#endif
       retval.setfield ("VerticalScrollCount", octave_value (ydelta / 120));
 
       // FIXME: Is there any way to access the number of lines a scroll step
--- a/libgui/graphics/RadioButtonControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/RadioButtonControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -69,11 +69,39 @@
     if (btnGroup)
       btnGroup->addButton (radio);
 
+    uicontrol::properties& up = properties<uicontrol> ();
+
     radio->setAutoFillBackground (true);
     radio->setAutoExclusive (false);
+    if (up.enable_is ("inactive"))
+      radio->setCheckable (false);
   }
 
   RadioButtonControl::~RadioButtonControl (void)
   { }
 
+  void
+  RadioButtonControl::update (int pId)
+  {
+    uicontrol::properties& up = properties<uicontrol> ();
+    QRadioButton *btn = qWidget<QRadioButton> ();
+
+    switch (pId)
+      {
+      case uicontrol::properties::ID_ENABLE:
+        {
+          if (up.enable_is ("inactive"))
+            btn->setCheckable (false);
+          else
+            btn->setCheckable (true);
+          ButtonControl::update (pId);
+        }
+        break;
+
+      default:
+        ButtonControl::update (pId);
+        break;
+      }
+  }
+
 };
--- a/libgui/graphics/RadioButtonControl.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/RadioButtonControl.h	Sun May 16 09:44:35 2021 +0200
@@ -50,6 +50,9 @@
     static RadioButtonControl * create (octave::base_qobject& oct_qobj,
                                         octave::interpreter& interp,
                                         const graphics_object& go);
+
+  protected:
+    void update (int pId);
   };
 
 }
--- a/libgui/graphics/SliderControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/SliderControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -90,7 +90,8 @@
                                                * RANGE_INT_MAX));
       }
 
-    connect (slider, SIGNAL (valueChanged (int)), SLOT (valueChanged (int)));
+    connect (slider, &QAbstractSlider::valueChanged,
+             this, &SliderControl::valueChanged);
   }
 
   SliderControl::~SliderControl (void)
--- a/libgui/graphics/Table.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/Table.cc	Sun May 16 09:44:35 2021 +0200
@@ -52,10 +52,10 @@
 
 #include "graphics.h"
 #include "interpreter.h"
+#include "oct-map.h"
 #include "oct-stream.h"
 #include "oct-string.h"
 #include "oct-strstrm.h"
-#include "ov-struct.h"
 
 namespace QtHandles
 {
@@ -479,12 +479,12 @@
     m_tableWidget->installEventFilter (this);
 
 
-    connect (m_tableWidget, SIGNAL (itemChanged (QTableWidgetItem*)),
-             SLOT (itemChanged (QTableWidgetItem*)));
-    connect (m_tableWidget, SIGNAL (cellClicked (int, int)),
-             SLOT (cellClicked (int, int)));
-    connect (m_tableWidget, SIGNAL (itemSelectionChanged (void)),
-             SLOT (itemSelectionChanged (void)));
+    connect (m_tableWidget, &QTableWidget::itemChanged,
+             this, &Table::itemChanged);
+    connect (m_tableWidget, &QTableWidget::cellClicked,
+             this, &Table::cellClicked);
+    connect (m_tableWidget, &QTableWidget::itemSelectionChanged,
+             this, &Table::itemSelectionChanged);
   }
 
   Table::~Table (void) { }
@@ -505,8 +505,7 @@
           }
         octave_scalar_map eventData;
         eventData.setfield ("Indices", indices);
-        octave_value cellSelectionCallbackEventObject =
-          octave_value (new octave_struct (eventData));
+        octave_value cellSelectionCallbackEventObject (eventData);
         emit gh_callback_event (m_handle, "cellselectioncallback",
                                 cellSelectionCallbackEventObject);
       }
@@ -553,8 +552,7 @@
         eventData.setfield ("EditData", edit_data);
         eventData.setfield ("Error", error);
 
-        octave_value cellEditCallbackEventObject =
-          octave_value (new octave_struct (eventData));
+        octave_value cellEditCallbackEventObject (eventData);
 
         emit gh_callback_event (m_handle, "celleditcallback",
                                 cellEditCallbackEventObject);
@@ -1323,11 +1321,7 @@
                                      : QAbstractItemView::NoSelection);
 
     // Set rearrangeablecolumns
-    #if defined (HAVE_QT4)
-      m_tableWidget->horizontalHeader ()->setMovable (enabled && rearrangeableColumns);
-    #elif defined (HAVE_QT5)
-      m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
-    #endif
+    m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
     m_tableWidget->horizontalHeader ()->setDragEnabled (enabled && rearrangeableColumns);
     m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
 
@@ -1506,11 +1500,7 @@
     bool rearrangeableColumns = tp.is_rearrangeablecolumns ();
     bool enabled = tp.is_enable ();
 
-  #if defined (HAVE_QT4)
-    m_tableWidget->horizontalHeader ()->setMovable (enabled && rearrangeableColumns);
-  #elif defined (HAVE_QT5)
     m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
-  #endif
     m_tableWidget->horizontalHeader ()->setDragEnabled (enabled && rearrangeableColumns);
     m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
   }
--- a/libgui/graphics/ToggleButtonControl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ToggleButtonControl.cc	Sun May 16 09:44:35 2021 +0200
@@ -77,6 +77,7 @@
     QImage img = Utils::makeImageFromCData (cdat,
                                             cdat.columns (), cdat.rows ());
     btn->setIcon (QIcon (QPixmap::fromImage (img)));
+    btn->setIconSize (QSize (cdat.columns (), cdat.rows ()));
   }
 
   ToggleButtonControl::~ToggleButtonControl (void)
@@ -97,6 +98,7 @@
                                                   cdat.rows (),
                                                   cdat.columns ());
           btn->setIcon (QIcon (QPixmap::fromImage (img)));
+          btn->setIconSize (QSize (cdat.columns (), cdat.rows ()));
         }
         break;
 
--- a/libgui/graphics/ToggleTool.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ToggleTool.cc	Sun May 16 09:44:35 2021 +0200
@@ -64,8 +64,7 @@
     action->setCheckable (true);
     action->setChecked (tp.is_state ());
 
-    connect (action, SIGNAL (toggled (bool)),
-             this, SLOT (triggered (bool)));
+    connect (action, &QAction::toggled, this, &ToggleTool::triggered);
   }
 
   ToggleTool::~ToggleTool (void)
--- a/libgui/graphics/ToolBar.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ToolBar.cc	Sun May 16 09:44:35 2021 +0200
@@ -150,7 +150,7 @@
                   if (xevent->type () == QEvent::ActionAdded)
                     {
                       if (bar->actions ().size () == 2)
-                        QTimer::singleShot (0, this, SLOT (hideEmpty (void)));
+                        QTimer::singleShot (0, this, &ToolBar::hideEmpty);
                     }
                   else
                     {
--- a/libgui/graphics/ToolBarButton.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/ToolBarButton.cc	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
     action->setVisible (tp.is_visible ());
 
     // Get the icon data from cdata or as a named icon
-    QImage img = Utils::makeImageFromCData (tp.get_cdata (), 32, 32);
+    QImage img = Utils::makeImageFromCData (tp.get_cdata (), 24, 24);
 
     if (img.width () == 0)
       {
@@ -104,7 +104,7 @@
       case T::properties::ID_CDATA:
         {
           // Get the icon data from cdata or as a named icon
-          QImage img = Utils::makeImageFromCData (tp.get_cdata (), 32, 32);
+          QImage img = Utils::makeImageFromCData (tp.get_cdata (), 24, 24);
 
           if (img.width () == 0)
             {
--- a/libgui/graphics/annotation-dialog.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/annotation-dialog.cc	Sun May 16 09:44:35 2021 +0200
@@ -64,20 +64,20 @@
     restoreGeometry (settings->value (gp_annotation_geometry).toByteArray ());
 
   // connect signals
-  connect (ui->button_box, SIGNAL (clicked (QAbstractButton *)),
-           this, SLOT (button_clicked (QAbstractButton *)));
+  connect (ui->button_box, &QDialogButtonBox::clicked,
+           this, &annotation_dialog::button_clicked);
 
-  connect (ui->edit_string, SIGNAL (textChanged (const QString&)),
-           this, SLOT (edit_string_changed (const QString&)));
+  connect (ui->edit_string, &QLineEdit::textChanged,
+           this, &annotation_dialog::edit_string_changed);
 
-  connect (ui->btn_color, SIGNAL (clicked ()),
-           this, SLOT (prompt_for_color ()));
+  connect (ui->btn_color, &QPushButton::clicked,
+           this, &annotation_dialog::prompt_for_color);
 
-  connect (ui->btn_background_color, SIGNAL (clicked ()),
-           this, SLOT (prompt_for_color ()));
+  connect (ui->btn_background_color, &QPushButton::clicked,
+           this, &annotation_dialog::prompt_for_color);
 
-  connect (ui->btn_edge_color, SIGNAL (clicked ()),
-           this, SLOT (prompt_for_color ()));
+  connect (ui->btn_edge_color, &QPushButton::clicked,
+           this, &annotation_dialog::prompt_for_color);
 
   // set gui element to default values
   ui->cb_fit_box_to_text->setChecked (true);
--- a/libgui/graphics/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -128,7 +128,7 @@
   @OCTGUI_DLL_DEFS@ \
   @QT_OPENGL_CPPFLAGS@ \
   -Ilibgui/graphics -I$(srcdir)/libgui/graphics \
-  -Isrc -I$(srcdir)/libgui/src \
+  -Ilibgui/src -I$(srcdir)/libgui/src \
   -Iliboctave \
   -I$(srcdir)/liboctave/array \
   -Iliboctave/numeric -I$(srcdir)/liboctave/numeric \
--- a/libgui/graphics/qt-graphics-toolkit.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/graphics/qt-graphics-toolkit.cc	Sun May 16 09:44:35 2021 +0200
@@ -112,8 +112,8 @@
     // BlockingQueuedConnection. After the signal is emitted, the interpreter
     // thread is locked until the slot has returned.
 
-    connect (this, SIGNAL (create_object_signal (double)),
-             this, SLOT (create_object (double)),
+    connect (this, &qt_graphics_toolkit::create_object_signal,
+             this, &qt_graphics_toolkit::create_object,
              Qt::BlockingQueuedConnection);
   }
 
@@ -139,7 +139,7 @@
 
         gh_mgr.unlock ();
 
-        Logger::debug ("qt_graphics_toolkit::initialize %s from thread %08x",
+        Logger::debug ("qt_graphics_toolkit::initialize %s from thread %p",
                        go.type ().c_str (), QThread::currentThreadId ());
 
         ObjectProxy *proxy = new ObjectProxy ();
@@ -173,7 +173,7 @@
         || pId == base_properties::ID___MODIFIED__)
       return;
 
-    Logger::debug ("qt_graphics_toolkit::update %s(%d) from thread %08x",
+    Logger::debug ("qt_graphics_toolkit::update %s(%d) from thread %p",
                    go.type ().c_str (), pId, QThread::currentThreadId ());
 
     ObjectProxy *proxy = toolkitObjectProxy (go);
@@ -205,7 +205,7 @@
 
     gh_mgr.unlock ();
 
-    Logger::debug ("qt_graphics_toolkit::finalize %s from thread %08x",
+    Logger::debug ("qt_graphics_toolkit::finalize %s from thread %p",
                    go.type ().c_str (), QThread::currentThreadId ());
 
     ObjectProxy *proxy = toolkitObjectProxy (go);
@@ -401,7 +401,7 @@
       }
 
     Logger::debug ("qt_graphics_toolkit::create_object: "
-                   "create %s from thread %08x",
+                   "create %s from thread %p",
                    go.type ().c_str (), QThread::currentThreadId ());
 
     Object *obj = nullptr;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/languages/tr_TR.ts	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,6471 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="tr_TR">
+<context>
+    <name>QColorDialog</name>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1378"/>
+        <source>Hu&amp;e:</source>
+        <translation>To&amp;n:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1379"/>
+        <source>&amp;Sat:</source>
+        <translation>&amp;Doygunluk:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1380"/>
+        <source>&amp;Val:</source>
+        <translation>&amp;Değer:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1381"/>
+        <source>&amp;Red:</source>
+        <translation>&amp;Kırmızı:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1382"/>
+        <source>&amp;Green:</source>
+        <translation>&amp;Yeşil:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1383"/>
+        <source>Bl&amp;ue:</source>
+        <translation>M&amp;avi:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1384"/>
+        <source>A&amp;lpha channel:</source>
+        <translation>A&amp;lfa kanalı:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1485"/>
+        <source>Select Color</source>
+        <translation>Renk seç</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1668"/>
+        <source>&amp;Basic colors</source>
+        <translation>&amp;Temel renkler</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1669"/>
+        <source>&amp;Custom colors</source>
+        <translation>&amp;Özel Renkler</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qcolordialog.cpp" line="1670"/>
+        <source>&amp;Add to Custom Colors</source>
+        <translation>&amp;Özel Renkler Ekle</translation>
+    </message>
+</context>
+<context>
+    <name>QDialog</name>
+    <message>
+        <location filename="../../../octave-qt/qdialog.cpp" line="528"/>
+        <source>Done</source>
+        <translation>Tamamlandı</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qdialog.cpp" line="661"/>
+        <source>What&apos;s This?</source>
+        <translation>Bu nedir?</translation>
+    </message>
+</context>
+<context>
+    <name>QDialogButtonBox</name>
+    <message>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="1936"/>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="2382"/>
+        <source>OK</source>
+        <translation>TAMAM</translation>
+    </message>
+    <message>
+        <source>&amp;OK</source>
+        <translation type="vanished">&amp;TAMAM</translation>
+    </message>
+    <message>
+        <source>&amp;Save</source>
+        <translation type="vanished">&amp;Kaydet</translation>
+    </message>
+    <message>
+        <source>&amp;Close</source>
+        <translation type="vanished">&amp;Kapat</translation>
+    </message>
+    <message>
+        <source>Close without Saving</source>
+        <translation type="vanished">Kaydetmeden Kapat</translation>
+    </message>
+    <message>
+        <source>&amp;Cancel</source>
+        <translation type="vanished">&amp;İptal</translation>
+    </message>
+    <message>
+        <source>Don&apos;t Save</source>
+        <translation type="vanished">Kaydetme</translation>
+    </message>
+</context>
+<context>
+    <name>QErrorMessage</name>
+    <message>
+        <location filename="../../../octave-qt/qerrormessage.cpp" line="208"/>
+        <source>Debug Message:</source>
+        <translation>Hata Mesajı:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qerrormessage.cpp" line="211"/>
+        <source>Warning:</source>
+        <translation>Uyarı:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qerrormessage.cpp" line="214"/>
+        <source>Fatal Error:</source>
+        <translation>Önemli Hata:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qerrormessage.cpp" line="422"/>
+        <source>&amp;Show this message again</source>
+        <translation>Bu mesajı tekrar &amp;göster</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qerrormessage.cpp" line="423"/>
+        <source>&amp;OK</source>
+        <translation>&amp;TAMAM</translation>
+    </message>
+</context>
+<context>
+    <name>QFileDialog</name>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="557"/>
+        <location filename="../../../octave-qt/qfiledialog_symbian.cpp" line="192"/>
+        <source>Find Directory</source>
+        <translation>Dizin Bul</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="559"/>
+        <source>Open</source>
+        <translation>Aç</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="561"/>
+        <source>Save As</source>
+        <translation>Farklı Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="576"/>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1126"/>
+        <source>All Files (*)</source>
+        <translation>Tüm Dosyalar (*)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="586"/>
+        <source>Show </source>
+        <translation>Göster </translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="590"/>
+        <source>&amp;Rename</source>
+        <translation>&amp;Yeniden Adlandır</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="591"/>
+        <source>&amp;Delete</source>
+        <translation>&amp;Sil</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="592"/>
+        <source>Show &amp;hidden files</source>
+        <translation>&amp;Gizli dosyaları göster</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="593"/>
+        <source>&amp;New Folder</source>
+        <translation>&amp;Yeni Klasör</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="598"/>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1348"/>
+        <source>Directory:</source>
+        <translation>Dizin:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="600"/>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1354"/>
+        <source>File &amp;name:</source>
+        <translation>Dosya &amp;adı:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1341"/>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1396"/>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="2978"/>
+        <source>&amp;Open</source>
+        <translation>&amp;Aç</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1341"/>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1396"/>
+        <source>&amp;Save</source>
+        <translation>&amp;Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1344"/>
+        <source>Directories</source>
+        <translation>Dizinler</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1351"/>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="1394"/>
+        <source>&amp;Choose</source>
+        <translation>&amp;Seç</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="2183"/>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="3049"/>
+        <source>%1
+Directory not found.
+Please verify the correct directory name was given.</source>
+        <translation>%1
+Dizin bulunamadı.
+Lütfen doğru dizin adının verildiğini doğrulayın.</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="2217"/>
+        <source>%1 already exists.
+Do you want to replace it?</source>
+        <translation>%1 zaten var.
+Değiştirmek istiyor musun?</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="2237"/>
+        <source>%1
+File not found.
+Please verify the correct file name was given.</source>
+        <translation>%1
+Dosya bulunamadı.
+Lütfen doğru dosya adının verildiğini doğrulayın.</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="2699"/>
+        <source>New Folder</source>
+        <translation>Yeni Klasör</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="2827"/>
+        <source>&apos;%1&apos; is write protected.
+Do you want to delete it anyway?</source>
+        <translation>&apos;%1&apos; yazma korumalı.
+Yine de silmek istiyor musunuz?</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="2832"/>
+        <source>Are sure you want to delete &apos;%1&apos;?</source>
+        <translation>&apos;%1&apos; i silmek istediğinizden emin misiniz?</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="2847"/>
+        <source>Could not delete directory.</source>
+        <translation>Dizin silinemedi.</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog.cpp" line="3256"/>
+        <source>Recent Places</source>
+        <translation>Son gidilen yerler</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfiledialog_win.cpp" line="131"/>
+        <source>All Files (*.*)</source>
+        <translation>Tüm Dosyalar (*.*)</translation>
+    </message>
+</context>
+<context>
+    <name>QFileSystemModel</name>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="763"/>
+        <source>%1 TB</source>
+        <translation>%1 TB</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="765"/>
+        <source>%1 GB</source>
+        <translation>%1 GB</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="767"/>
+        <source>%1 MB</source>
+        <translation>%1 MB</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="769"/>
+        <source>%1 KB</source>
+        <translation>%1 KB</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="770"/>
+        <source>%1 bytes</source>
+        <translation>%1 bayt</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="860"/>
+        <source>Invalid filename</source>
+        <translation>Geçersiz dosya adı</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="861"/>
+        <source>&lt;b&gt;The name &quot;%1&quot; can not be used.&lt;/b&gt;&lt;p&gt;Try using another name, with fewer characters or no punctuations marks.</source>
+        <translation>&lt;b&gt;Bu isim &quot;%1&quot; kullanılamaz.&lt;/b&gt;&lt;p&gt;Daha az karakter içeren veya noktalama işareti içermeyen başka bir ad kullanmayı deneyin.</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="925"/>
+        <source>Name</source>
+        <translation>İsim</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="927"/>
+        <source>Size</source>
+        <translation>Boyut</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="931"/>
+        <source>Kind</source>
+        <comment>Match OS X Finder</comment>
+        <translation>Tür</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="933"/>
+        <source>Type</source>
+        <comment>All other platforms</comment>
+        <translation>Tip</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfilesystemmodel.cpp" line="940"/>
+        <source>Date Modified</source>
+        <translation>Değiştirilme Tarihi</translation>
+    </message>
+</context>
+<context>
+    <name>QFontDialog</name>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="183"/>
+        <source>Select Font</source>
+        <translation>Yazı Tipi Seç</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="768"/>
+        <source>&amp;Font</source>
+        <translation>&amp;Yazı tipi</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="769"/>
+        <source>Font st&amp;yle</source>
+        <translation>Yazı tipi st&amp;ili</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="770"/>
+        <source>&amp;Size</source>
+        <translation>&amp;Boyut</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="774"/>
+        <source>Effects</source>
+        <translation>Efektler</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="776"/>
+        <source>Stri&amp;keout</source>
+        <translation>Alt&amp;çizgili</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="777"/>
+        <source>&amp;Underline</source>
+        <translation>&amp;Altını çizgili</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="778"/>
+        <source>Sample</source>
+        <translation>Örnek</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qfontdialog.cpp" line="779"/>
+        <source>Wr&amp;iting System</source>
+        <translation>Yaz&amp;ma Sistemi</translation>
+    </message>
+</context>
+<context>
+    <name>QHelpSearchQueryWidget</name>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="124"/>
+        <source>Search for:</source>
+        <translation>Aranacak:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="125"/>
+        <source>Previous search</source>
+        <translation>Önceki arama</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="126"/>
+        <source>Next search</source>
+        <translation>Sonraki arama</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="127"/>
+        <source>Search</source>
+        <translation>Ara</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="129"/>
+        <source>Advanced search</source>
+        <translation>Gelişmiş arama</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="130"/>
+        <source>words &lt;B&gt;similar&lt;/B&gt; to:</source>
+        <translation>şuna &lt;B&gt;benzer&lt;/B&gt; kelimeler:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="131"/>
+        <source>&lt;B&gt;without&lt;/B&gt; the words:</source>
+        <translation>&lt;B&gt;kelimeler&lt;/B&gt; olmadan:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="132"/>
+        <source>with &lt;B&gt;exact phrase&lt;/B&gt;:</source>
+        <translation>tam tabiri &lt;B&gt; ile&lt;/B&gt;:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="133"/>
+        <source>with &lt;B&gt;all&lt;/B&gt; of the words:</source>
+        <translation>tüm &lt;B&gt;dahili&lt;/B&gt; kelimeler ile:</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qhelpsearchquerywidget.cpp" line="134"/>
+        <source>with &lt;B&gt;at least one&lt;/B&gt; of the words:</source>
+        <translation>kelimelerin &lt;B&gt; en az biri&lt;/B&gt; ile:</translation>
+    </message>
+</context>
+<context>
+    <name>QInputDialog</name>
+    <message>
+        <location filename="../../../octave-qt/qinputdialog.cpp" line="223"/>
+        <source>Enter a value:</source>
+        <translation>Bir değer girin:</translation>
+    </message>
+</context>
+<context>
+    <name>QMessageBox</name>
+    <message>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="139"/>
+        <source>Show Details...</source>
+        <translation>Ayrıntıları Göster...</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="139"/>
+        <source>Hide Details...</source>
+        <translation>Ayrıntıları Gizle...</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="427"/>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="1272"/>
+        <source>OK</source>
+        <translation>TAMAM</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="1273"/>
+        <source>Help</source>
+        <translation>Yardım</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="1761"/>
+        <source>&lt;h3&gt;About Qt&lt;/h3&gt;&lt;p&gt;This program uses Qt version %1.&lt;/p&gt;</source>
+        <translation>&lt;h3&gt;Qt Hakkında&lt;/h3&gt;&lt;p&gt;Bu program %1 Qt sürümünü kullanıyor.&lt;/p&gt;</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="1766"/>
+        <source>&lt;p&gt;Qt is a C++ toolkit for cross-platform application development.&lt;/p&gt;&lt;p&gt;Qt provides single-source portability across all major desktop operating systems. It is also available for embedded Linux and other embedded and mobile operating systems.&lt;/p&gt;&lt;p&gt;Qt is available under three different licensing options designed to accommodate the needs of our various users.&lt;/p&gt;&lt;p&gt;Qt licensed under our commercial license agreement is appropriate for development of proprietary/commercial software where you do not want to share any source code with third parties or otherwise cannot comply with the terms of the GNU LGPL version 3 or GNU LGPL version 2.1.&lt;/p&gt;&lt;p&gt;Qt licensed under the GNU LGPL version 3 is appropriate for the development of Qt&amp;nbsp;applications provided you can comply with the terms and conditions of the GNU LGPL version 3.&lt;/p&gt;&lt;p&gt;Qt licensed under the GNU LGPL version 2.1 is appropriate for the development of Qt&amp;nbsp;applications provided you can comply with the terms and conditions of the GNU LGPL version 2.1.&lt;/p&gt;&lt;p&gt;Please see &lt;a href=&quot;http://%2/&quot;&gt;%2&lt;/a&gt; for an overview of Qt licensing.&lt;/p&gt;&lt;p&gt;Copyright (C) %1 The Qt Company Ltd and other contributors.&lt;/p&gt;&lt;p&gt;Qt and the Qt logo are trademarks of The Qt Company Ltd.&lt;/p&gt;&lt;p&gt;Qt is The Qt Company Ltd product developed as an open source project. See &lt;a href=&quot;http://%3/&quot;&gt;%3&lt;/a&gt; for more information.&lt;/p&gt;</source>
+        <translation>&lt;p&gt;Qt, platformlar arası uygulama geliştirme için bir C++ araç setidir.&lt;/p&gt;&lt;p&gt;Qt, tüm büyük masaüstü işletim sistemlerinde tek kaynaklı taşınabilirlik sağlar. Gömülü Linux ve diğer gömülü ve mobil işletim sistemleri için de mevcuttur.&lt;/p&gt;&lt;p&gt;Qt, çeşitli kullanıcılarımızın ihtiyaçlarını karşılamak için tasarlanmış üç farklı lisanslama seçeneği altında mevcuttur.&lt;/p&gt;&lt;p&gt;Ticari lisans anlaşmamız kapsamında lisanslanan Qt, herhangi bir kaynak kodunu üçüncü şahıslarla paylaşmak istemediğiniz veya başka bir şekilde GNU LGPL sürüm 3 veya GNU LGPL sürüm 2.1 hükümlerine uyamayacağınız özel / ticari yazılımların geliştirilmesi için uygundur.&lt;/p&gt;&lt;p&gt;GNU LGPL sürüm 3 altında lisanslanan Qt, Qt&apos;nin geliştirilmesi için uygundur&amp;nbsp;Sağlanan uygulamalar, GNU LGPL sürüm 3&apos;ün hüküm ve koşullarına uyabilir.&lt;/p&gt;&lt;p&gt;GNU LGPL sürüm 2.1 altında lisanslanan Qt, Qt&apos;nin geliştirilmesi için uygundur&amp;nbsp;Sağlanan uygulamalar, GNU LGPL sürüm 2.1&apos;in hüküm ve koşullarına uyabilir.&lt;/p&gt;&lt;p&gt;Bakınız&lt;a href=&quot;http://%2/&quot;&gt;%2&lt;/a&gt;Qt lisansına genel bir bakış için.&lt;/p&gt;&lt;p&gt;Telif Hakkı (C) %1 The Qt Company Ltd ve diğer katkıda bulunanlar.&lt;/p&gt;&lt;p&gt;Qt ve Qt logosu, The Qt Company Ltd.&apos;nin ticari markalarıdır.&lt;/p&gt;&lt;p&gt;Qt, açık kaynaklı bir proje olarak geliştirilen Qt Company Ltd ürünüdür. Göster&lt;a href=&quot;http://%3/&quot;&gt;%3&lt;/a&gt;daha fazla bilgi için.&lt;/p&gt;</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qmessagebox.cpp" line="1796"/>
+        <source>About Qt</source>
+        <translation>QT Hakkında</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="674"/>
+        <source>Difference to the default size</source>
+        <translation>Varsayılan boyut farkı</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="680"/>
+        <source>Background color, pink (255, 0, 255) means default</source>
+        <translation>Arka plan rengi, pembe (255, 0, 255) varsayılan anlamına gelir</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="682"/>
+        <source>b</source>
+        <comment>short form for bold</comment>
+        <translation>b</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="683"/>
+        <source>i</source>
+        <comment>short form for italic</comment>
+        <translation>i</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="684"/>
+        <source>u</source>
+        <comment>short form for underlined</comment>
+        <translation>u</translation>
+    </message>
+    <message>
+        <source>b</source>
+        <translation type="vanished">b</translation>
+    </message>
+    <message>
+        <source>i</source>
+        <translation type="vanished">i</translation>
+    </message>
+    <message>
+        <source>hidden</source>
+        <translation type="vanished">gizli</translation>
+    </message>
+    <message>
+        <source>automatic</source>
+        <translation type="vanished">otomatik</translation>
+    </message>
+    <message>
+        <source>function</source>
+        <translation type="vanished">işlev</translation>
+    </message>
+    <message>
+        <source>inherited</source>
+        <translation type="vanished">kalıtsal</translation>
+    </message>
+</context>
+<context>
+    <name>QPPDOptionsModel</name>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="1238"/>
+        <source>Name</source>
+        <translation>İsim</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="1240"/>
+        <source>Value</source>
+        <translation>Değer</translation>
+    </message>
+</context>
+<context>
+    <name>QPageSetupWidget</name>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="304"/>
+        <source>Centimeters (cm)</source>
+        <translation>Santimetre (cm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="304"/>
+        <source>Millimeters (mm)</source>
+        <translation>Milimetre (mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="304"/>
+        <source>Inches (in)</source>
+        <translation>İnç (in)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="304"/>
+        <source>Points (pt)</source>
+        <translation>İşaretler (pt)</translation>
+    </message>
+</context>
+<context>
+    <name>QPlatformTheme</name>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="710"/>
+        <source>OK</source>
+        <translation>TAMAM</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="712"/>
+        <source>Save</source>
+        <translation>Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="714"/>
+        <source>Save All</source>
+        <translation>Hepsini Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="716"/>
+        <source>Open</source>
+        <translation>Aç</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="718"/>
+        <source>&amp;Yes</source>
+        <translation>&amp;Evet</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="720"/>
+        <source>Yes to &amp;All</source>
+        <translation>&amp;Tümüne Evet</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="722"/>
+        <source>&amp;No</source>
+        <translation>&amp;Hayır</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="724"/>
+        <source>N&amp;o to All</source>
+        <translation>Tümüne H&amp;ayır</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="726"/>
+        <source>Abort</source>
+        <translation>Durdur</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="728"/>
+        <source>Retry</source>
+        <oldsource>Retry</oldsource>
+        <translation>Tekrar dene</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="730"/>
+        <source>Ignore</source>
+        <oldsource>Ignore</oldsource>
+        <translation>Yoksay</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="732"/>
+        <source>Close</source>
+        <oldsource>Close</oldsource>
+        <translation>Kapat</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="734"/>
+        <source>Cancel</source>
+        <oldsource>Cancel</oldsource>
+        <translation>İptal</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="736"/>
+        <source>Discard</source>
+        <oldsource>Discard</oldsource>
+        <translation>Yoksay</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="738"/>
+        <source>Help</source>
+        <oldsource>Help</oldsource>
+        <translation>Yardım</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="740"/>
+        <source>Apply</source>
+        <oldsource>Apply</oldsource>
+        <translation>Uygula</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="742"/>
+        <source>Reset</source>
+        <oldsource>Reset</oldsource>
+        <translation>Sıfırla</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qplatformtheme.cpp" line="744"/>
+        <source>Restore Defaults</source>
+        <oldsource>Restore Defaults</oldsource>
+        <translation>Varsayılanlara Dön</translation>
+    </message>
+</context>
+<context>
+    <name>QPrintDialog</name>
+    <message>
+        <location filename="../../../octave-qt/qabstractprintdialog.cpp" line="116"/>
+        <location filename="../../../octave-qt/qabstractprintdialog.cpp" line="129"/>
+        <location filename="../../../octave-qt/qprintdialog_win.cpp" line="272"/>
+        <source>Print</source>
+        <translation>Yazdır</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="72"/>
+        <source>A0</source>
+        <translation>A0</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="73"/>
+        <source>A1</source>
+        <translation>A1</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="74"/>
+        <source>A2</source>
+        <translation>A2</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="75"/>
+        <source>A3</source>
+        <translation>A3</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="76"/>
+        <source>A4</source>
+        <translation>A4</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="77"/>
+        <source>A5</source>
+        <translation>A5</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="78"/>
+        <source>A6</source>
+        <translation>A6</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="79"/>
+        <source>A7</source>
+        <translation>A7</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="80"/>
+        <source>A8</source>
+        <translation>A8</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="81"/>
+        <source>A9</source>
+        <translation>A9</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="82"/>
+        <source>B0</source>
+        <translation>B0</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="83"/>
+        <source>B1</source>
+        <translation>B1</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="84"/>
+        <source>B2</source>
+        <translation>B2</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="85"/>
+        <source>B3</source>
+        <translation>B3</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="86"/>
+        <source>B4</source>
+        <translation>B4</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="87"/>
+        <source>B5</source>
+        <translation>B5</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="88"/>
+        <source>B6</source>
+        <translation>B6</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="89"/>
+        <source>B7</source>
+        <translation>B7</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="90"/>
+        <source>B8</source>
+        <translation>B8</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="91"/>
+        <source>B9</source>
+        <translation>B9</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="92"/>
+        <source>B10</source>
+        <translation>B10</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="93"/>
+        <source>C5E</source>
+        <translation>C5E</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="94"/>
+        <source>DLE</source>
+        <translation>DLE</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="95"/>
+        <source>Executive</source>
+        <translation>Yönetici</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="96"/>
+        <source>Folio</source>
+        <translation>Yaprak</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="97"/>
+        <source>Ledger</source>
+        <translation>Defter</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="98"/>
+        <source>Legal</source>
+        <translation>Resmi</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="99"/>
+        <source>Letter</source>
+        <translation>Mektup</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="100"/>
+        <source>Tabloid</source>
+        <translation>Sıkıştırılmış</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="101"/>
+        <source>US Common #10 Envelope</source>
+        <translation>ABD Ortak #10 Zarf</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qpagesetupdialog_unix.cpp" line="102"/>
+        <source>Custom</source>
+        <translation>Özel</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="148"/>
+        <source>File exists</source>
+        <translation>Dosya mevcut</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="149"/>
+        <source>&lt;qt&gt;Do you want to overwrite it?&lt;/qt&gt;</source>
+        <translation>&lt;qt&gt;Üzerine yazmak ister misin?&lt;/qt&gt;</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="333"/>
+        <source>A0 (841 x 1189 mm)</source>
+        <translation>A0 (841 x 1189 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="334"/>
+        <source>A1 (594 x 841 mm)</source>
+        <translation>A1 (594 x 841 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="335"/>
+        <source>A2 (420 x 594 mm)</source>
+        <translation>A2 (420 x 594 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="336"/>
+        <source>A3 (297 x 420 mm)</source>
+        <translation>A3 (297 x 420 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="337"/>
+        <source>A4 (210 x 297 mm, 8.26 x 11.7 inches)</source>
+        <translation>A4 (210 x 297 mm, 8,26 x 11,7 inç)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="338"/>
+        <source>A5 (148 x 210 mm)</source>
+        <translation>A5 (148 x 210 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="339"/>
+        <source>A6 (105 x 148 mm)</source>
+        <translation>A6 (105 x 148 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="340"/>
+        <source>A7 (74 x 105 mm)</source>
+        <translation>A7 (74 x 105 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="341"/>
+        <source>A8 (52 x 74 mm)</source>
+        <translation>A8 (52 x 74 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="342"/>
+        <source>A9 (37 x 52 mm)</source>
+        <translation>A9 (37 x 52 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="343"/>
+        <source>B0 (1000 x 1414 mm)</source>
+        <translation>B0 (1000 x 1414 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="344"/>
+        <source>B1 (707 x 1000 mm)</source>
+        <translation>B1 (707 x 1000 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="345"/>
+        <source>B2 (500 x 707 mm)</source>
+        <translation>B2 (500 x 707 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="346"/>
+        <source>B3 (353 x 500 mm)</source>
+        <translation>B3 (353 x 500 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="347"/>
+        <source>B4 (250 x 353 mm)</source>
+        <translation>B4 (250 x 353 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="348"/>
+        <source>B5 (176 x 250 mm, 6.93 x 9.84 inches)</source>
+        <translation>B5 (176 x 250 mm, 6.93 x 9.84 inc)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="349"/>
+        <source>B6 (125 x 176 mm)</source>
+        <translation>B6 (125 x 176 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="350"/>
+        <source>B7 (88 x 125 mm)</source>
+        <translation>B7 (88 x 125 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="351"/>
+        <source>B8 (62 x 88 mm)</source>
+        <translation>B8 (62 x 88 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="352"/>
+        <source>B9 (44 x 62 mm)</source>
+        <translation>B9 (44 x 62 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="353"/>
+        <source>B10 (31 x 44 mm)</source>
+        <translation>B10 (31 x 44 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="354"/>
+        <source>C5E (163 x 229 mm)</source>
+        <translation>C5E (163 x 229 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="355"/>
+        <source>DLE (110 x 220 mm)</source>
+        <translation>DLE (110 x 220 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="356"/>
+        <source>Executive (7.5 x 10 inches, 191 x 254 mm)</source>
+        <translation>Yönetici (7,5 x 10 inç, 191 x 254 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="357"/>
+        <source>Folio (210 x 330 mm)</source>
+        <translation>Yaprak (210 x 330 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="358"/>
+        <source>Ledger (432 x 279 mm)</source>
+        <translation>Defter (432 x 279 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="359"/>
+        <source>Legal (8.5 x 14 inches, 216 x 356 mm)</source>
+        <translation>Resmi (8.5 x 14 inc, 216 x 356 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="360"/>
+        <source>Letter (8.5 x 11 inches, 216 x 279 mm)</source>
+        <translation>Mektup (8,5 x 11 inç, 216 x 279 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="361"/>
+        <source>Tabloid (279 x 432 mm)</source>
+        <translation>Sıkıştırılmış (279 x 432 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="362"/>
+        <source>US Common #10 Envelope (105 x 241 mm)</source>
+        <translation>ABD Ortak # 10 Zarf (105 x 241 mm)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="379"/>
+        <source>Print all</source>
+        <translation>Hepsini yazdır</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="380"/>
+        <source>Print selection</source>
+        <translation>Seçimi yazdır</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="381"/>
+        <source>Print range</source>
+        <translation>Baskı aralığı</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_qws.cpp" line="382"/>
+        <source>Print current page</source>
+        <translation>Geçerli sayfayı yazdır</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="396"/>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="464"/>
+        <source>&amp;Options &gt;&gt;</source>
+        <translation>&amp;Seçenekler &gt;&gt;</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="401"/>
+        <source>&amp;Print</source>
+        <translation>&amp;Yazdır</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="468"/>
+        <source>&amp;Options &lt;&lt;</source>
+        <translation>&amp;Seçenekler &lt;&lt;</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="728"/>
+        <source>Print to File (PDF)</source>
+        <translation>Dosyaya Yazdır (PDF)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="729"/>
+        <source>Print to File (Postscript)</source>
+        <translation>Dosyaya Yazdır (Dipnot)</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="776"/>
+        <source>Local file</source>
+        <translation>Yerel dosya</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="777"/>
+        <source>Write %1 file</source>
+        <translation>%1 Dosya yaz</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="848"/>
+        <source>Print To File ...</source>
+        <translation>Dosyaya Yazdır...</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="926"/>
+        <source>%1 is a directory.
+Please choose a different file name.</source>
+        <translation>%1 bir dizindir.
+Lütfen farklı bir dosya adı seçin.</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="930"/>
+        <source>File %1 is not writable.
+Please choose a different file name.</source>
+        <translation>%1 dosyası yazılabilir değil.
+Lütfen farklı bir dosya adı seçin.</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_unix.cpp" line="934"/>
+        <source>%1 already exists.
+Do you want to overwrite it?</source>
+        <translation>%1 zaten var.
+Üzerine yazmak istiyor musunuz?</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_win.cpp" line="273"/>
+        <source>The &apos;From&apos; value cannot be greater than the &apos;To&apos; value.</source>
+        <translation>&apos;Başlangıç&apos; değeri &apos;Bitiş&apos; değerinden büyük olamaz.</translation>
+    </message>
+    <message>
+        <location filename="../../../octave-qt/qprintdialog_win.cpp" line="274"/>
+        <source>OK</source>
+        <translation>TAMAM</translation>
+    </message>
+</context>
+<context>
+    <name>QPrintPreviewDialog</name>
+    <message>
+        <location filename="../../../octave-qt/qabstractpagesetupdialog.cpp" line="68"/>
+        <location filename="../../../octave-qt/qabstractpagesetupdialog.cpp" line="80"/>
+        <source>Page Setup</source>
+        <translation>Sayfa Ayarı</translation>
+    </message>
+</context>
+<context>
+    <name>QTerminal</name>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="139"/>
+        <source>Edit %1</source>
+        <oldsource>Edit</oldsource>
+        <translation>%1 Düzenle</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="143"/>
+        <source>Help on %1</source>
+        <oldsource>Help on</oldsource>
+        <translation>%1 Yardım</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="147"/>
+        <source>Documentation on %1</source>
+        <oldsource>Documentation on</oldsource>
+        <translation>%1 Belgelendirme</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="301"/>
+        <source>Copy</source>
+        <translation>Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="305"/>
+        <source>Paste</source>
+        <translation>Yapıştır</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="311"/>
+        <source>Select All</source>
+        <translation>Tümünü Seçin</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="314"/>
+        <source>Run Selection</source>
+        <translation>Seçimi Çalıştır</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="318"/>
+        <source>Edit selection</source>
+        <oldsource>Print selection</oldsource>
+        <translation>Seçimi yazdır</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="321"/>
+        <source>Help on selection</source>
+        <oldsource>selection</oldsource>
+        <translation>Seçim yardımı</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="324"/>
+        <source>Documentation on selection</source>
+        <oldsource>Documentation on</oldsource>
+        <translation>Seçimle ilgili belgeler</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="331"/>
+        <source>Clear Window</source>
+        <translation>Pencereyi Temizle</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/QTerminal.cc" line="118"/>
+        <source>Edit %1 at line %2</source>
+        <translation>%1 &apos;i %2 satırında düzenleyin</translation>
+    </message>
+</context>
+<context>
+    <name>QWinTerminalImpl</name>
+    <message>
+        <location filename="../qterminal/libqterminal/win32/QWinTerminalImpl.cpp" line="1804"/>
+        <source>copied selection to clipboard</source>
+        <translation>seçim panoya kopyalandı</translation>
+    </message>
+</context>
+<context>
+    <name>QsciLexerBash</name>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="203"/>
+        <source>Default</source>
+        <translation>Ön tanımlı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="206"/>
+        <source>Error</source>
+        <translation>Hata</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="209"/>
+        <source>Comment</source>
+        <translation>Yorum</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="212"/>
+        <source>Number</source>
+        <translation>Numara</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="215"/>
+        <source>Keyword</source>
+        <translation>Anahtar kelime</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="218"/>
+        <source>Double-quoted string</source>
+        <translation>Çift tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="221"/>
+        <source>Single-quoted string</source>
+        <translation>Tek tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="224"/>
+        <source>Operator</source>
+        <translation>Operatör</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="227"/>
+        <source>Identifier</source>
+        <translation>Tanımlayıcı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="230"/>
+        <source>Scalar</source>
+        <translation>Basamaklı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="233"/>
+        <source>Parameter expansion</source>
+        <translation>Parametre genişletme</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="236"/>
+        <source>Backticks</source>
+        <translation>Ters tik</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="239"/>
+        <source>Here document delimiter</source>
+        <translation>Burada belge sınırlayıcı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbash.cpp" line="242"/>
+        <source>Single-quoted here document</source>
+        <translation>Tek alıntı belge burada</translation>
+    </message>
+</context>
+<context>
+    <name>QsciLexerBatch</name>
+    <message>
+        <location filename="../../../qsci/qscilexerbatch.cpp" line="174"/>
+        <source>Default</source>
+        <translation>Ön tanımlı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbatch.cpp" line="177"/>
+        <source>Comment</source>
+        <translation>Yorum</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbatch.cpp" line="180"/>
+        <source>Keyword</source>
+        <translation>Anahtar kelime</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbatch.cpp" line="183"/>
+        <source>Label</source>
+        <translation>Etiket</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbatch.cpp" line="186"/>
+        <source>Hide command character</source>
+        <translation>Komut karakterini gizle</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbatch.cpp" line="189"/>
+        <source>External command</source>
+        <translation>Harici komut</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbatch.cpp" line="192"/>
+        <source>Variable</source>
+        <translation>Değişken</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerbatch.cpp" line="195"/>
+        <source>Operator</source>
+        <translation>Operatör</translation>
+    </message>
+</context>
+<context>
+    <name>QsciLexerCPP</name>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="364"/>
+        <source>Default</source>
+        <translation>Ön tanımlı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="367"/>
+        <source>Inactive default</source>
+        <translation>Varsayılan pasif</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="370"/>
+        <source>C comment</source>
+        <translation>C açıklaması</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="373"/>
+        <source>Inactive C comment</source>
+        <translation>Pasif C yorumu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="376"/>
+        <source>C++ comment</source>
+        <translation>C++ açıklaması</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="379"/>
+        <source>Inactive C++ comment</source>
+        <translation>Pasif C++ açıklaması</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="382"/>
+        <source>JavaDoc style C comment</source>
+        <translation>JavaDoc tarzı C yorumu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="385"/>
+        <source>Inactive JavaDoc style C comment</source>
+        <translation>Pasif JavaDoc tarzı C yorumu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="388"/>
+        <source>Number</source>
+        <translation>Numara</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="391"/>
+        <source>Inactive number</source>
+        <translation>Pasif numara</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="394"/>
+        <source>Keyword</source>
+        <translation>Anahtar kelime</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="397"/>
+        <source>Inactive keyword</source>
+        <translation>Pasif anahtar kelime</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="400"/>
+        <source>Double-quoted string</source>
+        <translation>Çift tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="403"/>
+        <source>Inactive double-quoted string</source>
+        <translation>Pasif çift tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="406"/>
+        <source>Single-quoted string</source>
+        <translation>Tek tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="409"/>
+        <source>Inactive single-quoted string</source>
+        <translation>Pasif tek tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="412"/>
+        <source>IDL UUID</source>
+        <translation>IDL UUID</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="415"/>
+        <source>Inactive IDL UUID</source>
+        <translation>Pasif IDL UUID</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="418"/>
+        <source>Pre-processor block</source>
+        <translation>Ön işlemci bloğu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="421"/>
+        <source>Inactive pre-processor block</source>
+        <translation>Pasif ön işlemci bloğu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="424"/>
+        <source>Operator</source>
+        <translation>Operatör</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="427"/>
+        <source>Inactive operator</source>
+        <translation>Etkisiz işleç</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="430"/>
+        <source>Identifier</source>
+        <translation>Tanımlayıcı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="433"/>
+        <source>Inactive identifier</source>
+        <translation>Pasif tanımlayıcı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="436"/>
+        <source>Unclosed string</source>
+        <translation>Kapatılmamış dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="439"/>
+        <source>Inactive unclosed string</source>
+        <translation>Pasif kapatılmamış dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="442"/>
+        <source>C# verbatim string</source>
+        <translation>C# kelimesi kelimesine dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="445"/>
+        <source>Inactive C# verbatim string</source>
+        <translation>Pasif C# kelimesi kelimesine dizesi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="448"/>
+        <source>JavaScript regular expression</source>
+        <translation>JavaScript normal ifadesi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="451"/>
+        <source>Inactive JavaScript regular expression</source>
+        <translation>Pasif JavaScript normal ifadesi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="454"/>
+        <source>JavaDoc style C++ comment</source>
+        <translation>JavaDoc tarzı C++ açıklaması</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="457"/>
+        <source>Inactive JavaDoc style C++ comment</source>
+        <translation>Pasif JavaDoc tarzı C++ açıklaması</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="460"/>
+        <source>Secondary keywords and identifiers</source>
+        <translation>İkincil anahtar kelimeler ve tanımlayıcılar</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="463"/>
+        <source>Inactive secondary keywords and identifiers</source>
+        <translation>Pasif ikincil anahtar kelimeler ve tanımlayıcılar</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="466"/>
+        <source>JavaDoc keyword</source>
+        <translation>JavaDoc anahtar sözcüğü</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="469"/>
+        <source>Inactive JavaDoc keyword</source>
+        <translation>Pasif JavaDoc anahtar sözcüğü</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="472"/>
+        <source>JavaDoc keyword error</source>
+        <translation>JavaDoc anahtar kelime hatası</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="475"/>
+        <source>Inactive JavaDoc keyword error</source>
+        <translation>Pasif JavaDoc anahtar kelime hatası</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="478"/>
+        <source>Global classes and typedefs</source>
+        <translation>Küresel sınıflar ve yazıtipleri</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="481"/>
+        <source>Inactive global classes and typedefs</source>
+        <translation>Pasif genel sınıflar ve türler</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="484"/>
+        <source>C++ raw string</source>
+        <translation>C++ ham dizi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="487"/>
+        <source>Inactive C++ raw string</source>
+        <translation>Pasif C++ ham dizesi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="490"/>
+        <source>Vala triple-quoted verbatim string</source>
+        <oldsource>Inactive C# verbatim string</oldsource>
+        <translation>Vala üç tırnaklı harfi harfine dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="493"/>
+        <source>Inactive Vala triple-quoted verbatim string</source>
+        <oldsource>Inactive single-quoted string</oldsource>
+        <translation>Pasif Vala üç tırnaklı harfi harfine dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="496"/>
+        <source>Pike hash-quoted string</source>
+        <oldsource>Single-quoted string</oldsource>
+        <translation>Pike hash-tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="499"/>
+        <source>Inactive Pike hash-quoted string</source>
+        <oldsource>Inactive single-quoted string</oldsource>
+        <translation>Pasif Pike hash-tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="502"/>
+        <source>Pre-processor C comment</source>
+        <translation>Ön işlemci bloğu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="505"/>
+        <source>Inactive pre-processor C comment</source>
+        <translation>Pasif ön işlemci C yorumu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="508"/>
+        <source>JavaDoc style pre-processor comment</source>
+        <translation>JavaDoc tarzı ön işlemci yorumu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="511"/>
+        <source>Inactive JavaDoc style pre-processor comment</source>
+        <translation>Pasif JavaDoc tarzı ön işlemci yorumu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="514"/>
+        <source>User-defined literal</source>
+        <translation>Kullanıcı tanımlı değişmez bilgi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="517"/>
+        <source>Inactive user-defined literal</source>
+        <translation>Pasif kullanıcı tanımlı değişmez bilgi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="520"/>
+        <source>Task marker</source>
+        <translation>Görev işaretçisi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="523"/>
+        <source>Inactive task marker</source>
+        <translation>Pasif görev işaretçisi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="526"/>
+        <source>Escape sequence</source>
+        <translation>Kaçış dizisi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexercpp.cpp" line="529"/>
+        <source>Inactive escape sequence</source>
+        <translation>Pasif kaçış dizisi</translation>
+    </message>
+</context>
+<context>
+    <name>QsciLexerDiff</name>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="106"/>
+        <source>Default</source>
+        <translation>Ön tanımlı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="109"/>
+        <source>Comment</source>
+        <translation>Yorum</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="112"/>
+        <source>Command</source>
+        <translation>Komut</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="115"/>
+        <source>Header</source>
+        <translation>Başlık</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="118"/>
+        <source>Position</source>
+        <translation>Pozisyon</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="121"/>
+        <source>Removed line</source>
+        <translation>Satır kaldırıldı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="124"/>
+        <source>Added line</source>
+        <translation>Satır eklendi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="127"/>
+        <source>Changed line</source>
+        <translation>Satır değiştirildi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="130"/>
+        <source>Added adding patch</source>
+        <translation>Ekleme yaması eklendi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="133"/>
+        <source>Removed adding patch</source>
+        <translation>Yama ekleme kaldırıldı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="136"/>
+        <source>Added removing patch</source>
+        <translation>Kaldırma yaması eklendi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerdiff.cpp" line="139"/>
+        <source>Removed removing patch</source>
+        <translation>Kaldırma yaması eklendi</translation>
+    </message>
+</context>
+<context>
+    <name>QsciLexerMatlab</name>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="133"/>
+        <source>Default</source>
+        <translation>Ön tanımlı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="136"/>
+        <source>Comment</source>
+        <translation>Yorum</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="139"/>
+        <source>Command</source>
+        <translation>Komut</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="142"/>
+        <source>Number</source>
+        <translation>Numara</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="145"/>
+        <source>Keyword</source>
+        <translation>Anahtar kelime</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="148"/>
+        <source>Single-quoted string</source>
+        <translation>Tek tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="151"/>
+        <source>Operator</source>
+        <translation>Operatör</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="154"/>
+        <source>Identifier</source>
+        <translation>Tanımlayıcı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexermatlab.cpp" line="157"/>
+        <source>Double-quoted string</source>
+        <translation>Çift tırnaklı dize</translation>
+    </message>
+</context>
+<context>
+    <name>QsciLexerPerl</name>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="328"/>
+        <source>Default</source>
+        <translation>Varsayılan</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="331"/>
+        <source>Error</source>
+        <translation>Hata</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="334"/>
+        <source>Comment</source>
+        <translation>Yorum</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="337"/>
+        <source>POD</source>
+        <translation>POD</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="340"/>
+        <source>Number</source>
+        <translation>Numara</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="343"/>
+        <source>Keyword</source>
+        <translation>Anahtar kelime</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="346"/>
+        <source>Double-quoted string</source>
+        <translation>Çift tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="349"/>
+        <source>Single-quoted string</source>
+        <translation>Tek tırnaklı dize</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="352"/>
+        <source>Operator</source>
+        <translation>Operatör</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="355"/>
+        <source>Identifier</source>
+        <translation>Tanımlayıcı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="358"/>
+        <source>Scalar</source>
+        <translation>Basamaklı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="361"/>
+        <source>Array</source>
+        <translation>Dizi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="364"/>
+        <source>Hash</source>
+        <translation>Hash</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="367"/>
+        <source>Symbol table</source>
+        <translation>Sembol tablosu</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="370"/>
+        <source>Regular expression</source>
+        <translation>Düzenli ifade</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="373"/>
+        <source>Substitution</source>
+        <translation>İkame</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="376"/>
+        <source>Backticks</source>
+        <translation>Ters tik</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="379"/>
+        <source>Data section</source>
+        <translation>Veri bölümü</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="382"/>
+        <source>Here document delimiter</source>
+        <translation>Burada belge sınırlayıcı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="385"/>
+        <source>Single-quoted here document</source>
+        <translation>Tek alıntı belge burada</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="388"/>
+        <source>Double-quoted here document</source>
+        <translation>Burada çift alıntı yapılan belge</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="391"/>
+        <source>Backtick here document</source>
+        <translation>Buraya geri dönüş belgesi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="394"/>
+        <source>Quoted string (q)</source>
+        <translation>Tırnaklı dize (q)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="397"/>
+        <source>Quoted string (qq)</source>
+        <translation>Tırnaklı dize (qq)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="400"/>
+        <source>Quoted string (qx)</source>
+        <translation>Tırnaklı dize (qx)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="403"/>
+        <source>Quoted string (qr)</source>
+        <translation>Tırnaklı dize (qr)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="406"/>
+        <source>Quoted string (qw)</source>
+        <translation>Tırnaklı dize (qw)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="409"/>
+        <source>POD verbatim</source>
+        <translation>POD kelimesi</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="412"/>
+        <source>Subroutine prototype</source>
+        <translation>Alt rutin prototip</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="415"/>
+        <source>Format identifier</source>
+        <translation>Biçim tanımlayıcı</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="418"/>
+        <source>Format body</source>
+        <translation>Gövde biçimlendir</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="421"/>
+        <source>Double-quoted string (interpolated variable)</source>
+        <translation>Çift tırnaklı dize (enterpolasyonlu değişken)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="424"/>
+        <source>Translation</source>
+        <translation>Çeviri</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="427"/>
+        <source>Regular expression (interpolated variable)</source>
+        <translation>Normal ifade (enterpolasyonlu değişken)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="430"/>
+        <source>Substitution (interpolated variable)</source>
+        <translation>Değiştirme (enterpolasyonlu değişken)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="433"/>
+        <source>Backticks (interpolated variable)</source>
+        <translation>Geri işaretleri (enterpolasyonlu değişken)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="436"/>
+        <source>Double-quoted here document (interpolated variable)</source>
+        <translation>Burada çift alıntı yapılan belge (enterpolasyonlu değişken)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="439"/>
+        <source>Backtick here document (interpolated variable)</source>
+        <translation>Buraya geri dönüş belgesi (enterpolasyonlu değişken)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="442"/>
+        <source>Quoted string (qq, interpolated variable)</source>
+        <translation>Alıntılanan dize (qq, enterpolasyonlu değişken)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="445"/>
+        <source>Quoted string (qx, interpolated variable)</source>
+        <translation>Alıntılanan dize (qx, enterpolasyonlu değişken)</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qscilexerperl.cpp" line="448"/>
+        <source>Quoted string (qr, interpolated variable)</source>
+        <translation>Alıntılanan dize (qr, enterpolasyonlu değişken)</translation>
+    </message>
+</context>
+<context>
+    <name>QsciScintilla</name>
+    <message>
+        <location filename="../../../qsci/qsciscintilla.cpp" line="4475"/>
+        <source>&amp;Undo</source>
+        <translation>&amp;Geri Al</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qsciscintilla.cpp" line="4479"/>
+        <source>&amp;Redo</source>
+        <translation>&amp;Yinele</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qsciscintilla.cpp" line="4485"/>
+        <source>Cu&amp;t</source>
+        <translation>Ke&amp;s</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qsciscintilla.cpp" line="4490"/>
+        <source>&amp;Copy</source>
+        <translation>&amp;Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qsciscintilla.cpp" line="4496"/>
+        <source>&amp;Paste</source>
+        <translation>&amp;Yapıştır</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qsciscintilla.cpp" line="4500"/>
+        <source>Delete</source>
+        <translation>Sil</translation>
+    </message>
+    <message>
+        <location filename="../../../qsci/qsciscintilla.cpp" line="4507"/>
+        <source>Select All</source>
+        <translation>Hepsini Seç</translation>
+    </message>
+</context>
+<context>
+    <name>UrlFilter</name>
+    <message>
+        <location filename="../qterminal/libqterminal/unix/Filter.cpp" line="625"/>
+        <source>Open Link</source>
+        <translation>Bağlantıyı Aç</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/unix/Filter.cpp" line="626"/>
+        <source>Copy Link Address</source>
+        <translation>Bağlantı Adresini Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/unix/Filter.cpp" line="630"/>
+        <source>Send Email To...</source>
+        <translation>Email gönder...</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/unix/Filter.cpp" line="631"/>
+        <source>Copy Email Address</source>
+        <translation>E-posta Adresini Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../qterminal/libqterminal/unix/Filter.cpp" line="641"/>
+        <location filename="../qterminal/libqterminal/unix/Filter.cpp" line="653"/>
+        <source>Edit %1 at line %2</source>
+        <translation>%1 &apos;i %2 satırında düzenleyin</translation>
+    </message>
+</context>
+<context>
+    <name>annotation_dialog</name>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="17"/>
+        <source>Annotation</source>
+        <translation>Açıklamalar</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="23"/>
+        <source>Text</source>
+        <translation>Metin</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="29"/>
+        <source>String</source>
+        <translation>Dize</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="42"/>
+        <source>Font</source>
+        <translation>Yazı Tipi</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="84"/>
+        <source>bold</source>
+        <translation>kalın</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="87"/>
+        <source>b</source>
+        <translation>b</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="100"/>
+        <source>italic</source>
+        <translation>eğik</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="103"/>
+        <source>i</source>
+        <translation>i</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="531"/>
+        <source>color</source>
+        <translation>renk</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="553"/>
+        <source>Horz alignment</source>
+        <translation>Yatay hizalama</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="564"/>
+        <source>left</source>
+        <translation>sol</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="569"/>
+        <location filename="../graphics/annotation-dialog.ui" line="598"/>
+        <source>middle</source>
+        <translation>orta</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="574"/>
+        <source>right</source>
+        <translation>sağ</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="582"/>
+        <source>Vert alignment</source>
+        <translation>Dikey hizalama</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="593"/>
+        <source>top</source>
+        <translation>üst</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="603"/>
+        <source>bottom</source>
+        <translation>alt</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="614"/>
+        <source>Position</source>
+        <translation>Pozisyon</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="620"/>
+        <source>X</source>
+        <translation>X</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="640"/>
+        <source>Y</source>
+        <translation>Y</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="660"/>
+        <source>Width</source>
+        <translation>Genişlik</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="677"/>
+        <source>Height</source>
+        <translation>Yükseklik</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="694"/>
+        <source>units</source>
+        <translation>birimler</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="705"/>
+        <source>normalized</source>
+        <translation>normalleştirilmiş</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="713"/>
+        <source>Fit to box</source>
+        <translation>Kutuya sığdır</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="726"/>
+        <source>Box</source>
+        <translation>Kutu</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="732"/>
+        <source>Background</source>
+        <translation>Arkaplan</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="1176"/>
+        <source>Edge</source>
+        <translation>Kenar</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="1309"/>
+        <source>Line style</source>
+        <translation>Çizgi stili</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="1320"/>
+        <source>none</source>
+        <translation>yok</translation>
+    </message>
+    <message>
+        <location filename="../graphics/annotation-dialog.ui" line="1328"/>
+        <source>Line width</source>
+        <translation>Çizgi Kalınlığı</translation>
+    </message>
+</context>
+<context>
+    <name>octave::ListDialog</name>
+    <message>
+        <location filename="../src/dialog.cc" line="483"/>
+        <source>Select All</source>
+        <translation>Hepsini Seç</translation>
+    </message>
+</context>
+<context>
+    <name>octave::documentation</name>
+    <message>
+        <location filename="../src/documentation.cc" line="103"/>
+        <location filename="../src/documentation.cc" line="115"/>
+        <location filename="../src/documentation.cc" line="783"/>
+        <source>Octave Documentation</source>
+        <translation>Octave Belgelendirmeleri</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="104"/>
+        <source>Could not copy help collection to temporary
+file. Search capabilities may be affected.
+%1</source>
+        <translation>Yardım koleksiyonu geçici olarak kopyalanamadı
+dosya. Arama yetenekleri etkilenebilir.
+%1</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="116"/>
+        <source>Could not setup the data required for the
+documentation viewer. Only help texts in
+the Command Window will be available.</source>
+        <translation>İçin gerekli veriler ayarlanamadı
+belge görüntüleyici. Sadece içindeki yardım metinleri
+Komut Penceresi açılacaktır.</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="138"/>
+        <source>Find:</source>
+        <translation>Bul:</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="145"/>
+        <location filename="../src/documentation.cc" line="146"/>
+        <source>Search forward</source>
+        <translation>İleriye doğru ara</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="152"/>
+        <location filename="../src/documentation.cc" line="153"/>
+        <source>Search backward</source>
+        <translation>Geriye doğru ara</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="228"/>
+        <source>Function Index</source>
+        <translation>İşlev İndeksi</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="328"/>
+        <source>Go home</source>
+        <translation>Anasayfaya git</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="331"/>
+        <source>Go back</source>
+        <translation>Geri git</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="345"/>
+        <source>Go forward</source>
+        <translation>İleri git</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="388"/>
+        <source>Find</source>
+        <translation>Bul</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="394"/>
+        <source>Zoom in</source>
+        <translation>Yaklaştır</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="397"/>
+        <source>Zoom out</source>
+        <translation>Uzaklaştır</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="400"/>
+        <source>Zoom original</source>
+        <translation>Orijinal Yakınlık</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="193"/>
+        <source>Contents</source>
+        <translation>İçindekiler</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="203"/>
+        <source>Enter text to search the indices</source>
+        <translation>Endeksleri aramak için metin girin</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="212"/>
+        <location filename="../src/documentation.cc" line="251"/>
+        <source>Search</source>
+        <translation>Ara</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="337"/>
+        <source>Previous pages</source>
+        <translation>Önceki sayfalar</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="351"/>
+        <source>Next pages</source>
+        <translation>Sonraki sayfalar</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation.cc" line="784"/>
+        <source>Unable to register help file %1.</source>
+        <translation>%1 yardım dosyası kaydedilemiyor.</translation>
+    </message>
+</context>
+<context>
+    <name>octave::documentation_dock_widget</name>
+    <message>
+        <location filename="../src/documentation-dock-widget.cc" line="41"/>
+        <source>Documentation</source>
+        <translation>Belgelendirme</translation>
+    </message>
+    <message>
+        <location filename="../src/documentation-dock-widget.cc" line="42"/>
+        <source>See the documentation for help.</source>
+        <translation>Yardım için belgelere bakın.</translation>
+    </message>
+</context>
+<context>
+    <name>octave::dw_main_window</name>
+    <message>
+        <location filename="../src/dw-main-window.cc" line="54"/>
+        <source>&amp;Close</source>
+        <translation>&amp;Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/dw-main-window.cc" line="58"/>
+        <source>Close &amp;All</source>
+        <translation>&amp;Tümünü Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/dw-main-window.cc" line="62"/>
+        <source>Close &amp;Other</source>
+        <translation>&amp;Diğerlerini Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/dw-main-window.cc" line="65"/>
+        <source>Switch to &amp;Left Widget</source>
+        <translation>&amp;Soldaki araca Geç</translation>
+    </message>
+    <message>
+        <location filename="../src/dw-main-window.cc" line="69"/>
+        <source>Switch to &amp;Right Widget</source>
+        <translation>&amp;Sağdaki araca Geç</translation>
+    </message>
+</context>
+<context>
+    <name>octave::external_editor_interface</name>
+    <message>
+        <location filename="../src/external-editor-interface.cc" line="68"/>
+        <location filename="../src/external-editor-interface.cc" line="115"/>
+        <source>Octave Editor</source>
+        <translation>Oktave Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/external-editor-interface.cc" line="69"/>
+        <source>Could not start custom file editor
+%1</source>
+        <translation>Özel dosya düzenleyicisi başlatılamadı
+%1</translation>
+    </message>
+    <message>
+        <location filename="../src/external-editor-interface.cc" line="116"/>
+        <source>There is no custom editor configured yet.
+Do you want to open the preferences?</source>
+        <translation>Henüz yapılandırılmış özel bir düzenleyici yok.
+Tercihleri açmak istiyor musunuz?</translation>
+    </message>
+</context>
+<context>
+    <name>octave::file_editor</name>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1008"/>
+        <location filename="../src/m-editor/file-editor.cc" line="1036"/>
+        <location filename="../src/m-editor/file-editor.cc" line="1572"/>
+        <location filename="../src/m-editor/file-editor.cc" line="1590"/>
+        <location filename="../src/m-editor/file-editor.cc" line="1615"/>
+        <source>Octave Editor</source>
+        <translation>Oktave Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1009"/>
+        <source>File not saved! A file with the selected name
+%1
+is already open in the editor</source>
+        <translation>Dosya kaydedilmedi! Seçili ada sahip bir dosya
+%1
+düzenleyicide zaten açık</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1037"/>
+        <source>The associated file editor tab has disappeared.</source>
+        <translation>İlişkili dosya düzenleyici sekmesi kayboldu.</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1573"/>
+        <source>Could not open file
+%1
+for read: %2.</source>
+        <translation>Dosya açılamadı
+%1
+okumak için: %2.</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1591"/>
+        <source>File
+%1
+does not exist. Do you want to create it?</source>
+        <translation>Dosya
+%1
+mevcut değil. Onu oluşturmak ister misin?</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1595"/>
+        <source>Create</source>
+        <translation>Oluştur</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1596"/>
+        <source>Cancel</source>
+        <translation>İptal</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1616"/>
+        <source>Could not open file
+%1
+for write: %2.</source>
+        <translation>Dosya açılamadı
+%1
+yazmak için: %2.</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1849"/>
+        <source>&amp;File</source>
+        <translation>&amp;DOSYA</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1852"/>
+        <source>&amp;Recent Editor Files</source>
+        <translation>&amp;Son Düzenleyici Dosyaları</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1861"/>
+        <source>&amp;Edit Function</source>
+        <translation>İşlevi &amp;Düzenle</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1868"/>
+        <source>&amp;Save File</source>
+        <translation>Dosyayı &amp;Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1872"/>
+        <source>Save File &amp;As...</source>
+        <translation>Dosyayı &amp;Farklı Kaydet...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1879"/>
+        <source>&amp;Close</source>
+        <translation>&amp;Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1883"/>
+        <source>Close All</source>
+        <translation>Tümünü Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1887"/>
+        <source>Close Other Files</source>
+        <translation>Diğer Dosyaları Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1894"/>
+        <source>Print...</source>
+        <translation>Yazdır...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1898"/>
+        <source>&amp;Edit</source>
+        <translation>&amp;Düzenle</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1902"/>
+        <source>&amp;Redo</source>
+        <translation>&amp;Yinele</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1909"/>
+        <source>Cu&amp;t</source>
+        <translation>Ke&amp;s</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1914"/>
+        <source>&amp;Find and Replace...</source>
+        <translation>&amp;Bul ve Değiştir...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1917"/>
+        <source>Find &amp;Next...</source>
+        <translation>&amp;Sonrakini Bul...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1921"/>
+        <source>Find &amp;Previous...</source>
+        <translation>&amp;Öncekini Bul...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1926"/>
+        <source>&amp;Commands</source>
+        <translation>&amp;Komutlar</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1929"/>
+        <source>Delete Line</source>
+        <translation>Satırı Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1933"/>
+        <source>Copy Line</source>
+        <translation>Satırı Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1937"/>
+        <source>Cut Line</source>
+        <translation>Satır Kes</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1943"/>
+        <source>Delete to Start of Word</source>
+        <translation>Kelimenin Başını Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1947"/>
+        <source>Delete to End of Word</source>
+        <translation>Kelimenin Sonuna Kadar Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1951"/>
+        <source>Delete to Start of Line</source>
+        <translation>Satırın Başına Kadar Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1955"/>
+        <source>Delete to End of Line</source>
+        <translation>Satırın Sonuna Kadar Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1961"/>
+        <source>Duplicate Selection/Line</source>
+        <translation>Yinelenen Seçim/Satır</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1965"/>
+        <source>Transpose Line</source>
+        <translation>Satırı Aktar</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1971"/>
+        <source>&amp;Show Completion List</source>
+        <translation>Tamamlama Listesini &amp;Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1974"/>
+        <source>&amp;Format</source>
+        <translation>&amp;Biçim</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1977"/>
+        <source>&amp;Uppercase Selection</source>
+        <translation>&amp;Büyük Harf Seçimi</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1981"/>
+        <source>&amp;Lowercase Selection</source>
+        <translation>&amp;Küçük Harf Seçimi</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1987"/>
+        <source>&amp;Comment</source>
+        <translation>&amp;Açıklama</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1991"/>
+        <source>&amp;Uncomment</source>
+        <translation>&amp;Açıklamayı geri al</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="1995"/>
+        <source>Comment (Choosing String)</source>
+        <translation>Yorum (Dize Seçme)</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2001"/>
+        <source>&amp;Indent Selection Rigidly</source>
+        <translation>Sert &amp;Girinti Seçimi</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2005"/>
+        <source>&amp;Unindent Selection Rigidly</source>
+        <translation>&amp;Seçimi Katı Şekilde Çöz</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2009"/>
+        <source>Indent Code</source>
+        <translation>Girinti Kodu</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2016"/>
+        <source>Convert Line Endings to &amp;Windows (CRLF)</source>
+        <translation>Satır Sonlarını &amp;Windows&apos;a (CRLF) Dönüştür</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2020"/>
+        <source>Convert Line Endings to &amp;Unix (LF)</source>
+        <translation>Satır Uçlarını &amp;Unix&apos;e (LF) Dönüştür</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2025"/>
+        <source>Convert Line Endings to Legacy &amp;Mac (CR)</source>
+        <translation>Satır Sonlarını Eski &amp;Mac&apos;e Dönüştür (CR)</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2028"/>
+        <source>Navi&amp;gation</source>
+        <translation>Gezi&amp;nme</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2031"/>
+        <source>Go &amp;to Line...</source>
+        <translation>&amp;Satıra Git...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2037"/>
+        <source>Move to Matching Brace</source>
+        <translation>Eşleşen Ayraca Taşı</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2041"/>
+        <source>Select to Matching Brace</source>
+        <translation>Eşleşen Ayraç Seçin</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2047"/>
+        <source>&amp;Next Bookmark</source>
+        <translation>&amp;Sonraki Yer İşareti</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2051"/>
+        <source>Pre&amp;vious Bookmark</source>
+        <translation>&amp;Önceki Yer İşareti</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2055"/>
+        <source>Toggle &amp;Bookmark</source>
+        <translation>&amp;Yer İşaretini Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2059"/>
+        <source>&amp;Remove All Bookmarks</source>
+        <translation>Tüm Yer İşaretlerini &amp;Kaldır</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2066"/>
+        <source>&amp;Preferences...</source>
+        <translation>&amp;Tercihler...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2071"/>
+        <source>&amp;Styles Preferences...</source>
+        <translation>&amp;Stil Tercihleri...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2076"/>
+        <source>&amp;View</source>
+        <translation>&amp;Görünüm</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2078"/>
+        <source>&amp;Editor</source>
+        <translation>&amp;Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2081"/>
+        <source>Show &amp;Line Numbers</source>
+        <translation>&amp;Satır Numaralarını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2086"/>
+        <source>Show &amp;Whitespace Characters</source>
+        <translation>&amp;Boşluk Karakterlerini Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2091"/>
+        <source>Show Line &amp;Endings</source>
+        <translation>Satır &amp;Sonlarını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2096"/>
+        <source>Show &amp;Indentation Guides</source>
+        <translation>Girinti &amp;Kılavuzlarını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2101"/>
+        <source>Show Long Line &amp;Marker</source>
+        <translation>Uzun Çizgi &amp;İşaretleyiciyi Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2108"/>
+        <source>Show &amp;Toolbar</source>
+        <translation>&amp;Araç Çubuğunu Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2113"/>
+        <source>Show &amp;Statusbar</source>
+        <translation>&amp;Durum çubuğunu Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2118"/>
+        <source>Show &amp;Horizontal Scrollbar</source>
+        <translation>&amp;Yatay Kaydırma Çubuğunu Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2125"/>
+        <source>Zoom &amp;In</source>
+        <translation>&amp;Yaklaştır</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2129"/>
+        <source>Zoom &amp;Out</source>
+        <translation>&amp;Uzaklaş</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2133"/>
+        <source>&amp;Normal Size</source>
+        <translation>&amp;Normal Boyut</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2138"/>
+        <source>&amp;Sort Tabs Alphabetically</source>
+        <translation>Sekmeleri Alfabetik Olarak &amp;Sırala</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2146"/>
+        <source>&amp;Debug</source>
+        <translation>&amp;Hata Ayıklama</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2150"/>
+        <source>Toggle &amp;Breakpoint</source>
+        <translation>&amp;Kesme Noktasını Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2155"/>
+        <source>&amp;Next Breakpoint</source>
+        <translation>&amp;Sonraki Kesme Noktası</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2160"/>
+        <source>Pre&amp;vious Breakpoint</source>
+        <translation>Önc&amp;eki Kesme Noktası</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2165"/>
+        <source>&amp;Remove All Breakpoints</source>
+        <translation>Tüm Kesme Noktalarını &amp;Kaldır</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2174"/>
+        <source>&amp;Run</source>
+        <translation>&amp;Çalıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="186"/>
+        <source>Save File and Run</source>
+        <translation>Dosyayı Kaydet ve Çalıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="179"/>
+        <source>Continue</source>
+        <translation>Devam</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2179"/>
+        <source>Save File and Run / Continue</source>
+        <translation>Dosyayı Kaydet ve Çalıştır / Devam et</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2184"/>
+        <source>Run &amp;Selection</source>
+        <translation>&amp;Seçimi Çalıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2190"/>
+        <source>&amp;Help</source>
+        <translation>&amp;Yardım</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2194"/>
+        <source>&amp;Help on Keyword</source>
+        <translation>Anahtar Kelime &amp;Yardımı</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2199"/>
+        <source>&amp;Documentation on Keyword</source>
+        <translation>Anahtar Kelime ile ilgili &amp;Belgeler</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2224"/>
+        <source>Recent Files</source>
+        <translation>Son Dosyalar</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor.cc" line="2293"/>
+        <source>Editor</source>
+        <translation>Düzenleyici</translation>
+    </message>
+</context>
+<context>
+    <name>octave::file_editor_tab</name>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="150"/>
+        <source>line:</source>
+        <translation>satır:</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="153"/>
+        <source>col:</source>
+        <translation>col:</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="160"/>
+        <source>encoding:</source>
+        <translation>kodlanıyor:</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="167"/>
+        <source>eol:</source>
+        <translation>eol:</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="424"/>
+        <source>Breakpoint condition</source>
+        <translation>Kesme Noktası durumu</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="480"/>
+        <source>ERROR: </source>
+        <translation>HATA: </translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="541"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1745"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1861"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2255"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2413"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2439"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2476"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2578"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2614"/>
+        <source>Octave Editor</source>
+        <translation>Oktave Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="542"/>
+        <source>Cannot add breakpoint to modified or unnamed file.
+Save and add breakpoint, or cancel?</source>
+        <translation>Değiştirilmiş veya adlandırılmamış dosyaya kesme noktası eklenemez.
+Kesme noktası kaydedip eklemek mi yoksa iptalmi edilsin?</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1420"/>
+        <source>Goto line</source>
+        <translation>Satıra git</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1421"/>
+        <source>Line number</source>
+        <translation>Satır numarası</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1548"/>
+        <source>Comment selected text</source>
+        <translation>Seçili metni yorumla</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1549"/>
+        <source>Comment string to use:
+</source>
+        <translation>Kullanılacak yorum dizesi:
+</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1685"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1742"/>
+        <source>&lt;unnamed&gt;</source>
+        <translation>&lt;isimsiz&gt;</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1736"/>
+        <source>Do you want to cancel closing, save or discard the changes?</source>
+        <translation>Kapatmayı iptal etmek, değişiklikleri kaydetmek veya atmak istiyor musunuz?</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1746"/>
+        <source>The file
+
+  %1
+
+is about to be closed but has been modified.  %2</source>
+        <translation>Dosya
+
+   %1
+
+kapatılmak üzere ancak değiştirildi.  %2</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1852"/>
+        <source>There were problems reading the file
+%1
+with the selected encoding %2.
+
+Modifying and saving the file might cause data loss!</source>
+        <translation>Dosyayı okurken sorunlar oluştu
+%1
+seçilen kodlama %2 ile.
+
+Dosyayı değiştirmek ve kaydetmek veri kaybına neden olabilir!</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1862"/>
+        <source>&amp;Edit anyway</source>
+        <translation>Yine de &amp;düzenle</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1863"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1920"/>
+        <source>Chan&amp;ge encoding</source>
+        <translation>Kodlamayı değiş&amp;tir</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1864"/>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1913"/>
+        <source>&amp;Close</source>
+        <translation>&amp;Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1924"/>
+        <source>Select new default encoding</source>
+        <translation>Yeni varsayılan kodlamayı seçin</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="1927"/>
+        <source>Please select a new encoding
+for reloading the current file.
+
+This does not change the default encoding.
+</source>
+        <translation>Lütfen yeni bir kodlama seçin
+mevcut dosyayı yeniden yüklemek için.
+
+Bu, varsayılan kodlamayı değiştirmez.
+</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2088"/>
+        <source>Debug or Save</source>
+        <translation>Hata Ayıklama veya Kaydetme</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2089"/>
+        <source>This file is currently being executed.
+Quit debugging and save?</source>
+        <translation>Bu dosya şu anda yürütülüyor.
+Hata ayıklamadan çıkılsın ve kaydedilsin mi?</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2256"/>
+        <source>Could not open file %1 for write:
+%2.</source>
+        <translation>%1 dosyası yazmak için açılamadı:
+%2.</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2440"/>
+        <source>The current encoding %1
+can not be applied.
+
+Please select another one!</source>
+        <translation>Mevcut kodlama %1
+uygulanamaz.
+
+Lütfen başka bir tane seçin!</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2477"/>
+        <source>The current editor contents can not be encoded
+with the selected encoding %1.
+Using it would result in data loss!
+
+Please select another one!</source>
+        <translation>Mevcut düzenleyici içeriği kodlanamaz
+seçilen kodlama %1 ile.
+Bunu kullanmak veri kaybına neden olur!
+
+Lütfen başka bir tane seçin!</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2335"/>
+        <source>Octave Files (*.m)</source>
+        <translation>Octave Dosyaları (*.m)</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2336"/>
+        <source>All Files (*)</source>
+        <translation>Tüm Dosyalar (*)</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2414"/>
+        <source>&quot;%1&quot;
+is not a valid identifier.
+
+If you keep this filename, you will not be able to
+call your script using its name as an Octave command.
+
+Do you want to choose another name?</source>
+        <translation>&quot;%1&quot;
+geçerli bir tanımlayıcı değil.
+
+Bu dosya adını saklarsanız, yapamazsınız
+adını Octave komutu olarak kullanarak betiğinizi çağırın.
+
+Başka bir isim seçmek ister misin?</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2579"/>
+        <source>It seems that &apos;%1&apos; has been modified by another application. Do you want to reload it?</source>
+        <translation>Görünüşe göre &apos;%1&apos; başka bir uygulama tarafından değiştirilmiş. Yeniden yüklemek ister misin?</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2608"/>
+        <source>
+
+Warning: The contents in the editor is modified!</source>
+        <translation>
+
+Uyarı: Editördeki içerik değiştirildi!</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/file-editor-tab.cc" line="2615"/>
+        <source>It seems that the file
+%1
+has been deleted or renamed. Do you want to save it now?%2</source>
+        <translation>Görünüşe göre dosya
+%1
+silindi veya yeniden adlandırıldı. Şimdi kaydetmek istiyor musunuz?%2</translation>
+    </message>
+</context>
+<context>
+    <name>octave::files_dock_widget</name>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="78"/>
+        <source>File Browser</source>
+        <translation>Dosya Gezgini</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="79"/>
+        <source>Browse your files</source>
+        <translation>Dosyalarınıza göz atın</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="84"/>
+        <source>File size</source>
+        <translation>Dosya boyutu</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="85"/>
+        <source>File type</source>
+        <translation>Dosya türü</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="86"/>
+        <source>Date modified</source>
+        <translation>Değiştirilme tarihi</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="87"/>
+        <source>Show hidden</source>
+        <translation>Gizlileri göster</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="88"/>
+        <source>Alternating row colors</source>
+        <translation>Alternatif satır renkleri</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="126"/>
+        <source>Enter the path or filename</source>
+        <translation>Yolu veya dosya adını girin</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="138"/>
+        <source>One directory up</source>
+        <translation>Bir dizin yukarı</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="141"/>
+        <source>Show Octave directory</source>
+        <translation>Oktave dizinini göster</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="143"/>
+        <source>Go to current Octave directory</source>
+        <translation>Mevcut Octave dizinine git</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="147"/>
+        <source>Set Octave directory</source>
+        <translation>Oktave dizinini ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="149"/>
+        <source>Set Octave directory to current browser directory</source>
+        <translation>Octave dizinini mevcut tarayıcı dizinine ayarlayın</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="153"/>
+        <source>Actions on current directory</source>
+        <translation>Mevcut dizindeki eylemler</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="156"/>
+        <source>Show Home Directory</source>
+        <translation>Ana Dizini Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="167"/>
+        <source>Set Browser Directory...</source>
+        <translation>Tarayıcı Dizini Ayarla...</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="171"/>
+        <location filename="../src/files-dock-widget.cc" line="568"/>
+        <source>Find Files...</source>
+        <translation>Dosyaları Bul...</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="175"/>
+        <location filename="../src/files-dock-widget.cc" line="581"/>
+        <source>New File...</source>
+        <translation>Yeni Dosya...</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="178"/>
+        <location filename="../src/files-dock-widget.cc" line="584"/>
+        <source>New Directory...</source>
+        <translation>Yeni Dizin...</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="230"/>
+        <source>Double-click to open file/folder, right click for alternatives</source>
+        <translation>Dosya/klasörü açmak için çift tıklayın, alternatifler için sağ tıklayın</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="521"/>
+        <source>Open</source>
+        <translation>Aç</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="526"/>
+        <source>Open in System File Explorer</source>
+        <translation>Sistem Dosya Gezgini&apos;nde Aç</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="531"/>
+        <source>Open in Text Editor</source>
+        <translation>Metin düzenleyicide aç</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="534"/>
+        <source>Copy Selection to Clipboard</source>
+        <translation>Seçimi Panoya Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="539"/>
+        <source>Run</source>
+        <translation>Çalıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="542"/>
+        <source>Load Data</source>
+        <translation>Veri yükle</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="548"/>
+        <source>Set Current Directory</source>
+        <translation>Mevcut Dizini Ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="551"/>
+        <source>Add to Path</source>
+        <translation>Yola Ekle</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="553"/>
+        <location filename="../src/files-dock-widget.cc" line="560"/>
+        <source>Selected Directories</source>
+        <translation>Seçilen Dizinler</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="555"/>
+        <location filename="../src/files-dock-widget.cc" line="562"/>
+        <source>Selected Directories and Subdirectories</source>
+        <translation>Seçilen Dizinler ve Alt Dizinler</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="558"/>
+        <source>Remove from Path</source>
+        <translation>Yoldan Kaldır</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="573"/>
+        <source>Rename...</source>
+        <translation>Yeniden adlandır...</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="575"/>
+        <source>Delete...</source>
+        <translation>Sil...</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="693"/>
+        <source>Rename file/directory</source>
+        <translation>Dosyayı/dizini yeniden adlandırın</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="694"/>
+        <source>Rename file/directory:
+</source>
+        <translation>Dosyayı/dizini yeniden adlandırın:
+</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="695"/>
+        <source>
+ to: </source>
+        <translation>
+ ya: </translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="726"/>
+        <location filename="../src/files-dock-widget.cc" line="740"/>
+        <source>Delete file/directory</source>
+        <translation>Dosyayı/dizini sil</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="727"/>
+        <source>Are you sure you want to delete
+</source>
+        <translation>Silmek istediğine emin misin
+</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="741"/>
+        <source>Can not delete a directory that is not empty</source>
+        <translation>Boş olmayan bir dizin silinemez</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="933"/>
+        <source>Set directory of file browser</source>
+        <translation>Dosya tarayıcısının dizinini ayarlayın</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="958"/>
+        <source>Create File</source>
+        <translation>Dosya Oluştur</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="959"/>
+        <source>Create file in
+</source>
+        <comment>String ends with \n!</comment>
+        <translation>İçinde dosya oluştur
+</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="961"/>
+        <source>New File.txt</source>
+        <translation>Yeni Dosya.txt</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="976"/>
+        <source>Create Directory</source>
+        <translation>Dizin Oluşturun</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="977"/>
+        <source>Create folder in
+</source>
+        <comment>String ends with \n!</comment>
+        <translation>İçinde klasör oluştur
+</translation>
+    </message>
+    <message>
+        <location filename="../src/files-dock-widget.cc" line="979"/>
+        <source>New Directory</source>
+        <translation>Yeni Dizin</translation>
+    </message>
+</context>
+<context>
+    <name>octave::final_page</name>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="319"/>
+        <source>Enjoy!</source>
+        <translation>Zevkli!</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="323"/>
+        <source>Previous</source>
+        <translation>Önceki</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="324"/>
+        <source>Finish</source>
+        <translation>Bitir</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="325"/>
+        <source>Cancel</source>
+        <translation>İptal</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="332"/>
+        <source>&lt;html&gt;&lt;body&gt;
+&lt;p&gt;We hope you find Octave to be a useful tool.&lt;/p&gt;
+&lt;p&gt;If you encounter problems, there are a number of ways to get help, including commercial support options, a mailing list, a wiki, and other community-based support channels.
+You can find more information about each of these by visiting &lt;a href=&quot;https://octave.org/support.html&quot;&gt;https://octave.org/support.html&lt;/a&gt; (opens in external browser).&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;body&gt;
+&lt;p&gt;Octave&apos;yi yararlı bir araç olarak bulacağınızı umuyoruz.&lt;/p&gt;
+&lt;p&gt;Sorunlarla karşılaşırsanız, ticari destek seçenekleri, bir posta listesi, bir wiki ve diğer topluluk tabanlı destek kanalları dahil olmak üzere yardım almanın birkaç yolu vardır.
+&lt;a href=&quot;https://octave.org/support.html&quot;&gt;https://octave.org/support.html&lt;/a&gt;(harici tarayıcıda açılır) adresini ziyaret ederek bunların her biri hakkında daha fazla bilgi bulabilirsiniz. .&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="353"/>
+        <source>&lt;html&gt;&lt;head&gt;
+&lt;style&gt;
+a:link { text-decoration: underline; color: #0000ff; }
+&lt;/style&gt;
+&lt;/head&gt;&lt;body&gt;
+&lt;p&gt;For more information about Octave:&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;Visit &lt;a href=&quot;https://octave.org&quot;&gt;https://octave.org&lt;/a&gt; (opens in external browser)&lt;/li&gt;
+&lt;li&gt;Get the documentation online as &lt;a href=&quot;https://www.gnu.org/software/octave/doc/interpreter/index.html&quot;&gt;html&lt;/a&gt;- or &lt;a href=&quot;https://www.gnu.org/software/octave/octave.pdf&quot;&gt;pdf&lt;/a&gt;-document (opens in external browser)&lt;/li&gt;
+&lt;li&gt;Open the documentation browser of the Octave GUI with the help menu&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head&gt;
+&lt;style&gt;
+a: link {text-decoration: underline; renk: # 0000ff; }
+&lt;/style&gt;
+&lt;/head&gt;&lt;body&gt;
+&lt;p&gt; Octave hakkında daha fazla bilgi için:&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;a href=&quot;https://octave.org&quot;&gt;https://octave.org &lt;/a&gt; adresini ziyaret edin (harici tarayıcıda açılır)&lt;/li&gt;
+&lt;li&gt;Belgeleri çevrimiçi olarak&lt;a href=&quot;https://www.gnu.org/software/octave/doc/interpreter/index.html&quot;&gt;html&lt;/a&gt;- veya &lt;a href=&quot;https: //www.gnu.org/software/octave/octave.pdf&quot;&gt;pdf&lt;/a&gt;-doküman (harici tarayıcıda açılır)&lt;/li&gt;
+&lt;li&gt;Yardım menüsü ile Octave GUI&apos;nin dokümantasyon tarayıcısını açın&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+</context>
+<context>
+    <name>octave::find_dialog</name>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="94"/>
+        <source>Editor: Find and Replace</source>
+        <translation>Düzenleyici: Bul ve Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="97"/>
+        <source>Find &amp;what:</source>
+        <translation>&amp;Ne buldun:</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="99"/>
+        <source>Enter text to search for</source>
+        <translation>Aranacak metni girin</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="105"/>
+        <source>Re&amp;place with:</source>
+        <translation>Şununla de&amp;ğiştir:</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="107"/>
+        <source>Enter new text replacing search hits</source>
+        <translation>Arama sonuçlarının yerini alan yeni metin girin</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="117"/>
+        <source>Match &amp;case</source>
+        <translation>&amp;Büyük/küçük harf eşleştir</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="118"/>
+        <source>Search from &amp;start</source>
+        <translation>&amp;Başlangıçta ara</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="119"/>
+        <source>&amp;Wrap while searching</source>
+        <translation>&amp;Arama sırasında sarın</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="121"/>
+        <source>&amp;Find Next</source>
+        <translation>&amp;Sonrakini Bul</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="122"/>
+        <source>Find &amp;Previous</source>
+        <translation>&amp;Öncekini Bul</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="123"/>
+        <source>&amp;Replace</source>
+        <translation>&amp;Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="124"/>
+        <source>Replace &amp;All</source>
+        <translation>&amp;Tümünü Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="126"/>
+        <source>&amp;More...</source>
+        <translation>&amp;Daha...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="139"/>
+        <source>&amp;Whole words</source>
+        <translation>&amp;Bütün kelimeler</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="140"/>
+        <source>Regular E&amp;xpressions</source>
+        <translation>D&amp;üzenli ifadeler</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="141"/>
+        <source>Search &amp;backward</source>
+        <translation>&amp;Geriye doğru ara</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="142"/>
+        <source>Search se&amp;lection</source>
+        <translation>Arama se&amp;çimi</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="306"/>
+        <source>Search from end</source>
+        <translation>Sonundan ara</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="308"/>
+        <source>Search from start</source>
+        <translation>Baştan ara</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="628"/>
+        <source>Replace Result</source>
+        <translation>Sonucu Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="629"/>
+        <source>%1 items replaced</source>
+        <translation>%1 öğe değiştirildi</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="643"/>
+        <source>Find Result</source>
+        <translation>Sonuç Bulundu</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/find-dialog.cc" line="644"/>
+        <source>No more matches found</source>
+        <translation>Başka eşleşme bulunamadı</translation>
+    </message>
+</context>
+<context>
+    <name>octave::find_files_dialog</name>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="61"/>
+        <source>Find Files</source>
+        <translation>Dosyaları Bul</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="72"/>
+        <source>Named:</source>
+        <translation>Adlandırılmış:</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="74"/>
+        <source>Enter the filename search expression</source>
+        <translation>Dosya adı arama ifadesini girin</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="79"/>
+        <source>Start in:</source>
+        <translation>Başla:</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="84"/>
+        <source>Enter the start directory</source>
+        <translation>Başlangıç dizinini girin</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="87"/>
+        <source>Browse...</source>
+        <translation>Gözat...</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="88"/>
+        <source>Browse for start directory</source>
+        <translation>Başlangıç dizinine göz atın</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="92"/>
+        <source>Search subdirectories</source>
+        <translation>Alt dizinlerde ara</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="94"/>
+        <source>Search recursively through directories for matching files</source>
+        <translation>Eşleşen dosyalar için dizinlerde yinelemeli olarak arama yapın</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="96"/>
+        <source>Include directory names</source>
+        <translation>Dizin adlarını dahil et</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="98"/>
+        <source>Include matching directories in search results</source>
+        <translation>Eşleşen dizinleri arama sonuçlarına dahil et</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="100"/>
+        <source>Name case insensitive</source>
+        <translation>Ad büyük / küçük harfe duyarlı değil</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="102"/>
+        <source>Set matching name is case insensitive</source>
+        <translation>Eşleşen adı ayarla büyük / küçük harf duyarlıdır</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="104"/>
+        <source>Contains text:</source>
+        <translation>Metin içerir:</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="105"/>
+        <source>Enter the file content search expression</source>
+        <translation>Dosya içeriği arama ifadesini girin</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="109"/>
+        <source>Text to match</source>
+        <translation>Eşleştirilecek metin</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="112"/>
+        <source>Text case insensitive</source>
+        <translation>Metin büyük / küçük harf duyarlılığı</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="114"/>
+        <source>Set text content is case insensitive</source>
+        <translation>Metin içeriği büyük/küçük harf duyarlı ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="125"/>
+        <source>Search results</source>
+        <translation>Arama Sonuçları</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="145"/>
+        <source>Idle.</source>
+        <translation>Boşta.</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="147"/>
+        <source>Find</source>
+        <translation>Bul</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="148"/>
+        <source>Start search for matching files</source>
+        <translation>Eşleşen dosyaları aramaya başlayın</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="152"/>
+        <source>Stop</source>
+        <translation>Dur</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="153"/>
+        <source>Stop searching</source>
+        <translation>Aramayı bırak</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="168"/>
+        <source>Filename/location</source>
+        <translation>Dosya adı/konumu</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="185"/>
+        <source>File contents</source>
+        <translation>Dosya içeriği</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="286"/>
+        <source>Searching...</source>
+        <translation>Aranıyor...</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="308"/>
+        <source>%1 match (es)</source>
+        <translation>%1 eşleşme</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-dialog.cc" line="324"/>
+        <source>Set search directory</source>
+        <translation>Arama dizinini ayarlayın</translation>
+    </message>
+</context>
+<context>
+    <name>octave::find_files_model</name>
+    <message>
+        <location filename="../src/find-files-model.cc" line="91"/>
+        <source>Filename</source>
+        <translation>Dosya Adı</translation>
+    </message>
+    <message>
+        <location filename="../src/find-files-model.cc" line="92"/>
+        <source>Directory</source>
+        <translation>Dizin</translation>
+    </message>
+</context>
+<context>
+    <name>octave::history_dock_widget</name>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="53"/>
+        <source>Browse and search the command history.</source>
+        <translation>Komut geçmişine göz atın ve arayın.</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="148"/>
+        <source>Copy</source>
+        <translation>Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="150"/>
+        <source>Evaluate</source>
+        <translation>Değerlendirme</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="152"/>
+        <source>Create script</source>
+        <translation>Komut dosyası oluştur</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="156"/>
+        <source>Hide filter</source>
+        <translation>Filtreyi gizle</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="159"/>
+        <source>Show filter</source>
+        <translation>Filtreyi göster</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="280"/>
+        <source>Double-click a command to transfer it to the Command Window.</source>
+        <translation>Komut Penceresine aktarmak için bir komutu çift tıklayın.</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="288"/>
+        <source>Enter text to filter the command history</source>
+        <translation>Komut geçmişini filtrelemek için metin girin</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="298"/>
+        <source>Filter</source>
+        <translation>Filtrele</translation>
+    </message>
+    <message>
+        <location filename="../src/history-dock-widget.cc" line="303"/>
+        <source>Command History</source>
+        <translation>Komut Geçmişi</translation>
+    </message>
+</context>
+<context>
+    <name>octave::initial_page</name>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="164"/>
+        <source>Welcome to Octave!</source>
+        <translation>Octave&apos;e hoş geldiniz!</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="167"/>
+        <source>Next</source>
+        <translation>Sonraki</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="168"/>
+        <source>Cancel</source>
+        <translation>İptal</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="177"/>
+        <source>&lt;html&gt;&lt;body&gt;
+&lt;p&gt;You seem to be using the Octave graphical interface for the first time on this computer.
+Click &apos;Next&apos; to create a configuration file and launch Octave.&lt;/p&gt;
+&lt;p&gt;The configuration file is stored in&lt;br&gt;%1.&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;body&gt;
+&lt;p&gt;Bu bilgisayarda Octave grafik arayüzünü ilk kez kullanıyor görünüyorsunuz.
+Bir yapılandırma dosyası oluşturmak ve Octave&apos;ı başlatmak için &apos;İleri&apos;yi tıklayın.&lt;/p&gt;
+&lt;p&gt;Yapılandırma dosyası şurada saklanır:&lt;br&gt;%1.&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+</context>
+<context>
+    <name>octave::label_dock_widget</name>
+    <message>
+        <location filename="../src/octave-dock-widget.cc" line="78"/>
+        <source>Undock widget</source>
+        <translation>Aracı ayır</translation>
+    </message>
+    <message>
+        <location filename="../src/octave-dock-widget.cc" line="86"/>
+        <source>Close widget</source>
+        <translation>Aracı kapat</translation>
+    </message>
+</context>
+<context>
+    <name>octave::main_window</name>
+    <message>
+        <location filename="../src/main-window.cc" line="403"/>
+        <source>Save Workspace As</source>
+        <translation>Çalışma Alanını Farklı Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="431"/>
+        <source>Load Workspace</source>
+        <translation>Çalışma Alanını Yükle</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="654"/>
+        <source>The release notes file &apos;%1&apos; is empty.</source>
+        <translation>Sürüm notları dosyası &apos;%1&apos; boş.</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="658"/>
+        <source>The release notes file &apos;%1&apos; cannot be read.</source>
+        <translation>&apos;%1&apos; sürüm notları dosyası okunamıyor.</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="670"/>
+        <source>Octave Release Notes</source>
+        <translation>Octave Sürüm Notları</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="750"/>
+        <source>Octave Community News</source>
+        <translation>Octave Topluluk Haberleri</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="835"/>
+        <location filename="../src/main-window.cc" line="2665"/>
+        <source>About Octave</source>
+        <translation>Octave hakkında</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="294"/>
+        <source>Octave</source>
+        <translation>Octave</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="295"/>
+        <source>Are you sure you want to exit Octave?</source>
+        <translation>Octave&apos;den çıkmak istediğinizden emin misiniz?</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="1002"/>
+        <location filename="../src/main-window.cc" line="2729"/>
+        <source>Browse directories</source>
+        <translation>Dizinlere göz atın</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="1263"/>
+        <source>Octave Files (*.m);;All Files (*)</source>
+        <translation>Octave Dosyaları (*.m);;Tüm Dosyalar (*)</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="1302"/>
+        <source>New Function</source>
+        <translation>Yeni İşlev</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="1303"/>
+        <source>New function name:
+</source>
+        <translation>Yeni işlev adı:
+</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="1353"/>
+        <source>%1 is a built-in, compiled or inline
+function and can not be edited.</source>
+        <translation>%1 yerleşik, derlenmiş veya satır içi
+işlevi ve düzenlenemez.</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="1394"/>
+        <source>Can not find function %1</source>
+        <translation>%1 işlevi bulunamıyor</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="1416"/>
+        <source>Octave Editor</source>
+        <translation>Oktave Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2327"/>
+        <source>&amp;File</source>
+        <translation>&amp;Dosya</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2333"/>
+        <source>Open...</source>
+        <translation>Aç...</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2335"/>
+        <source>Open an existing file in editor</source>
+        <translation>Düzenleyicide mevcut bir dosyayı açın</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2344"/>
+        <source>Load Workspace...</source>
+        <translation>Çalışma Alanını Yükle...</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2347"/>
+        <source>Save Workspace As...</source>
+        <translation>Çalışma Alanını Farklı Kaydet...</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2351"/>
+        <source>Exit</source>
+        <translation>Çık</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2370"/>
+        <source>New</source>
+        <translation>Yeni</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2374"/>
+        <source>New Script</source>
+        <translation>Yeni Komut Dosyası</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2377"/>
+        <source>New Function...</source>
+        <translation>Yeni İşlev...</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2381"/>
+        <source>New Figure</source>
+        <translation>Yeni Şekil</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2407"/>
+        <source>&amp;Edit</source>
+        <translation>&amp;Düzenle</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2413"/>
+        <source>Undo</source>
+        <translation>Geri Al</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2419"/>
+        <source>Copy</source>
+        <translation>Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2424"/>
+        <source>Paste</source>
+        <translation>Yapıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2429"/>
+        <source>Select All</source>
+        <translation>Tümünü Seç</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2433"/>
+        <source>Clear Clipboard</source>
+        <translation>Panoyu Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2439"/>
+        <source>Find Files...</source>
+        <translation>Dosyaları Bul...</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2444"/>
+        <source>Clear Command Window</source>
+        <translation>Komut Penceresini Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2447"/>
+        <source>Clear Command History</source>
+        <translation>Komut Geçmişini Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2450"/>
+        <source>Clear Workspace</source>
+        <translation>Çalışma Alanını Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2455"/>
+        <source>Set Path</source>
+        <translation>Yolu Ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2459"/>
+        <source>Preferences...</source>
+        <translation>Ayarlar...</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2512"/>
+        <source>De&amp;bug</source>
+        <translation>Hata &amp;Ayıklama</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2515"/>
+        <source>Step</source>
+        <translation>Adım</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2519"/>
+        <source>Step In</source>
+        <translation>İçeri Gir</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2523"/>
+        <source>Step Out</source>
+        <translation>Dışarı Çık</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2527"/>
+        <source>Continue</source>
+        <translation>Devam</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2536"/>
+        <source>Quit Debug Mode</source>
+        <translation>Hata Ayıklama Modundan Çık</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2585"/>
+        <source>&amp;Window</source>
+        <translation>&amp;Pencere</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2588"/>
+        <source>Show Command Window</source>
+        <translation>Komut Penceresini Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2591"/>
+        <source>Show Command History</source>
+        <translation>Komut Geçmişini Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2594"/>
+        <source>Show File Browser</source>
+        <translation>Dosya Tarayıcısını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2597"/>
+        <source>Show Workspace</source>
+        <translation>Çalışma Alanını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2600"/>
+        <source>Show Editor</source>
+        <translation>Düzenleyiciyi Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2603"/>
+        <source>Show Documentation</source>
+        <translation>Belgeleri Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2606"/>
+        <source>Show Variable Editor</source>
+        <translation>Değişken Düzenleyiciyi Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2611"/>
+        <source>Command Window</source>
+        <translation>Komut Penceresi</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2614"/>
+        <source>Command History</source>
+        <translation>Komut Geçmişi</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2617"/>
+        <source>File Browser</source>
+        <translation>Dosya Gezgini</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2620"/>
+        <source>Workspace</source>
+        <translation>Çalışma Alanı</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2623"/>
+        <source>Editor</source>
+        <translation>Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2626"/>
+        <location filename="../src/main-window.cc" line="2670"/>
+        <source>Documentation</source>
+        <translation>Belgelendirme</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2629"/>
+        <source>Variable Editor</source>
+        <translation>Değişken Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2634"/>
+        <source>Previous Widget</source>
+        <translation>Önceki Araçlar</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2639"/>
+        <source>Reset Default Window Layout</source>
+        <translation>Varsayılan Pencere Düzenini Sıfırla</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2644"/>
+        <source>&amp;Help</source>
+        <translation>&amp;Yardım</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2651"/>
+        <source>Report Bug</source>
+        <translation>Hata Bildir</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2654"/>
+        <source>Octave Packages</source>
+        <translation>Oktave Paketleri</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2657"/>
+        <source>Contribute</source>
+        <translation>Katkıda bulun</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2660"/>
+        <source>Donate to Octave</source>
+        <translation>Octave&apos;a Bağış Yapın</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2673"/>
+        <source>On Disk</source>
+        <translation>Diskte</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2676"/>
+        <source>Online</source>
+        <translation>Çevrimiçi</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2681"/>
+        <source>&amp;News</source>
+        <translation>&amp;Yenilikler</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2684"/>
+        <source>Release Notes</source>
+        <translation>Sürüm Notları</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2687"/>
+        <source>Community News</source>
+        <translation>Topluluk Haberleri</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2692"/>
+        <source>Toolbar</source>
+        <translation>Araç çubuğu</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2713"/>
+        <source>Enter directory name</source>
+        <translation>Dizin adını girin</translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2721"/>
+        <source>Current Directory: </source>
+        <translation>Mevcut Dizin: </translation>
+    </message>
+    <message>
+        <location filename="../src/main-window.cc" line="2726"/>
+        <source>One directory up</source>
+        <translation>Bir dizin yukarı</translation>
+    </message>
+</context>
+<context>
+    <name>octave::news_reader</name>
+    <message>
+        <location filename="../src/news-reader.cc" line="115"/>
+        <source>&lt;html&gt;
+&lt;body&gt;
+&lt;p&gt;
+Octave&apos;s community news source seems to be unavailable.
+&lt;/p&gt;
+&lt;p&gt;
+For the latest news, please check
+&lt;a href=&quot;https://octave.org/community-news.html&quot;&gt;https://octave.org/community-news.html&lt;/a&gt;
+when you have a connection to the web (link opens in an external browser).
+&lt;/p&gt;
+&lt;p&gt;
+&lt;small&gt;&lt;em&gt;&amp;mdash; The Octave Developers, </source>
+        <translation>&lt;html&gt;
+&lt;body&gt;
+&lt;p&gt;
+Octave&apos;ın topluluk haber kaynağı kullanılamıyor gibi görünüyor.
+&lt;/p&gt;
+&lt;p&gt;
+En son haberler için lütfen kontrol edin
+&lt;a href=&quot;https://octave.org/community-news.html&quot;&gt;https://octave.org/community-news.html&lt;/a&gt;
+web bağlantınız olduğunda (bağlantı harici bir tarayıcıda açılır).
+&lt;/p&gt;
+&lt;p&gt;
+&lt;small&gt;&lt;em&gt;&amp;mdash; Octave Geliştiricileri, </translation>
+    </message>
+    <message>
+        <location filename="../src/news-reader.cc" line="133"/>
+        <source>&lt;html&gt;
+&lt;body&gt;
+&lt;p&gt;
+Connecting to the web to display the latest Octave Community news has been disabled.
+&lt;/p&gt;
+&lt;p&gt;
+For the latest news, please check
+&lt;a href=&quot;https://octave.org/community-news.html&quot;&gt;https://octave.org/community-news.html&lt;/a&gt;
+when you have a connection to the web (link opens in an external browser)
+or enable web connections for news in Octave&apos;s network settings dialog.
+&lt;/p&gt;
+&lt;p&gt;
+&lt;small&gt;&lt;em&gt;&amp;mdash; The Octave Developers, </source>
+        <translation>&lt;html&gt;
+&lt;body&gt;
+&lt;p&gt;
+En son Octave Topluluğu haberlerini görüntülemek için web&apos;e bağlanma devre dışı bırakıldı.
+&lt;/p&gt;
+&lt;p&gt;
+En son haberler için lütfen kontrol edin
+&lt;a href=&quot;https://octave.org/community-news.html&quot;&gt;https://octave.org/community-news.html&lt;/a&gt;
+web bağlantınız olduğunda (bağlantı harici bir tarayıcıda açılır)
+veya Octave&apos;nin ağ ayarları iletişim kutusunda haberler için web bağlantılarını etkinleştirin.
+&lt;/p&gt;
+&lt;p&gt;
+&lt;small&gt;&lt;em&gt;&amp;mdash; Octave Geliştiricileri, </translation>
+    </message>
+</context>
+<context>
+    <name>octave::octave_dock_widget</name>
+    <message>
+        <location filename="../src/octave-dock-widget.cc" line="239"/>
+        <source>Hide widget</source>
+        <translation>Aracı gizle</translation>
+    </message>
+    <message>
+        <location filename="../src/octave-dock-widget.cc" line="315"/>
+        <source>Dock widget</source>
+        <translation>Dock aracı</translation>
+    </message>
+    <message>
+        <location filename="../src/octave-dock-widget.cc" line="363"/>
+        <source>Undock widget</source>
+        <translation>Aracı ayır</translation>
+    </message>
+</context>
+<context>
+    <name>octave::octave_qscintilla</name>
+    <message>
+        <location filename="../src/m-editor/octave-qscintilla.cc" line="294"/>
+        <source>Help on</source>
+        <translation>Yardım</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/octave-qscintilla.cc" line="296"/>
+        <source>Documentation on</source>
+        <translation>Belgeler</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/octave-qscintilla.cc" line="299"/>
+        <source>Edit</source>
+        <translation>Düzenle</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/octave-qscintilla.cc" line="314"/>
+        <source>dbstop if ...</source>
+        <translation>dbstop eğer ...</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/octave-qscintilla.cc" line="785"/>
+        <source>Octave Editor</source>
+        <translation>Oktave Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/octave-qscintilla.cc" line="786"/>
+        <source>Creating temporary files failed.
+Make sure you have write access to temp. directory
+%1
+
+&quot;Run Selection&quot; requires temporary files.</source>
+        <translation>Geçici dosyalar oluşturulamadı.
+Temp&apos;ye yazma erişiminiz olduğundan emin olun. dizin
+%1
+
+&quot;Seçimi Çalıştır&quot; geçici dosyalar gerektirir.</translation>
+    </message>
+    <message>
+        <location filename="../src/m-editor/octave-qscintilla.cc" line="1059"/>
+        <source>Press &apos;%1&apos; to replace all occurrences of &apos;%2&apos; with &apos;%3&apos;.</source>
+        <translation>Tüm &apos;%2&apos; oluşumlarını &apos;%3&apos; ile değiştirmek için &apos;%1&apos; tuşuna basın.</translation>
+    </message>
+</context>
+<context>
+    <name>octave::octave_txt_lexer</name>
+    <message>
+        <location filename="../src/m-editor/octave-txt-lexer.cc" line="43"/>
+        <source>Default</source>
+        <translation>Varsayılan</translation>
+    </message>
+</context>
+<context>
+    <name>octave::qt_interpreter_events</name>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="288"/>
+        <location filename="../src/qt-interpreter-events.cc" line="293"/>
+        <location filename="../src/qt-interpreter-events.cc" line="295"/>
+        <source>Create</source>
+        <translation>Oluştur</translation>
+    </message>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="288"/>
+        <location filename="../src/qt-interpreter-events.cc" line="319"/>
+        <source>Cancel</source>
+        <translation>İptal Et</translation>
+    </message>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="291"/>
+        <source>File
+%1
+does not exist. Do you want to create it?</source>
+        <translation>Dosya
+%1
+mevcut değil. Onu oluşturmak ister misin?</translation>
+    </message>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="293"/>
+        <source>Octave Editor</source>
+        <translation>Oktave Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="312"/>
+        <source>The file %1 does not exist in the load path.  To run or debug the function you are editing, you must either change to the directory %2 or add that directory to the load path.</source>
+        <translation>%1 dosyası yükleme yolunda mevcut değil.  Düzenlediğiniz işlevi çalıştırmak veya hatalarını ayıklamak için, %2 dizinine geçmelisiniz veya bu dizini yükleme yoluna eklemelisiniz.</translation>
+    </message>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="313"/>
+        <source>The file %1 is shadowed by a file with the same name in the load path. To run or debug the function you are editing, change to the directory %2.</source>
+        <translation>%1 dosyası, yükleme yolunda aynı ada sahip bir dosya tarafından gölgeleniyor. Düzenlediğiniz işlevi çalıştırmak veya hata ayıklamak için %2 dizinine geçin.</translation>
+    </message>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="315"/>
+        <source>Change Directory or Add Directory to Load Path</source>
+        <translation>Dizini Değiştirin veya Yolu Yüklemek İçin Dizin Ekleyin</translation>
+    </message>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="317"/>
+        <source>&amp;Change Directory</source>
+        <translation>Dizini &amp;Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/qt-interpreter-events.cc" line="318"/>
+        <source>&amp;Add Directory to Load Path</source>
+        <translation>Yükleme Yoluna Dizin &amp;Ekle</translation>
+    </message>
+</context>
+<context>
+    <name>octave::resource_manager</name>
+    <message>
+        <location filename="../src/resource-manager.cc" line="308"/>
+        <source>The settings file
+%1
+does not exist and can not be created.
+Make sure you have read and write permissions to
+%2
+
+Octave GUI must be closed now.</source>
+        <translation>Ayarlar dosyası
+%1
+mevcut değil ve oluşturulamaz.
+Okuma ve yazma izinleriniz olduğundan emin olun
+%2
+
+Octave ARAYÜZÜ şimdi kapatılmalıdır.</translation>
+    </message>
+    <message>
+        <location filename="../src/resource-manager.cc" line="314"/>
+        <source>Octave Critical Error</source>
+        <translation>Oktave Kritik Hata</translation>
+    </message>
+</context>
+<context>
+    <name>octave::set_path_dialog</name>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="64"/>
+        <source>Set Path</source>
+        <translation>Yolu Ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="68"/>
+        <source>All changes take effect immediately.</source>
+        <translation>Tüm değişiklikler hemen yürürlüğe girer.</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="70"/>
+        <source>Add Folder...</source>
+        <translation>Klasör Ekle...</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="74"/>
+        <source>Single Folder</source>
+        <translation>Tek Klasör</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="76"/>
+        <source>Folder with Subfolders</source>
+        <translation>Alt Klasörlü Klasör</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="79"/>
+        <source>Move to Top</source>
+        <translation>Yukarı Taşı</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="80"/>
+        <source>Move to Bottom</source>
+        <translation>En Alta Taşı</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="81"/>
+        <source>Move Up</source>
+        <translation>Yukarı Taşı</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="82"/>
+        <source>Move Down</source>
+        <translation>Aşağı Taşı</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="83"/>
+        <source>Remove</source>
+        <translation>Kaldır</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="85"/>
+        <source>Reload</source>
+        <translation>Tekrar Yükle</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="86"/>
+        <source>Save</source>
+        <translation>Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="88"/>
+        <source>Revert</source>
+        <translation>Geri Al</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="92"/>
+        <source>Revert Last Change</source>
+        <translation>Son Değişikliği Geri Al</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="94"/>
+        <source>Revert All Changes</source>
+        <translation>Tüm Değişiklikleri Geri Al</translation>
+    </message>
+    <message>
+        <location filename="../src/set-path-dialog.cc" line="188"/>
+        <source>Open Directory</source>
+        <translation>Dizin Aç</translation>
+    </message>
+</context>
+<context>
+    <name>octave::settings_dialog</name>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="105"/>
+        <source>Octave Preferences</source>
+        <translation>Oktave Tercihleri</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="106"/>
+        <source>Unable to save preferences.  Missing preferences file or unknown directory.</source>
+        <translation>Tercihler kaydedilemiyor.  Eksik tercihler dosyası veya bilinmeyen dizin.</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="122"/>
+        <location filename="../src/settings-dialog.cc" line="127"/>
+        <location filename="../src/settings-dialog.cc" line="832"/>
+        <source>System setting</source>
+        <translation>Sistem ayarı</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="371"/>
+        <source>IBeam Cursor</source>
+        <translation>Işınlama İmleci</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="372"/>
+        <source>Block Cursor</source>
+        <translation>İmleci Engelle</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="373"/>
+        <source>Underline Cursor</source>
+        <translation>İmleç Altı Çizili</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="542"/>
+        <source>Set Octave Startup Directory</source>
+        <translation>Octave Başlangıç Dizinini Ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="547"/>
+        <source>Set File Browser Startup Directory</source>
+        <translation>Dosya Tarayıcı Başlangıç Dizinini Ayarlayın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="1053"/>
+        <source>Enable attribute colors</source>
+        <translation>Öznitelik renklerini etkinleştir</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.cc" line="1056"/>
+        <source>Hide tools tips</source>
+        <translation>Araç ipuçlarını gizle</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-cs.h" line="68"/>
+        <source>foreground</source>
+        <translation>ön plan</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-cs.h" line="69"/>
+        <source>background</source>
+        <translation>arkaplan</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-cs.h" line="70"/>
+        <source>selection</source>
+        <translation>seçim</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-cs.h" line="71"/>
+        <source>cursor</source>
+        <translation>imleç</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ed.h" line="198"/>
+        <source>Top</source>
+        <translation>Üst</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ed.h" line="199"/>
+        <source>Bottom</source>
+        <translation>Alt</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ed.h" line="200"/>
+        <source>Left</source>
+        <translation>Sol</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ed.h" line="201"/>
+        <source>Right</source>
+        <translation>Sağ</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ve.h" line="67"/>
+        <source>Foreground</source>
+        <translation>Ön plan</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ve.h" line="68"/>
+        <source>Background</source>
+        <translation>Arkaplan</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ve.h" line="69"/>
+        <source>Selected Foreground</source>
+        <translation>Seçili Ön Plan</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ve.h" line="70"/>
+        <source>Selected Background</source>
+        <translation>Seçili Arka Plan</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ve.h" line="71"/>
+        <source>Alternate Background</source>
+        <translation>Alternatif Arka Plan</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ws.h" line="85"/>
+        <source>argument</source>
+        <translation>argüman</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ws.h" line="86"/>
+        <source>global</source>
+        <translation>evrensel</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ws.h" line="87"/>
+        <source>persistant</source>
+        <translation>kalıcı</translation>
+    </message>
+</context>
+<context>
+    <name>octave::setup_community_news</name>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="223"/>
+        <source>Community News</source>
+        <translation>Topluluk Haberleri</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="228"/>
+        <source>Previous</source>
+        <translation>Önceki</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="229"/>
+        <source>Next</source>
+        <translation>Sonraki</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="230"/>
+        <source>Cancel</source>
+        <translation>İptal</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="237"/>
+        <source>&lt;html&gt;&lt;body&gt;
+&lt;p&gt;When Octave starts, it will optionally check the Octave web site for current news and information about the Octave community.
+The check will happen at most once each day and news will only be displayed if there is something new since the last time you viewed the news.&lt;/p&gt;
+&lt;p&gt;You may also view the news by selecting the &quot;Community News&quot; item in the &quot;Help&quot; menu, or by visiting
+&lt;a href=&quot;https://octave.org/community-news.html&quot;&gt;https://octave.org/community-news.html&lt;/a&gt;.&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;body&gt;
+&lt;p&gt;Octave başladığında, Octave topluluğu hakkında güncel haberler ve bilgiler için isteğe bağlı olarak Octave web sitesini kontrol edecektir.
+Kontrol her gün en fazla bir kez yapılacak ve haberler yalnızca haberleri son görüntülemenizden bu yana yeni bir şey olması durumunda gösterilecektir.&lt;/p&gt;
+&lt;p&gt;&quot;Yardım&quot; menüsünde &quot;Topluluk Haberleri&quot; öğesini seçerek veya şu adresi ziyaret ederek de haberleri görüntüleyebilirsiniz:
+&lt;a href=&quot;https://octave.org/community-news.html&quot;&gt;https://octave.org/community-news.html&lt;/a&gt;.&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="267"/>
+        <source>&lt;html&gt;&lt;head&gt;
+&lt;style&gt;
+a:link { text-decoration: underline; color: #0000ff; }
+&lt;/style&gt;
+&lt;/head&gt;&lt;body&gt;
+&lt;p&gt;Allow Octave to connect to the Octave web site when it starts to display current news and information about the Octave community.&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head&gt;
+&lt;style&gt;
+a:link { text-decoration: underline; color: #0000ff; }
+&lt;/style&gt;
+&lt;/head&gt;&lt;body&gt;
+&lt;p&gt;Octave topluluğu hakkında güncel haberleri ve bilgileri görüntülemeye başladığında Octave&apos;nin Octave web sitesine bağlanmasına izin verin.&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+</context>
+<context>
+    <name>octave::shortcut_manager</name>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="582"/>
+        <source>Double Shortcut</source>
+        <translation>Çift Kısayol</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="583"/>
+        <source>The chosen shortcut
+  &quot;%1&quot;
+is already used for the action
+  &quot;%2&quot;.
+Do you want to use the shortcut anyhow removing it from the previous action?</source>
+        <translation>Seçilen kısayol
+  &quot;%1&quot;
+eylem için zaten kullanılıyor
+  &quot;%2&quot;.
+Kısayolu bir önceki eylemden kaldırarak kullanmak istiyor musunuz?</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="143"/>
+        <source>New File</source>
+        <translation>Yeni Dosya</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="137"/>
+        <source>Undock/Dock Widget</source>
+        <oldsource>Undock widget</oldsource>
+        <translation>Undock/Dock Widget</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="138"/>
+        <source>Close Widget</source>
+        <oldsource>Close widget</oldsource>
+        <translation>Aracı kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="144"/>
+        <source>New Function</source>
+        <translation>Yeni İşlev</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="145"/>
+        <source>New Figure</source>
+        <translation>Yeni Şekil</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="146"/>
+        <source>Open File</source>
+        <translation>Dosya Aç</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="147"/>
+        <source>Load Workspace</source>
+        <translation>Çalışma Alanını Yükle</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="148"/>
+        <source>Save Workspace As</source>
+        <translation>Çalışma Alanını Farklı Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="149"/>
+        <source>Exit Octave</source>
+        <translation>Oktave`dan Çık</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="152"/>
+        <source>Copy</source>
+        <translation>Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="153"/>
+        <source>Paste</source>
+        <translation>Yapıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="154"/>
+        <source>Undo</source>
+        <translation>Geri al</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="155"/>
+        <source>Select All</source>
+        <translation>Tümünü Seç</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="156"/>
+        <source>Clear Clipboard</source>
+        <translation>Panoyu Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="157"/>
+        <source>Find in Files</source>
+        <translation>Dosyalarda Bul</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="158"/>
+        <source>Clear Command Window</source>
+        <translation>Komut Penceresini Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="159"/>
+        <source>Clear Command History</source>
+        <translation>Komut Geçmişini Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="160"/>
+        <source>Clear Workspace</source>
+        <translation>Çalışma Alanını Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="161"/>
+        <source>Set Path</source>
+        <translation>Yolu Ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="162"/>
+        <location filename="../src/shortcut-manager.cc" line="274"/>
+        <source>Preferences</source>
+        <translation>Seçenekler</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="165"/>
+        <source>Step</source>
+        <translation>Adım</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="166"/>
+        <source>Step Into</source>
+        <translation>İçeri Gir</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="167"/>
+        <source>Step Out</source>
+        <translation>Dışarı Çık</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="168"/>
+        <source>Continue</source>
+        <translation>Devam</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="169"/>
+        <source>Quit Debug Mode</source>
+        <translation>Hata Ayıklama Modundan Çık</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="172"/>
+        <source>Show Command Window</source>
+        <translation>Komut Penceresini Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="173"/>
+        <source>Show Command History</source>
+        <translation>Komut Geçmişini Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="174"/>
+        <source>Show File Browser</source>
+        <translation>Dosya Tarayıcısını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="175"/>
+        <source>Show Workspace</source>
+        <translation>Çalışma Alanını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="176"/>
+        <source>Show Editor</source>
+        <translation>Düzenleyiciyi Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="177"/>
+        <source>Show Documentation</source>
+        <translation>Belgelendirmeyi Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="178"/>
+        <source>Show Variable Editor</source>
+        <translation>Değişken Düzenleyiciyi Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="179"/>
+        <source>Command Window</source>
+        <translation>Komut Penceresi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="180"/>
+        <source>Command History</source>
+        <translation>Komut Geçmişi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="181"/>
+        <source>File Browser</source>
+        <translation>Dosya Gezgini</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="182"/>
+        <source>Workspace</source>
+        <translation>Çalışma Alanı</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="183"/>
+        <location filename="../src/shortcut-manager.cc" line="417"/>
+        <source>Editor</source>
+        <translation>Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="184"/>
+        <source>Documentation</source>
+        <translation>Belgelendirme</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="185"/>
+        <source>Variable Editor</source>
+        <translation>Değişken Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="186"/>
+        <source>Previous Widget</source>
+        <oldsource>Previous pages</oldsource>
+        <translation>Önceki Araçlar</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="187"/>
+        <source>Reset Default Window Layout</source>
+        <translation>Varsayılan Pencere Düzenini Sıfırla</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="190"/>
+        <source>Show Ondisk Documentation</source>
+        <translation>Belgelendirmeyi Diskte Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="191"/>
+        <source>Show Online Documentation</source>
+        <translation>Çevrimiçi Belgeleri Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="192"/>
+        <source>Report Bug</source>
+        <translation>Hata Bildir</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="193"/>
+        <source>Octave Packages</source>
+        <translation>Oktave Paketleri</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="194"/>
+        <source>Contribute to Octave</source>
+        <translation>Oktave`ya Katkıda Bulun</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="195"/>
+        <source>Octave Developer Resources</source>
+        <translation>Octave Geliştirici Kaynakları</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="196"/>
+        <source>About Octave</source>
+        <translation>Octave Hakkında</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="199"/>
+        <source>Release Notes</source>
+        <translation>Sürüm Notları</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="200"/>
+        <source>Community News</source>
+        <translation>Topluluk Haberleri</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="205"/>
+        <source>Close Tab</source>
+        <translation>Sekmeyi Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="206"/>
+        <source>Close All Tabs</source>
+        <translation>Tüm Sekmeleri Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="207"/>
+        <source>Close Other Tabs</source>
+        <translation>Diğer Sekmeleri Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="208"/>
+        <source>Switch to Left Tab</source>
+        <translation>Sol Sekmeye Geç</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="209"/>
+        <source>Switch to Right Tab</source>
+        <translation>Sağ Sekmeye Geç</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="210"/>
+        <source>Move Tab Left</source>
+        <translation>Sekmeyi Sola Taşı</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="211"/>
+        <source>Move Tab Right</source>
+        <translation>Sekmeyi Sağa Taşı</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="225"/>
+        <source>Edit Function</source>
+        <translation>Düzenleme İşlevi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="226"/>
+        <source>Save File</source>
+        <translation>Dosyayı Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="227"/>
+        <source>Save File As</source>
+        <translation>Dosyayı Farklı Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="228"/>
+        <source>Print</source>
+        <translation>Yazdır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="231"/>
+        <source>Redo</source>
+        <translation>Yinele</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="232"/>
+        <source>Cut</source>
+        <translation>Kes</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="233"/>
+        <source>Find and Replace</source>
+        <translation>Bul ve Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="234"/>
+        <source>Find Next</source>
+        <translation>Sonraki Bul</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="235"/>
+        <source>Find Previous</source>
+        <translation>Öncekini Bul</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="236"/>
+        <source>Delete to Start of Word</source>
+        <translation>Kelimenin Başını Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="237"/>
+        <source>Delete to End of Word</source>
+        <translation>Kelimenin Sonuna Kadar Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="238"/>
+        <source>Delete to Start of Line</source>
+        <translation>Satırın Başına Kadar Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="239"/>
+        <source>Delete to End of Line</source>
+        <translation>Satırın Sonuna Kadar Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="240"/>
+        <source>Delete Line</source>
+        <translation>Satırı Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="241"/>
+        <source>Copy Line</source>
+        <translation>Satırı Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="242"/>
+        <source>Cut Line</source>
+        <translation>Satır Kes</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="243"/>
+        <source>Duplicate Selection/Line</source>
+        <translation>Yinelenen Seçim/Satır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="244"/>
+        <source>Transpose Line</source>
+        <translation>Satırı Aktar</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="245"/>
+        <source>Show Completion List</source>
+        <translation>Tamamlama Listesini Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="247"/>
+        <source>Comment Selection</source>
+        <translation>Yorum Seçimi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="248"/>
+        <source>Uncomment Selection</source>
+        <translation>Açıklamayı Kaldır Seçimi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="249"/>
+        <source>Comment Selection (Choosing String)</source>
+        <translation>Yorum Seçimi (Dize Seçme)</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="250"/>
+        <source>Uppercase Selection</source>
+        <translation>Büyük Harf Seçimi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="251"/>
+        <source>Lowercase Selection</source>
+        <translation>Küçük Harf Seçimi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="254"/>
+        <location filename="../src/shortcut-manager.cc" line="257"/>
+        <source>Indent Selection Rigidly</source>
+        <translation>Sert Girinti Seçimi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="255"/>
+        <location filename="../src/shortcut-manager.cc" line="258"/>
+        <source>Unindent Selection Rigidly</source>
+        <translation>Seçimi Katı Şekilde Çöz</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="260"/>
+        <source>Indent Code</source>
+        <translation>Girinti Kodu</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="262"/>
+        <source>Convert Line Endings to Windows</source>
+        <translation>Satır Sonlarını Windows&apos;a Dönüştür</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="263"/>
+        <source>Convert Line Endings to Unix</source>
+        <translation>Satır Sonlarını Unix&apos;e Dönüştür</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="264"/>
+        <source>Convert Line Endings to Mac</source>
+        <translation>Satır Sonlarını Mac&apos;e Dönüştür</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="266"/>
+        <source>Goto Line</source>
+        <translation>Satıra Git</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="267"/>
+        <source>Move to Matching Brace</source>
+        <translation>Eşleşen Ayraca Taşı</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="268"/>
+        <source>Select to Matching Brace</source>
+        <translation>Eşleşen Ayraç Seçin</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="269"/>
+        <source>Toggle Bookmark</source>
+        <translation>Yer İşaretini Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="270"/>
+        <source>Next Bookmark</source>
+        <translation>Sonraki Yer İmi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="271"/>
+        <source>Previous Bookmark</source>
+        <translation>Önceki Yer İmi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="272"/>
+        <source>Remove All Bookmark</source>
+        <translation>Tüm Yer İşaretlerini Kaldır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="275"/>
+        <source>Styles Preferences</source>
+        <translation>Stil Tercihleri</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="278"/>
+        <source>Show Line Numbers</source>
+        <translation>Satır Numaralarını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="279"/>
+        <source>Show Whitespace Characters</source>
+        <translation>Boşluk Karakterlerini Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="280"/>
+        <source>Show Line Endings</source>
+        <translation>Satır Sonlarını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="281"/>
+        <source>Show Indentation Guides</source>
+        <translation>Girinti Kılavuzlarını Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="282"/>
+        <source>Show Long Line Marker</source>
+        <translation>Uzun Çizgi İşaretleyiciyi Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="283"/>
+        <source>Show Toolbar</source>
+        <translation>Araç Çubuğunu Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="284"/>
+        <source>Show Statusbar</source>
+        <translation>Durum çubuğunu göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="285"/>
+        <source>Show Horizontal Scrollbar</source>
+        <translation>Yatay Kaydırma Çubuğunu Göster</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="286"/>
+        <source>Sort Tabs Alphabetically</source>
+        <translation>Sekmeleri Alfabetik Olarak Sırala</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="397"/>
+        <source>Handling of Dock Widgets</source>
+        <oldsource>Tab Handling in Dock Widgets</oldsource>
+        <translation>Dock Araçların kullanımı</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="440"/>
+        <source>Documentation Viewer</source>
+        <translation>Belge Görüntüleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="444"/>
+        <source>Browser</source>
+        <translation>Gözat</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="524"/>
+        <source>Import shortcuts from file...</source>
+        <translation>Kısayolları dosyadan içe aktar...</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="529"/>
+        <source>Export shortcuts to file...</source>
+        <translation>Kısayolları dosyaya aktar...</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="540"/>
+        <source>Failed to open %1 as Octave shortcut file</source>
+        <translation>%1 Oktave kısayol dosyası olarak açılamadı</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="214"/>
+        <source>Zoom In</source>
+        <translation>Yaklaştır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="215"/>
+        <source>Zoom Out</source>
+        <translation>Uzaklaştır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="217"/>
+        <location filename="../src/shortcut-manager.cc" line="219"/>
+        <source>Zoom Normal</source>
+        <translation>Yaklaştırma Normal</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="289"/>
+        <source>Toggle Breakpoint</source>
+        <translation>Kesme Noktasını Aç/Kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="290"/>
+        <source>Next Breakpoint</source>
+        <translation>Sonraki Kesme Noktası</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="291"/>
+        <source>Previous Breakpoint</source>
+        <translation>Önceki Kesme Noktası</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="292"/>
+        <source>Remove All Breakpoints</source>
+        <translation>Tüm Kesme Noktalarını Kaldır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="295"/>
+        <source>Run File</source>
+        <translation>Dosyayı Çalıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="296"/>
+        <source>Run Selection</source>
+        <translation>Seçimi Çalıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="299"/>
+        <source>Help on Keyword</source>
+        <translation>Anahtar Kelime Yardımı</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="300"/>
+        <source>Document on Keyword</source>
+        <translation>Anahtar Kelime Belgesi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="304"/>
+        <source>Go to Homepage</source>
+        <translation>Ana sayfaya Git</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="305"/>
+        <source>Go Back one Page</source>
+        <translation>Go Back one Page</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="306"/>
+        <source>Go Forward one Page</source>
+        <translation>Bir Sayfa İleri Git</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="382"/>
+        <source>Global</source>
+        <translation>Evrensel</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="385"/>
+        <location filename="../src/shortcut-manager.cc" line="420"/>
+        <source>File Menu</source>
+        <translation>Dosya menüsü</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="387"/>
+        <location filename="../src/shortcut-manager.cc" line="422"/>
+        <source>Edit Menu</source>
+        <translation>Düzenle Menüsü</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="389"/>
+        <location filename="../src/shortcut-manager.cc" line="426"/>
+        <source>Debug Menu</source>
+        <translation>Hata Ayıklama Menüsü</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="391"/>
+        <source>Window Menu</source>
+        <translation>Pencere Menüsü</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="393"/>
+        <location filename="../src/shortcut-manager.cc" line="430"/>
+        <source>Help Menu</source>
+        <translation>Yardım Menüsü</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="395"/>
+        <source>News Menu</source>
+        <translation>Haber Menüsü</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="399"/>
+        <source>Tab Handling in Dock Widgets</source>
+        <translation>Dock Araçların`da Sekme İşleme</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="401"/>
+        <source>Find &amp; Replace in Dock Widgets</source>
+        <translation>Dock Araçların`da Bul ve Değiştir</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="403"/>
+        <source>Zooming in Editor and Documentation</source>
+        <translation>Yaklaştırma Düzenleyicisi ve Belgelendirmesi</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="424"/>
+        <source>View Menu</source>
+        <translation>Menüyü Görüntüle</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="428"/>
+        <source>Run Menu</source>
+        <translation>Çalıştır Menüsü</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="525"/>
+        <location filename="../src/shortcut-manager.cc" line="530"/>
+        <source>Octave Shortcut Files (*.osc);;All Files (*)</source>
+        <translation>Oktave Kısayol Dosyaları (*.osc);;Tüm Dosyalar (*)</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="653"/>
+        <source>Enter new Shortcut</source>
+        <translation>Yeni Kısayol girin</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="659"/>
+        <source>Apply the desired shortcut or click on the right button to reset the shortcut to its default.</source>
+        <translation>Kısayolu varsayılanına sıfırlamak için istenen kısayolu uygulayın veya sağ düğmeye tıklayın.</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="666"/>
+        <source>Enter shortcut directly by performing it</source>
+        <translation>Doğrudan uygulayarak kısayolu girin</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="669"/>
+        <source>Add Shift modifier
+(allows to enter number keys)</source>
+        <translation>Shift değiştirici ekle
+(sayı tuşlarının girilmesine izin verir)</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="687"/>
+        <source>Actual shortcut</source>
+        <translation>Gerçek kısayol</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="693"/>
+        <source>Default shortcut</source>
+        <translation>Varsayılan kısayol</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="699"/>
+        <source>Set to default</source>
+        <translation>Varsayılan olarak ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="766"/>
+        <source>Overwriting Shortcuts</source>
+        <translation>Kısayolların Üzerine Yazma</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="768"/>
+        <source>You are about to overwrite all shortcuts.
+Would you like to save the current shortcut set or cancel the action?</source>
+        <translation>Tüm kısayolların üzerine yazmak üzeresiniz.
+Mevcut kısayol kümesini kaydetmek mi yoksa eylemi iptal etmek mi istersiniz?</translation>
+    </message>
+    <message>
+        <location filename="../src/shortcut-manager.cc" line="771"/>
+        <source>Don&apos;t save</source>
+        <translation>Kaydetme</translation>
+    </message>
+</context>
+<context>
+    <name>octave::terminal_dock_widget</name>
+    <message>
+        <location filename="../src/terminal-dock-widget.cc" line="53"/>
+        <source>Command Window</source>
+        <translation>Komut Penceresi</translation>
+    </message>
+</context>
+<context>
+    <name>octave::variable_dock_widget</name>
+    <message>
+        <location filename="../src/variable-editor.cc" line="187"/>
+        <source>Dock widget</source>
+        <translation>Dock aracı</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="190"/>
+        <source>Variable Editor: </source>
+        <oldsource>Variable Editor</oldsource>
+        <translation>Değişken Düzenleyici: </translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="204"/>
+        <source>Undock widget</source>
+        <translation>Aracı ayır</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="227"/>
+        <source>Restore geometry</source>
+        <translation>Geometriyi geri yükle</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="230"/>
+        <source>Redock</source>
+        <translation>Redock</translation>
+    </message>
+</context>
+<context>
+    <name>octave::variable_editor</name>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1067"/>
+        <source>Variable Editor</source>
+        <translation>Değişken Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1068"/>
+        <source>Edit variables.</source>
+        <translation>Değişkenleri düzenleyin.</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1600"/>
+        <source>Variable Editor Toolbar</source>
+        <translation>Değişken Düzenleyici Araç Çubuğu</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1605"/>
+        <source>Save</source>
+        <translation>Kaydet</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1610"/>
+        <source>Save variable to a file</source>
+        <translation>Değişkeni bir dosyaya kaydedin</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1614"/>
+        <source>Cut</source>
+        <translation>Kes</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1616"/>
+        <source>Cut data to clipboard</source>
+        <translation>Verileri panoya kesin</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1618"/>
+        <source>Copy</source>
+        <translation>Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1620"/>
+        <source>Copy data to clipboard</source>
+        <translation>Verileri panoya kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1622"/>
+        <source>Paste</source>
+        <translation>Yapıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1624"/>
+        <source>Paste clipboard into variable data</source>
+        <translation>Panoyu değişken verilere yapıştırın</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1632"/>
+        <location filename="../src/variable-editor.cc" line="1637"/>
+        <location filename="../src/variable-editor.cc" line="1644"/>
+        <source>Plot</source>
+        <translation>Arsa</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1633"/>
+        <source>Plot Selected Data</source>
+        <translation>Seçilen Verilerin Grafiğini Çizin</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1638"/>
+        <source>Plot selected data</source>
+        <translation>Seçili verilerin grafiğini çizin</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1658"/>
+        <source>Up</source>
+        <translation>Yukarı</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="1660"/>
+        <source>Go one level up in variable hierarchy</source>
+        <translation>Değişken hiyerarşisinde bir seviye yukarı çıkın</translation>
+    </message>
+    <message>
+        <source>Background</source>
+        <translation type="vanished">Arkaplan</translation>
+    </message>
+</context>
+<context>
+    <name>octave::variable_editor_stack</name>
+    <message>
+        <location filename="../src/variable-editor.cc" line="472"/>
+        <source>Save Variable %1 As</source>
+        <translation>%1 Değişkenini Farklı Kaydet</translation>
+    </message>
+</context>
+<context>
+    <name>octave::variable_editor_view</name>
+    <message>
+        <location filename="../src/variable-editor.cc" line="600"/>
+        <source>Cut</source>
+        <translation>Kes</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="604"/>
+        <source>Copy</source>
+        <translation>Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="608"/>
+        <source>Paste</source>
+        <translation>Yapıştır</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="614"/>
+        <source>Clear</source>
+        <translation>Temizle</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="618"/>
+        <source>Delete</source>
+        <translation>Sil</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="622"/>
+        <source>Variable from Selection</source>
+        <translation>Seçimden Değişken</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="640"/>
+        <source>Transpose</source>
+        <translation>Aktar</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="690"/>
+        <source> columns</source>
+        <translation> sütunlar</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="690"/>
+        <source> column</source>
+        <translation> sütun</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="737"/>
+        <source> rows</source>
+        <translation> satırlar</translation>
+    </message>
+    <message>
+        <location filename="../src/variable-editor.cc" line="737"/>
+        <source> row</source>
+        <translation> satır</translation>
+    </message>
+</context>
+<context>
+    <name>octave::welcome_wizard</name>
+    <message>
+        <location filename="../src/welcome-wizard.cc" line="69"/>
+        <source>Welcome to GNU Octave</source>
+        <translation>GNU Octave&apos;e hoş geldiniz</translation>
+    </message>
+</context>
+<context>
+    <name>octave::workspace_model</name>
+    <message>
+        <location filename="../src/workspace-model.cc" line="47"/>
+        <source>Name</source>
+        <translation>İsim</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-model.cc" line="48"/>
+        <source>Class</source>
+        <translation>Sınıf</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-model.cc" line="49"/>
+        <source>Dimension</source>
+        <translation>Boyut</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-model.cc" line="50"/>
+        <source>Value</source>
+        <translation>Değer</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-model.cc" line="51"/>
+        <source>Attribute</source>
+        <translation>Öznitelik</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-model.cc" line="134"/>
+        <source>Right click to copy, rename, or display</source>
+        <translation>Kopyalamak, yeniden adlandırmak veya görüntülemek için sağ tıklayın</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-model.cc" line="164"/>
+        <location filename="../src/workspace-model.cc" line="166"/>
+        <source>complex</source>
+        <translation>karmaşık</translation>
+    </message>
+</context>
+<context>
+    <name>octave::workspace_view</name>
+    <message>
+        <location filename="../src/workspace-view.cc" line="62"/>
+        <source>Workspace</source>
+        <translation>Çalışma Alanı</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="63"/>
+        <source>View the variables in the active workspace.</source>
+        <translation>Etkin çalışma alanındaki değişkenleri görüntüleyin.</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="65"/>
+        <source>Enter text to filter the workspace</source>
+        <translation>Çalışma alanını filtrelemek için metin girin</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="74"/>
+        <source>Filter</source>
+        <translation>Filtre</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="210"/>
+        <source>View the variables in the active workspace.&lt;br&gt;</source>
+        <translation>Etkin çalışma alanındaki değişkenleri görüntüleyin.&lt;b&gt;</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="211"/>
+        <source>Colors for variable attributes:</source>
+        <translation>Değişken nitelikler için renkler:</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="343"/>
+        <source>Open in Variable Editor</source>
+        <translation>Değişken Düzenleyicide Aç</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="346"/>
+        <source>Copy name</source>
+        <translation>Adını Kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="349"/>
+        <source>Copy value</source>
+        <translation>Değeri kopyala</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="352"/>
+        <source>Rename</source>
+        <translation>Yeniden adlandır</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="360"/>
+        <source>Only top-level symbols may be renamed</source>
+        <translation>Yalnızca üst düzey semboller yeniden adlandırılabilir</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="382"/>
+        <source>Hide filter</source>
+        <translation>Filtreyi gizle</translation>
+    </message>
+    <message>
+        <location filename="../src/workspace-view.cc" line="385"/>
+        <source>Show filter</source>
+        <translation>Filtreyi göster</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ws.h" line="58"/>
+        <source>Class</source>
+        <translation>Sınıf</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ws.h" line="59"/>
+        <source>Dimension</source>
+        <translation>Boyut</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ws.h" line="60"/>
+        <source>Value</source>
+        <translation>Değer</translation>
+    </message>
+    <message>
+        <location filename="../src/gui-preferences-ws.h" line="61"/>
+        <source>Attribute</source>
+        <translation>Öznitelik</translation>
+    </message>
+</context>
+<context>
+    <name>settings_dialog</name>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="42"/>
+        <location filename="../src/settings-dialog.ui" line="853"/>
+        <source>General</source>
+        <translation>Genel</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="202"/>
+        <source>Octave logo only</source>
+        <translation>Yalnızca Oktave logosu</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="212"/>
+        <source>Letter icons</source>
+        <translation>Mektup simgeleri</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="108"/>
+        <source>Dock widget title bar</source>
+        <translation>Dock aracı başlık çubuğu</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="132"/>
+        <source>Small</source>
+        <translation>Küçük</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="149"/>
+        <source>Large</source>
+        <translation>Büyük</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="339"/>
+        <source>Custom style</source>
+        <translation>Özel stil</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="371"/>
+        <source>3D</source>
+        <translation>3B</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="832"/>
+        <source>Editor</source>
+        <translation>Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1033"/>
+        <source>Color</source>
+        <translation>Renk</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1420"/>
+        <location filename="../src/settings-dialog.ui" line="1560"/>
+        <source>This works well for monospaced fonts. The line is drawn at a position based on the width of a space character in the default font. It may not work very well if styles use proportional fonts or if varied font sizes or bold, italic and normal texts are used.</source>
+        <translation>Bu, tek aralıklı yazı tipleri için iyi çalışır. Çizgi, varsayılan yazı tipinde bir boşluk karakterinin genişliğine göre bir konumda çizilir. Stiller orantılı yazı tipi kullanırsa veya çeşitli yazı tipi boyutları veya kalın, italik ve normal metinler kullanılırsa çok iyi çalışmayabilir.</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="925"/>
+        <source>Enable Code Folding</source>
+        <translation>Kod Katlamayı Etkinleştir</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2084"/>
+        <source>Windows (CRLF)</source>
+        <translation>Windows (CRLF)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2089"/>
+        <source>Legacy Mac (CR)</source>
+        <translation>Eski Mac (CR)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2094"/>
+        <source>Unix (LF)</source>
+        <translation>Unix (LF)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="960"/>
+        <source>Show horizontal scroll bar</source>
+        <translation>Yatay kaydırma çubuğunu göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="941"/>
+        <source>Show tool bar</source>
+        <translation>Araç çubuğunu göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1563"/>
+        <source>Wrap long lines at current window border</source>
+        <translation>Uzun çizgileri geçerli pencere kenarlığında kaydır</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1578"/>
+        <source>Indentation</source>
+        <translation>Girinti</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1618"/>
+        <source>Indent width</source>
+        <translation>Girinti genişliği</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1625"/>
+        <source>Tab indents line</source>
+        <translation>Sekme girintileri satırı</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1645"/>
+        <source>Auto indentation</source>
+        <translation>Otomatik girinti</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1668"/>
+        <source>Tab width</source>
+        <translation>Sekme genişliği</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1675"/>
+        <source>Show indentation guides</source>
+        <translation>Girinti kılavuzlarını göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1682"/>
+        <source>Backspace unindents line</source>
+        <translation>Geri tuşu çizgiyi kaldırır</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1705"/>
+        <source>Indentation uses tabs</source>
+        <translation>Girinti sekmeleri kullanır</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1775"/>
+        <source>Auto completion</source>
+        <translation>Otomatik tamamlama</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1802"/>
+        <source>Match keywords</source>
+        <translation>Anahtar kelimeleri eşleştir</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1815"/>
+        <source>Case sensitive</source>
+        <translation>Büyük küçük harf duyarlı</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1838"/>
+        <source>Replace word by suggested one</source>
+        <translation>Kelimeyi önerilen bir kelimeyle değiştirin</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1828"/>
+        <source>Match words in document</source>
+        <translation>Belgedeki kelimeleri eşleştir</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1876"/>
+        <source>With Octave builtins</source>
+        <translation>Octave yerleşikleri ile</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1886"/>
+        <source>With Octave functions</source>
+        <translation>Oktave fonksiyonları ile</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1950"/>
+        <source>Show completion list automatically</source>
+        <translation>Tamamlama listesini otomatik olarak göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2026"/>
+        <source>Reload externally changed files without prompt</source>
+        <translation>Harici olarak değiştirilen dosyaları istem olmadan yeniden yükleyin</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1132"/>
+        <source>Use custom file editor</source>
+        <translation>Özel dosya düzenleyiciyi kullanın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2119"/>
+        <source>Text encoding used for loading and saving</source>
+        <translation>Yükleme ve kaydetme için kullanılan metin kodlaması</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2167"/>
+        <source>Editor Styles</source>
+        <translation>Düzenleyici Stilleri</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="704"/>
+        <source>(Changing buffer size clears history)</source>
+        <translation>(Arabellek boyutunu değiştirmek geçmişi temizler)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="732"/>
+        <source>History buffer Size</source>
+        <translation>Geçmiş arabellek Boyutu</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="609"/>
+        <location filename="../src/settings-dialog.ui" line="2545"/>
+        <source>Font</source>
+        <translation>Yazı Tipi</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="899"/>
+        <source>Show line numbers</source>
+        <translation>Satır numaralarını göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1049"/>
+        <source>Highlight current line</source>
+        <translation>Geçerli satırı vurgula</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="63"/>
+        <source>Interface</source>
+        <translation>Arayüz</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="420"/>
+        <source>Confirm before exiting</source>
+        <translation>Çıkmadan önce onayla</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="219"/>
+        <source>Graphic icons</source>
+        <translation>Grafik simgeleri</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="190"/>
+        <location filename="../src/settings-dialog.ui" line="880"/>
+        <source>Show status bar</source>
+        <translation>Durum çubuğunu göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="300"/>
+        <source>Text inactive</source>
+        <translation>Aktif olmayan metin</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="268"/>
+        <location filename="../src/settings-dialog.ui" line="313"/>
+        <source>Active</source>
+        <translation>Aktif</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="352"/>
+        <source>Background inactive</source>
+        <translation>Arka plan devre dışı</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="473"/>
+        <source>Octave Startup</source>
+        <translation>Oktave Başlatma</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="519"/>
+        <location filename="../src/settings-dialog.ui" line="2283"/>
+        <source>Browse</source>
+        <translation>Gözat</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="912"/>
+        <source>Show whitespace</source>
+        <translation>Boşluğu göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="867"/>
+        <source>Do not show whitespace used for indentation</source>
+        <translation>Girinti için kullanılan boşlukları gösterme</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1236"/>
+        <source>Tab width min.</source>
+        <translation>Sekme genişliği asg.</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1268"/>
+        <source>max.</source>
+        <translation>azm.</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2052"/>
+        <source>Create nonexistent files without prompting</source>
+        <translation>Var olmayan dosyaları sormadan oluşturun</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1142"/>
+        <source>command line (%f=file, %l=line):</source>
+        <translation>komut satırı (%f=dosya,%l=satır):</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="595"/>
+        <source>Cursor type:</source>
+        <translation>İmleç türü:</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="180"/>
+        <source>Cursor blinking</source>
+        <translation>İmleç yanıp sönüyor</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="584"/>
+        <source>Use foreground color</source>
+        <translation>Ön plan rengini kullan</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="636"/>
+        <location filename="../src/settings-dialog.ui" line="2462"/>
+        <source>Font size</source>
+        <translation>Yazı tipi boyutu</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2217"/>
+        <source>File Browser</source>
+        <translation>Dosya Gezgini</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="139"/>
+        <source>Normal</source>
+        <translation>Normal</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="479"/>
+        <source>These preferences are applied after any .octaverc startup files.</source>
+        <translation>Bu tercihler, herhangi bir .octaverc başlangıç dosyasından sonra uygulanır.</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1082"/>
+        <source>Show EOL characters</source>
+        <translation>EOL karakterlerini göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2064"/>
+        <source>Default EOL mode</source>
+        <translation>Varsayılan EOL modu</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1902"/>
+        <source>Number of characters before list is shown: </source>
+        <translation>Liste gösterilmeden önceki karakter sayısı: </translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="23"/>
+        <source>Preferences</source>
+        <translation>Seçenekler</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="86"/>
+        <source>(requires restart)</source>
+        <translation>(yeniden başlatma gerekli)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="118"/>
+        <source>Use native file dialogs</source>
+        <translation>Yerel dosya diyaloglarını kullanın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="171"/>
+        <source>Use system icon theme if available (requires restart)</source>
+        <translation>Varsa sistem simgesi temasını kullanın (yeniden başlatma gerektirir)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="241"/>
+        <source>Toolbar Icons</source>
+        <translation>Araç Çubuğu Simgeleri</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="427"/>
+        <source>Language</source>
+        <translation>Dil</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="461"/>
+        <source>Style</source>
+        <translation>Stil</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="488"/>
+        <source>Initial working directory of Octave interpreter</source>
+        <translation>Octave yorumlayıcısının ilk çalışma dizini</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="506"/>
+        <source>Restore last working directory of previous session</source>
+        <translation>Önceki oturumun son çalışma dizinini geri yükle</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="551"/>
+        <source>Command</source>
+        <translation>Komut</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="759"/>
+        <source>Set focus to Command Window when running a command from within another widget</source>
+        <translation>Başka bir widget&apos;tan bir komut çalıştırırken odağı Komut Penceresine ayarla</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="766"/>
+        <source>Print debug location in Command Window in addition to the marker in the editor</source>
+        <translation>Düzenleyicideki işaretçiye ek olarak Komut Penceresinde hata ayıklama konumunu yazdırın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="782"/>
+        <source>Command Window Colors</source>
+        <translation>Komut Penceresi Renkleri</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1308"/>
+        <source>Show complete path in title</source>
+        <translation>Başlıkta tam yolu göster</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="972"/>
+        <source>Number size as difference to editor font</source>
+        <translation>Düzenleyici yazı tipine göre sayı boyutu</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1112"/>
+        <source>Highlight all occurrences of a word selected by a double click</source>
+        <translation>Çift tıklama ile seçilen bir kelimenin tüm tekrarlarını vurgulayın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1177"/>
+        <source>Tabs</source>
+        <translation>Sekmeler</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1221"/>
+        <source>Tab position</source>
+        <oldsource>Position</oldsource>
+        <translation>Tab pozisyon</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1333"/>
+        <source>Comments (Octave)</source>
+        <translation>Yorumlar (Oktave)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1344"/>
+        <source>Strings considered for uncommenting text</source>
+        <translation>Yorumsuz metin için dikkate alınan dizeler</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1367"/>
+        <source>String used for commenting selected text</source>
+        <translation>Seçili metne yorum yapmak için kullanılan dize</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1398"/>
+        <source>Long lines</source>
+        <translation>Uzun çizgiler</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1423"/>
+        <source>Break long lines at line length</source>
+        <translation>Satır uzunluğunda uzun çizgileri kırın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1436"/>
+        <source>Break lines only in comments</source>
+        <translation>Satırları yalnızca yorumlarda ayırın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1496"/>
+        <source>Line length</source>
+        <translation>Satır uzunluğu</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1505"/>
+        <source>Long line marker</source>
+        <translation>Uzun çizgi işaretçisi</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1515"/>
+        <source>Line</source>
+        <translation>Satır</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1525"/>
+        <source>Background</source>
+        <translation>Arkaplan</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1716"/>
+        <source>Auto insert after &quot;if&quot; etc.</source>
+        <translation>Sonrasına otomatik ekle &quot;Eğer&quot; vb.</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1736"/>
+        <source>Nothing</source>
+        <translation>Hiç</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1741"/>
+        <source>&quot;endif&quot; etc.</source>
+        <translation>&quot;endif&quot; vb.</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1746"/>
+        <source>&quot;end&quot;</source>
+        <translation>&quot;son&quot;</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1984"/>
+        <source>Debugging</source>
+        <translation>Hata Ayıklama</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="1992"/>
+        <source>Always show debug breakpoints and pointers (opens related file if closed)</source>
+        <translation>Her zaman hata ayıklama kesme noktalarını ve işaretçileri göster (kapatılırsa ilgili dosyayı açar)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2007"/>
+        <source>File handling</source>
+        <translation>Dosya yönetimi</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2039"/>
+        <source>Restore editor tabs from previous session on startup or when editor is shown again after closing</source>
+        <translation>Başlangıçta veya düzenleyici kapattıktan sonra tekrar gösterildiğinde önceki oturumdan düzenleyici sekmelerini geri yükle</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2144"/>
+        <source>Close all files when the editor widget is closed/hidden</source>
+        <translation>Düzenleyici widget&apos;ı kapatıldığında / gizlendiğinde tüm dosyaları kapat</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2176"/>
+        <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select font, font size (as a difference from the default size), font style (&lt;b&gt;b&lt;/b&gt;old, &lt;b&gt;i&lt;/b&gt;talic, &lt;b&gt;u&lt;/b&gt;nderline), text color, and background color (for the latter, the color magenta (255,0,255) is a placeholder for the default background color).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Yazı tipini, yazı tipi boyutunu (varsayılan boyuttan farklı olarak), yazı tipi stilini seçin (&lt;b&gt;b&lt;/b&gt;old, &lt;b&gt;i&lt;/b&gt;talic, &lt;b&gt;u&lt;/b&gt;alt çizgi), metin rengi ve arka plan rengi (ikincisi için macenta rengi (255,0,255), varsayılan arka plan rengi için bir yer tutucudur).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2238"/>
+        <source>Behavior</source>
+        <translation>Davranış</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2260"/>
+        <source>Restore last directory of previous session</source>
+        <translation>Önceki oturumun son dizinini geri yükle</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2328"/>
+        <source>Extensions of files to be opened in the default text editor (separated by &quot;;&quot;):</source>
+        <translation>Varsayılan metin düzenleyicide açılacak dosya uzantıları (&quot;;&quot; ile ayrılmış):</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2367"/>
+        <source>Workspace</source>
+        <translation>Çalışma Alanı</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2402"/>
+        <source>Colors for variable attributes</source>
+        <translation>Değişken nitelikler için renkler</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2535"/>
+        <source>Use Command Window font</source>
+        <translation>Komut Penceresi yazı tipini kullan</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2668"/>
+        <source>Import shortcut set</source>
+        <translation>Kısayol kümesini içe aktar</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2678"/>
+        <source>Export current shortcut set</source>
+        <translation>Mevcut kısayol kümesini dışa aktar</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2688"/>
+        <source>Reset shortcuts to their defaults</source>
+        <translation>Kısayolları varsayılanlarına sıfırlayın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2691"/>
+        <location filename="../src/settings-dialog.ui" line="2771"/>
+        <source>Default</source>
+        <translation>Öntanımlı</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2700"/>
+        <source>Edit a shortcut by double-clicking in a cell</source>
+        <translation>Bir hücreye çift tıklayarak bir kısayolu düzenleme</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2776"/>
+        <source>Actual</source>
+        <translation>Güncel</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2793"/>
+        <source>Network</source>
+        <translation>Ağ</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2816"/>
+        <source>Allow Octave to connect to the Octave web site to display current news and information</source>
+        <translation>Octave&apos;in güncel haberleri ve bilgileri görüntülemek için Octave web sitesine bağlanmasına izin verin</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2862"/>
+        <source>Use proxy server</source>
+        <translation>Proxy sunucusu kullan</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2429"/>
+        <source>Variable Editor</source>
+        <translation>Değişken Düzenleyici</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2472"/>
+        <source>Default row height</source>
+        <translation>Varsayılan satır yüksekliği</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2479"/>
+        <source>Default column width</source>
+        <translation>Varsayılan sütun genişliği</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2557"/>
+        <source>Variable Editor Colors</source>
+        <translation>Değişken Düzenleyici Renkleri</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2569"/>
+        <source>Use alternating row colors</source>
+        <translation>Alternatif satır renkleri kullanın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2628"/>
+        <source>Disable global shortcuts when Command Window has focus</source>
+        <translation>Komut Penceresinde odak olduğunda genel kısayolları devre dışı bırakın</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2839"/>
+        <source>HttpProxy</source>
+        <translation>HttpProxy</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="251"/>
+        <source>Icon set for dock widgets</source>
+        <translation>Dock widget&apos;ları için simge seti</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2246"/>
+        <source>Synchronize Octave working directory with file browser</source>
+        <translation>Octave çalışma dizinini dosya tarayıcısı ile senkronize edin</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2292"/>
+        <source>Initial file browser directory (only if not synchronized with initial working directory of Octave)</source>
+        <translation>İlk dosya tarayıcı dizini (yalnızca Octave&apos;nin ilk çalışma dizini ile senkronize edilmemişse)</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2594"/>
+        <source>Shortcuts</source>
+        <translation>Kısayollar</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2625"/>
+        <source>Select this option to prevent conflicts with readline shortcuts</source>
+        <translation>Okuma satırı kısayollarıyla çakışmaları önlemek için bu seçeneği seçin</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2681"/>
+        <source>Export</source>
+        <translation>Dışa aktar</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2671"/>
+        <source>Import</source>
+        <translation>İçe aktar</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2761"/>
+        <source>Action</source>
+        <translation>Eylem</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2844"/>
+        <source>Socks5Proxy</source>
+        <translation>Socks5Proxy</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2828"/>
+        <source>Hostname:</source>
+        <translation>Makine ismi:</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2872"/>
+        <source>Proxy type:</source>
+        <translation>Proxy türü:</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2882"/>
+        <source>Port:</source>
+        <translation>Port:</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2855"/>
+        <source>Username:</source>
+        <translation>Kullanıcı adı:</translation>
+    </message>
+    <message>
+        <location filename="../src/settings-dialog.ui" line="2892"/>
+        <source>Password:</source>
+        <translation>Parola:</translation>
+    </message>
+    <message>
+        <source>Plus font height</source>
+        <translation type="vanished">Artı yazı tipi yüksekliği</translation>
+    </message>
+    <message>
+        <source>By Column</source>
+        <translation type="vanished">Sütuna göre</translation>
+    </message>
+    <message>
+        <source>Autofit</source>
+        <translation type="vanished">Otomatik sığdırma</translation>
+    </message>
+    <message>
+        <source>Uniform</source>
+        <translation type="vanished">Tektip</translation>
+    </message>
+</context>
+<context>
+    <name>QtHandles::MouseModeActionGroup</name>
+    <message>
+        <source>Pan</source>
+        <translation type="vanished">Yassılaştır</translation>
+    </message>
+    <message>
+        <source>Zoom In</source>
+        <translation type="vanished">Yaklaştır</translation>
+    </message>
+    <message>
+        <source>Rotate</source>
+        <translation type="vanished">Döndür</translation>
+    </message>
+    <message>
+        <source>Zoom Out</source>
+        <translation type="vanished">Uzaklaş</translation>
+    </message>
+    <message>
+        <source>Insert Text</source>
+        <translation type="vanished">Metin Ekle</translation>
+    </message>
+</context>
+<context>
+    <name>QtHandles::Figure</name>
+    <message>
+        <source>Axes</source>
+        <translation type="vanished">Eksen</translation>
+    </message>
+    <message>
+        <source>Grid</source>
+        <translation type="vanished">Izgara</translation>
+    </message>
+    <message>
+        <source>Figure ToolBar</source>
+        <translation type="vanished">Şekil Araç Çubuğu</translation>
+    </message>
+    <message>
+        <source>Autoscale</source>
+        <translation type="vanished">Oto-ölçekleme</translation>
+    </message>
+</context>
+<context>
+    <name>octave::octave_qt_link</name>
+    <message>
+        <source>File
+%1
+does not exist. Do you want to create it?</source>
+        <translation type="vanished">Dosya
+%1
+mevcut değil. Onu yaratmak ister misin?</translation>
+    </message>
+    <message>
+        <source>Octave Editor</source>
+        <translation type="vanished">Oktave Düzenleyici</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation type="vanished">İptal</translation>
+    </message>
+    <message>
+        <source>Create</source>
+        <translation type="vanished">Oluştur</translation>
+    </message>
+</context>
+</TS>
--- a/libgui/languages/translators	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/languages/translators	Sun May 16 09:44:35 2021 +0200
@@ -21,6 +21,7 @@
 pt_PT  Carnë Draug <carandraug@octave.org>
 ru_RU  Andriy Shinkarchuck <adriano32.gnu@gmail.com>
        Dmitry Astankov <mornie@basealt.ru>
+tr_TR  Serkan Önder <serkanonder@outlook.com>       
 uk_UA  Andriy Shinkarchuck <adriano32.gnu@gmail.com>
 zh_CN  Jeff Bai <aosc@members.fsf.org>
        Jun Wang <jstzwj@aliyun.com>
--- a/libgui/liboctgui-build-info.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/liboctgui-build-info.h	Sun May 16 09:44:35 2021 +0200
@@ -32,6 +32,6 @@
 
 #include <string>
 
-extern std::string liboctgui_hg_id (void);
+extern OCTGUI_API std::string liboctgui_hg_id (void);
 
 #endif
--- a/libgui/mk-default-qt-settings.in.sh	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-#! /bin/sh
-
-########################################################################
-##
-## Copyright (C) 2016-2021 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@}
-
-DEFAULT_TERMINAL_FONT="@DEFAULT_TERMINAL_FONT@"
-DEFAULT_TERMINAL_FONT_SIZE="@DEFAULT_TERMINAL_FONT_SIZE@"
-
-$SED \
-  -e "s|%DEFAULT_TERMINAL_FONT%|${DEFAULT_TERMINAL_FONT}|" \
-  -e "s|%DEFAULT_TERMINAL_FONT_SIZE%|${DEFAULT_TERMINAL_FONT_SIZE}|"
--- a/libgui/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -30,6 +30,7 @@
   %reldir%/languages/pt_BR.ts \
   %reldir%/languages/pt_PT.ts \
   %reldir%/languages/ru_RU.ts \
+  %reldir%/languages/tr_TR.ts \
   %reldir%/languages/uk_UA.ts \
   %reldir%/languages/zh_CN.ts
 
@@ -63,7 +64,7 @@
 ## to the rules in the etc/HACKING.md file:
 
 %canon_reldir%_liboctgui_current = 6
-%canon_reldir%_liboctgui_revision = 1
+%canon_reldir%_liboctgui_revision = 0
 %canon_reldir%_liboctgui_age = 0
 
 %canon_reldir%_liboctgui_version_info = $(%canon_reldir%_liboctgui_current):$(%canon_reldir%_liboctgui_revision):$(%canon_reldir%_liboctgui_age)
@@ -75,13 +76,8 @@
   $(LIBOCTGUI_LINK_OPTS) \
   $(WARN_LDFLAGS)
 
-octetc_DATA += %reldir%/default-qt-settings
-
 octlocale_DATA += $(LOCALES)
 
-%reldir%/default-qt-settings: %reldir%/default-qt-settings.in %reldir%/mk-default-qt-settings.sh | %reldir%/$(octave_dirstamp)
-	$(AM_V_GEN)$(call simple-filter-rule,%reldir%/mk-default-qt-settings.sh)
-
 DIRSTAMP_FILES += \
   %reldir%/$(octave_dirstamp)
 
@@ -129,15 +125,12 @@
 
 %canon_reldir%_EXTRA_DIST += \
   $(TRANSLATIONS) \
-  %reldir%/default-qt-settings.in \
-  %reldir%/liboctgui-build-info.in.cc \
-  %reldir%/mk-default-qt-settings.in.sh
+  %reldir%/liboctgui-build-info.in.cc
 
 EXTRA_DIST += $(%canon_reldir%_EXTRA_DIST)
 
 %canon_reldir%_CLEANFILES += \
   $(LOCALES) \
-  %reldir%/default-qt-settings \
   %reldir%/liboctgui-build-info.cc
 
 CLEANFILES += $(%canon_reldir%_CLEANFILES)
@@ -156,7 +149,4 @@
 %reldir%/liboctgui-build-info.cc: %reldir%/liboctgui-build-info.in.cc HG-ID | %reldir%/$(octave_dirstamp)
 	$(AM_V_GEN)$(build-info-commands)
 
-GEN_CONFIG_SHELL += \
-  %reldir%/mk-default-qt-settings.sh
-
 endif
--- a/libgui/qterminal/libqterminal/QTerminal.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/QTerminal.cc	Sun May 16 09:44:35 2021 +0200
@@ -49,12 +49,14 @@
 #endif
 
 QTerminal *
-QTerminal::create (octave::base_qobject& oct_qobj, QWidget *xparent)
+QTerminal::create (octave::base_qobject& oct_qobj, QWidget *p, QWidget *main_win)
 {
+  // p:       real parent
+  // xparent: main window for signal connections
 #if defined (Q_OS_WIN32)
-  QTerminal *terminal = new QWinTerminalImpl (xparent);
+  QTerminal *terminal = new QWinTerminalImpl (p, main_win);
 #else
-  QTerminal *terminal = new QUnixTerminalImpl (xparent);
+  QTerminal *terminal = new QUnixTerminalImpl (p, main_win);
 #endif
 
   // FIXME: this function should probably be called from or part of the
@@ -63,30 +65,11 @@
   // Unix- and Windows-specific versions would need access to the
   // base_qobject object, or the design would have to change significantly.
 
-  terminal->construct (oct_qobj, xparent);
+  terminal->construct (oct_qobj, main_win);
 
   return terminal;
 }
 
-// slot for disabling the interrupt action when terminal loses focus
-void
-QTerminal::set_global_shortcuts (bool focus_out)
-  {
-    if (focus_out)
-      {
-        _interrupt_action->setShortcut (QKeySequence ());
-        _nop_action->setShortcut (QKeySequence ());
-      }
-    else
-      {
-        _interrupt_action->setShortcut
-          (QKeySequence (Qt::ControlModifier | Qt::Key_C));
-
-        _nop_action->setShortcut
-          (QKeySequence (Qt::ControlModifier | Qt::Key_D));
-      }
-  }
-
 // slot for the terminal's context menu
 void
 QTerminal::handleCustomContextMenuRequested (const QPoint& at)
@@ -258,17 +241,16 @@
   bool cursorUseForegroundColor
     = settings->value (cs_cursor_use_fgcol).toBool ();
 
-  setForegroundColor
-    (settings->value (cs_colors[0].key, cs_colors[0].def).value<QColor> ());
+  int mode = settings->value (cs_color_mode).toInt ();
+
+  setForegroundColor (settings->color_value (cs_colors[0], mode));
 
-  setBackgroundColor
-    (settings->value (cs_colors[1].key, cs_colors[1].def).value<QColor> ());
+  setBackgroundColor (settings->color_value (cs_colors[1], mode));
 
-  setSelectionColor
-    (settings->value (cs_colors[2].key, cs_colors[2].def).value<QColor> ());
+  setSelectionColor (settings->color_value (cs_colors[2], mode));
 
   setCursorColor (cursorUseForegroundColor,
-     settings->value (cs_colors[3].key, cs_colors[3].def).value<QColor> ());
+                  settings->color_value (cs_colors[3], mode));
 
   setScrollBufferSize (settings->value (cs_hist_buffer).toInt ());
 
@@ -279,9 +261,12 @@
 
   QString sc = settings->sc_value (sc_main_edit_copy);
 
-  //  Dis- or enable extra interrupt action depending on the Copy shortcut
+  //  Dis- or enable extra interrupt action: We need an extra option when
+  //  copy shortcut is not Ctrl-C or when global shortcuts (like copy) are
+  //  disabled.
   bool extra_ir_action
-      = (sc != QKeySequence (Qt::ControlModifier | Qt::Key_C).toString ());
+      = (sc != QKeySequence (Qt::ControlModifier | Qt::Key_C).toString ())
+        || settings->value (sc_prevent_rl_conflicts).toBool ();
 
   _interrupt_action->setEnabled (extra_ir_action);
   has_extra_interrupt (extra_ir_action);
@@ -332,7 +317,7 @@
 
   _contextMenu->addSeparator ();
 
-  _contextMenu->addAction (tr ("Clear Window"), parent (),
+  _contextMenu->addAction (tr ("Clear Window"), xparent,
                            SLOT (handle_clear_command_window_request ()));
 
   connect (this, SIGNAL (customContextMenuRequested (QPoint)),
@@ -350,9 +335,6 @@
   connect (this, SIGNAL (execute_command_in_terminal_signal (const QString&)),
            xparent, SLOT (execute_command_in_terminal (const QString&)));
 
-  connect (xparent, SIGNAL (settings_changed (const gui_settings *)),
-           this, SLOT (notice_settings (const gui_settings *)));
-
   connect (xparent, SIGNAL (init_terminal_size_signal ()),
            this, SLOT (init_terminal_size ()));
 
@@ -371,8 +353,9 @@
 
   _interrupt_action->setShortcut
     (QKeySequence (Qt::ControlModifier + Qt::Key_C));
+  _interrupt_action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
 
-  connect (_interrupt_action, SIGNAL (triggered ()),
+  bool ok = connect (_interrupt_action, SIGNAL (triggered ()),
            this, SLOT (terminal_interrupt ()));
 
   // dummy (nop) action catching Ctrl-D in terminal, no connection
@@ -380,4 +363,5 @@
   addAction (_nop_action);
 
   _nop_action->setShortcut (QKeySequence (Qt::ControlModifier + Qt::Key_D));
+  _nop_action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
 }
--- a/libgui/qterminal/libqterminal/QTerminal.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/QTerminal.h	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 public:
 
   static QTerminal *
-  create (octave::base_qobject& oct_qobj, QWidget *xparent = nullptr);
+  create (octave::base_qobject& oct_qobj, QWidget *xparent, QWidget* main_win);
 
   virtual ~QTerminal (void) = default;
 
@@ -123,8 +123,6 @@
 
   void terminal_interrupt (void) { emit interrupt_signal (); }
 
-  void set_global_shortcuts (bool focus_out);
-
   void run_selection (void);
 
   void edit_file (void);
--- a/libgui/qterminal/libqterminal/unix/Filter.cpp	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/unix/Filter.cpp	Sun May 16 09:44:35 2021 +0200
@@ -683,7 +683,7 @@
   // the function name. depending on this we have to invoke different
   // slots in main_window
   if (file_info.isAbsolute () && file_info.exists ())
-    emit request_open_file_signal (file, line);
+    emit request_open_file_signal (file, QString (), line);
   else
     emit request_edit_mfile_signal (file, line);
 }
--- a/libgui/qterminal/libqterminal/unix/Filter.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/unix/Filter.h	Sun May 16 09:44:35 2021 +0200
@@ -245,7 +245,7 @@
 signals:
 
     void request_edit_mfile_signal (const QString&, int);
-    void request_open_file_signal (const QString&, int);
+    void request_open_file_signal (const QString&, const QString&, int);
 
 protected:
     /**
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp	Sun May 16 09:44:35 2021 +0200
@@ -24,14 +24,13 @@
 
 #include <termios.h>
 
-QUnixTerminalImpl::QUnixTerminalImpl(QWidget *p)
-    : QTerminal(p),
-      _parent (p)
+QUnixTerminalImpl::QUnixTerminalImpl(QWidget *p, QWidget *main_win)
+    : QTerminal(p)
 {
-    initialize();
+    initialize(main_win);
 }
 
-void QUnixTerminalImpl::initialize()
+void QUnixTerminalImpl::initialize(QWidget* main_win)
 {
     m_terminalView = new TerminalView(this);
     m_terminalView->setKeyboardCursorShape(TerminalView::UnderlineCursor);
@@ -51,9 +50,9 @@
     m_terminalView->filterChain ()->addFilter (file_filter);
 
     connect (file_filter, SIGNAL (request_edit_mfile_signal (const QString&, int)),
-             _parent, SLOT (edit_mfile (const QString&, int)));
-    connect (file_filter, SIGNAL (request_open_file_signal (const QString&, int)),
-             _parent, SLOT (open_file (const QString&, int)));
+             main_win, SLOT (edit_mfile (const QString&, int)));
+    connect (file_filter, SIGNAL (request_open_file_signal (const QString&, const QString&,int)),
+             main_win, SIGNAL (open_file_signal (const QString&, const QString&,int)));
 
     connect(m_terminalView, SIGNAL(customContextMenuRequested(QPoint)),
             this, SLOT(handleCustomContextMenuRequested(QPoint)));
@@ -107,8 +106,12 @@
 
 void QUnixTerminalImpl::connectToPty()
 {
-    // Store the file descriptor associated with the STDERR stream onto
-    // another temporary file descriptor for reconnect in the destructor.
+    // Store the file descriptor associated with the STDIN, STDOUT, and
+    // STDERR streams onto another temporary file descriptor for
+    // reconnect in the destructor.
+
+    fdstdin = dup (STDIN_FILENO);
+    fdstdout = dup (STDOUT_FILENO);
     fdstderr = dup (STDERR_FILENO);
 
     int fds = m_kpty->slaveFd();
@@ -136,7 +139,11 @@
     delete m_kpty;
     delete m_terminalView;
 
-    // Restore stderr so that any errors at exit might appear somewhere.
+    // Restore STDIN, STDOUT, and STDERR so that I/O at exit will work
+    // as expected.
+
+    dup2 (fdstdin, STDIN_FILENO);
+    dup2 (fdstdout, STDOUT_FILENO);
     dup2 (fdstderr, STDERR_FILENO);
 
     emit destroyed();
--- a/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.h	Sun May 16 09:44:35 2021 +0200
@@ -31,10 +31,12 @@
 {
     Q_OBJECT
 
+    int fdstdin;
+    int fdstdout;
     int fdstderr;
 
 public:
-    QUnixTerminalImpl(QWidget *parent = nullptr);
+    QUnixTerminalImpl(QWidget *parent, QWidget *main_win);
     virtual ~QUnixTerminalImpl();
 
     void setTerminalFont(const QFont &font);
@@ -63,14 +65,13 @@
     virtual void resizeEvent(QResizeEvent *);
 
 private:
-    void initialize();
+    void initialize (QWidget* main_win);
     void connectToPty();
 
     TerminalView *m_terminalView;
     TerminalModel *m_terminalModel;
     KPty *m_kpty;
     bool _extra_interrupt;
-    QWidget *_parent;
 };
 
 #endif // Q_UNIXTERMINALIMPL
--- a/libgui/qterminal/libqterminal/unix/TerminalView.cpp	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/unix/TerminalView.cpp	Sun May 16 09:44:35 2021 +0200
@@ -334,12 +334,6 @@
   _gridLayout->setMargin(0);
 
   setLayout( _gridLayout );
-
-  connect (this, SIGNAL (set_global_shortcuts_signal (bool)),
-           parent->parent (), SLOT (set_global_shortcuts (bool)));
-  connect (this, SIGNAL (set_global_shortcuts_signal (bool)),
-           parent, SLOT (set_global_shortcuts (bool)));
-
 }
 
 TerminalView::~TerminalView()
@@ -983,8 +977,6 @@
 
 void TerminalView::focusInEvent(QFocusEvent *focusEvent)
 {
-  emit set_global_shortcuts_signal (false);  // disable some shortcuts
-
   setBlinkingCursorState(true);
   updateImage();
   repaint();
@@ -995,8 +987,6 @@
 
 void TerminalView::focusOutEvent(QFocusEvent *focusEvent)
 {
-  emit set_global_shortcuts_signal (true);  // re-enable shortcuts
-
   // Force the cursor to be redrawn.
   _cursorBlinking = true;
   setBlinkingCursorState(false);
--- a/libgui/qterminal/libqterminal/unix/TerminalView.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/unix/TerminalView.h	Sun May 16 09:44:35 2021 +0200
@@ -497,12 +497,6 @@
 
    void tripleClicked( const QString& text );
 
-   /**
-    * Emitted when focus changes
-    */
-   void set_global_shortcuts_signal (bool);
-
-
 protected:
     virtual void paintEvent( QPaintEvent * );
 
--- a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.cpp	Sun May 16 09:44:35 2021 +0200
@@ -1441,19 +1441,14 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-QWinTerminalImpl::QWinTerminalImpl (QWidget* parent)
+QWinTerminalImpl::QWinTerminalImpl (QWidget* parent, QWidget* main_win)
     : QTerminal (parent), d (new QConsolePrivate (this)),
       allowTripleClick (false)
 {
     installEventFilter (this);
 
-    connect (this, SIGNAL (set_global_shortcuts_signal (bool)),
-           parent, SLOT (set_global_shortcuts (bool)));
-    connect (this, SIGNAL (set_global_shortcuts_signal (bool)),
-             this, SLOT (set_global_shortcuts (bool)));
-
     connect (this, SIGNAL (set_screen_size_signal (int, int)),
-             parent, SLOT (set_screen_size (int, int)));
+             main_win, SLOT (set_screen_size (int, int)));
 
     setAcceptDrops (true);
 }
@@ -1652,8 +1647,6 @@
 
 void QWinTerminalImpl::focusInEvent (QFocusEvent* event)
 {
-  emit set_global_shortcuts_signal (false);   // disable some shortcuts
-
   setBlinkingCursorState (true);
 
   QWidget::focusInEvent (event);
@@ -1661,8 +1654,6 @@
 
 void QWinTerminalImpl::focusOutEvent (QFocusEvent* event)
 {
-  emit set_global_shortcuts_signal (true);    // re-enable shortcuts
-
   // Force the cursor to be redrawn.
   d->m_cursorBlinking = true;
 
@@ -1814,7 +1805,15 @@
   QString text = QApplication::clipboard()->text (QClipboard::Clipboard);
 
   if (! text.isEmpty ())
+    {
+      if (text.contains ("\t"))
+        {
+          qWarning ("Tabs replaced with spaces in pasted text before processing");
+          text.replace ("\t", "    ");
+        }
+
     sendText (text);
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////
--- a/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/qterminal/libqterminal/win32/QWinTerminalImpl.h	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
   friend class QConsoleView;
 
 public:
-  QWinTerminalImpl (QWidget* parent = 0);
+  QWinTerminalImpl (QWidget* parent, QWidget* main_win);
   QWinTerminalImpl (const QString& cmd, QWidget* parent = 0);
   ~QWinTerminalImpl (void);
 
@@ -78,7 +78,6 @@
 signals:
   void terminated (void);
   void titleChanged (const QString&);
-  void set_global_shortcuts_signal (bool);
   void set_screen_size_signal (int, int);
 
 protected:
--- a/libgui/src/color-picker.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/color-picker.cc	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
     setFlat (true);
     setFocusPolicy (Qt::NoFocus);  // no focus, would change the color
     update_button ();
-    connect (this, SIGNAL (clicked (void)), SLOT (select_color (void)));
+    connect (this, &color_picker::clicked, this, &color_picker::select_color);
   }
 
   // Slot for button clicked: select a new color using QColorDialog
@@ -57,6 +57,13 @@
       }
   }
 
+  // Set the color of the button
+  void color_picker::set_color (QColor new_color)
+  {
+    m_color = new_color;
+    update_button ();
+  }
+
   // Draw the button with the actual color (using a stylesheet)
   void color_picker::update_button (void)
   {
--- a/libgui/src/color-picker.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/color-picker.h	Sun May 16 09:44:35 2021 +0200
@@ -44,6 +44,8 @@
 
     QColor color (void) const { return m_color; }
 
+    void set_color (QColor new_color);
+
   private slots:
 
     void select_color (void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/command-widget.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,181 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <QGroupBox>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QTextBrowser>
+#include <QVBoxLayout>
+
+#include "command-widget.h"
+
+#include "cmd-edit.h"
+#include "event-manager.h"
+#include "gui-preferences-cs.h"
+#include "gui-preferences-global.h"
+#include "gui-utils.h"
+#include "input.h"
+#include "interpreter.h"
+
+namespace octave
+{
+  // FIXME: this class needs a different name and should probably be
+  // defined in a separate file.
+
+  command_widget::command_widget (base_qobject& oct_qobj, QWidget *p)
+    : QWidget (p), m_incomplete_parse (false),
+      m_prompt (new QLabel ("", this)),
+      m_line_edit (new QLineEdit (this)),
+      m_output_display (new QTextBrowser (this)),
+      m_input_color (QColor ())
+  {
+    QPushButton *pause_button = new QPushButton (tr("Pause"), this);
+    QPushButton *stop_button = new QPushButton (tr("Stop"), this);
+    QPushButton *resume_button = new QPushButton (tr("Continue"), this);
+
+    QGroupBox *input_group_box = new QGroupBox (tr("Command Input"));
+    QHBoxLayout *input_layout = new QHBoxLayout;
+    input_layout->addWidget (m_prompt);
+    input_layout->addWidget (m_line_edit);
+    input_layout->addWidget (pause_button);
+    input_layout->addWidget (stop_button);
+    input_layout->addWidget (resume_button);
+    input_group_box->setLayout (input_layout);
+
+    QGroupBox *output_group_box = new QGroupBox (tr("Command Output"));
+    QHBoxLayout *output_layout = new QHBoxLayout ();
+    output_layout->addWidget (m_output_display);
+    output_group_box->setLayout (output_layout);
+
+    QVBoxLayout *main_layout = new QVBoxLayout ();
+    main_layout->addWidget (output_group_box);
+    main_layout->addWidget (input_group_box);
+
+    setLayout (main_layout);
+
+    setFocusProxy (m_line_edit);
+
+    connect (m_line_edit, &QLineEdit::returnPressed,
+             this, &command_widget::accept_input_line);
+
+    connect (this, &command_widget::clear_line_edit,
+             m_line_edit, &QLineEdit::clear);
+
+    connect (pause_button, &QPushButton::clicked,
+             &oct_qobj, &base_qobject::interpreter_pause);
+
+    connect (stop_button, &QPushButton::clicked,
+             &oct_qobj, &base_qobject::interpreter_stop);
+
+    connect (resume_button, &QPushButton::clicked,
+             &oct_qobj, &base_qobject::interpreter_resume);
+
+    connect (p, SIGNAL (update_prompt_signal (const QString&)),
+             m_prompt, SLOT (setText (const QSTring&)));
+
+    connect (p, SIGNAL (interpreter_output_signal (const QString&)),
+             this, SLOT (insert_interpreter_output (const QString&)));
+  }
+
+  void command_widget::insert_interpreter_output (const QString& msg)
+  {
+    QTextCursor cursor = m_output_display->textCursor ();
+
+    cursor.insertText (msg);
+
+    m_output_display->setTextCursor (cursor);
+  }
+
+  void command_widget::accept_input_line (void)
+  {
+    QTextCursor cursor = m_output_display->textCursor ();
+
+    QString input_line = m_line_edit->text ();
+
+    QString style;
+    if (! m_incomplete_parse)
+      {
+        style = QString ("<div style=\"color:%1; font-weight:bold;\">[in]:</div> ")
+                .arg (m_input_color.name ());
+        m_output_display->insertHtml (style);
+      }
+    style = QString ("<div style=\"color:%1\">%2</div><br>")
+            .arg (m_input_color.name ()).arg (input_line);
+    m_output_display->insertHtml (style);
+
+    emit interpreter_event
+      ([=] (interpreter& interp)
+       {
+         // INTERPRETER THREAD
+
+         interp.parse_and_execute (input_line.toStdString (),
+                                   m_incomplete_parse);
+
+         event_manager& evmgr = interp.get_event_manager ();
+         input_system& input_sys = interp.get_input_system ();
+
+         std::string prompt
+           = m_incomplete_parse ? input_sys.PS2 () : input_sys.PS1 ();
+
+         evmgr.update_prompt (command_editor::decode_prompt_string (prompt));
+       });
+
+    emit clear_line_edit ();
+  }
+
+  void command_widget::notice_settings (const gui_settings *settings)
+  {
+    // Set terminal font:
+    QFont term_font = QFont ();
+    term_font.setStyleHint (QFont::TypeWriter);
+    QString default_font = settings->value (global_mono_font).toString ();
+    term_font.setFamily
+      (settings->value (cs_font.key, default_font).toString ());
+    term_font.setPointSize
+      (settings->value (cs_font_size).toInt ());
+
+    m_line_edit->setFont (term_font);
+    m_output_display->setFont (term_font);
+
+    // Colors
+    int mode = settings->value (cs_color_mode).toInt ();
+    QColor fgc = settings->color_value (cs_colors[0], mode);
+    QColor bgc = settings->color_value (cs_colors[1], mode);
+
+    m_output_display->setStyleSheet (QString ("color: %1; background-color:%2;")
+                                     .arg (fgc.name ()).arg (bgc.name ()));
+    m_line_edit->setStyleSheet (QString ("color: %1; background-color:%2;")
+                                .arg (fgc.name ()).arg (bgc.name ()));
+
+    m_input_color = interpolate_color (fgc, bgc, 0.75, 0.5);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/command-widget.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,78 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2021 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_command_widget_h)
+#define octave_command_widget_h 1
+
+#include <QWidget>
+
+#include "octave-qobject.h"
+#include "gui-settings.h"
+
+class QLabel;
+class QLineEdit;
+class QStrung;
+class QTextBrowser;
+
+namespace octave
+{
+  class base_qobject;
+
+  class command_widget : public QWidget
+  {
+    Q_OBJECT
+
+  public:
+
+    command_widget (base_qobject& oct_qobj, QWidget *p);
+
+  signals:
+
+    void clear_line_edit (void);
+
+    void interpreter_event (const fcn_callback& fcn);
+    void interpreter_event (const meth_callback& meth);
+
+  public slots:
+
+    void notice_settings (const gui_settings *settings);
+
+  protected slots:
+
+    void accept_input_line (void);
+
+    void insert_interpreter_output (const QString& msg);
+
+  private:
+
+    bool m_incomplete_parse;
+    QLabel *m_prompt;
+    QLineEdit *m_line_edit;
+    QTextBrowser *m_output_display;
+    QColor m_input_color;
+  };
+}
+
+#endif
--- a/libgui/src/dialog.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/dialog.cc	Sun May 16 09:44:35 2021 +0200
@@ -51,45 +51,17 @@
     : QObject (), m_octave_qobj (oct_qobj), m_dialog_result (-1),
       m_dialog_button (), m_string_list (), m_list_index (), m_path_name ()
   {
-    connect (this,
-             SIGNAL (create_dialog (const QString&, const QString&,
-                                    const QString&, const QStringList&,
-                                    const QString&, const QStringList&)),
-             this,
-             SLOT (handle_create_dialog (const QString&, const QString&,
-                                         const QString&, const QStringList&,
-                                         const QString&, const QStringList&)));
+    connect (this, &QUIWidgetCreator::create_dialog,
+             this, &QUIWidgetCreator::handle_create_dialog);
 
-    connect (this,
-             SIGNAL (create_listview (const QStringList&, const QString&,
-                                      int, int, const QIntList&,
-                                      const QString&, const QStringList&,
-                                      const QString&, const QString&)),
-             this,
-             SLOT (handle_create_listview (const QStringList&, const QString&,
-                                           int, int, const QIntList&,
-                                           const QString&, const QStringList&,
-                                           const QString&, const QString&)));
+    connect (this, &QUIWidgetCreator::create_listview,
+             this, &QUIWidgetCreator::handle_create_listview);
 
-    connect (this,
-             SIGNAL (create_inputlayout (const QStringList&, const QString&,
-                                         const QFloatList&, const QFloatList&,
-                                         const QStringList&)),
-             this,
-             SLOT (handle_create_inputlayout (const QStringList&,
-                                              const QString&,
-                                              const QFloatList&,
-                                              const QFloatList&,
-                                              const QStringList&)));
+    connect (this, &QUIWidgetCreator::create_inputlayout,
+             this, &QUIWidgetCreator::handle_create_inputlayout);
 
-    connect (this,
-             SIGNAL (create_filedialog (const QStringList&,const QString&,
-                                        const QString&, const QString&,
-                                        const QString&)),
-             this,
-             SLOT (handle_create_filedialog (const QStringList&, const QString&,
-                                             const QString&, const QString&,
-                                             const QString&)));
+    connect (this, &QUIWidgetCreator::create_filedialog,
+             this, &QUIWidgetCreator::handle_create_filedialog);
   }
 
   QString QUIWidgetCreator::rm_amp (const QString& text)
@@ -211,8 +183,8 @@
       = new MessageDialog (m_octave_qobj, message, title, icon,
                            button, defbutton, role);
 
-    connect (message_dialog, SIGNAL (buttonClicked (QAbstractButton *)),
-             this, SLOT (dialog_button_clicked (QAbstractButton *)));
+    connect (message_dialog, &MessageDialog::buttonClicked,
+             this, &QUIWidgetCreator::dialog_button_clicked);
 
     message_dialog->setAttribute (Qt::WA_DeleteOnClose);
     message_dialog->show ();
@@ -263,8 +235,8 @@
       = new ListDialog (m_octave_qobj, list, mode, wd, ht, initial,
                         name, prompt, ok_string, cancel_string);
 
-    connect (list_dialog, SIGNAL (finish_selection (const QIntList&, int)),
-             this, SLOT (list_select_finished (const QIntList&, int)));
+    connect (list_dialog, &ListDialog::finish_selection,
+             this, &QUIWidgetCreator::list_select_finished);
 
     list_dialog->setAttribute (Qt::WA_DeleteOnClose);
     list_dialog->show ();
@@ -294,8 +266,8 @@
     InputDialog *input_dialog
       = new InputDialog (m_octave_qobj, prompt, title, nr, nc, defaults);
 
-    connect (input_dialog, SIGNAL (finish_input (const QStringList&, int)),
-             this, SLOT (input_finished (const QStringList&, int)));
+    connect (input_dialog, &InputDialog::finish_input,
+             this, &QUIWidgetCreator::input_finished);
 
     input_dialog->setAttribute (Qt::WA_DeleteOnClose);
     input_dialog->show ();
@@ -323,10 +295,8 @@
       = new FileDialog (m_octave_qobj, filters, title, filename,
                         dirname, multimode);
 
-    connect (file_dialog, SIGNAL (finish_input (const QStringList&,
-                                                const QString&, int)),
-             this, SLOT (filedialog_finished (const QStringList&,
-                                              const QString&, int)));
+    connect (file_dialog, &FileDialog::finish_input,
+             this, &QUIWidgetCreator::filedialog_finished);
 
     file_dialog->setAttribute (Qt::WA_DeleteOnClose);
     file_dialog->show ();
@@ -424,7 +394,7 @@
                           const QStringList& prompt,
                           const QString& ok_string,
                           const QString& cancel_string)
-    : QDialog (), m_model (new QStringListModel (list))
+    : QDialog (), m_model (new QStringListModel (list, this))
   {
     QListView *view = new QListView;
     view->setModel (m_model);
@@ -503,22 +473,17 @@
     // If empty, make blank rather than use default OS behavior.
     setWindowTitle (title.isEmpty () ? " " : title);
 
-    connect (select_all, SIGNAL (clicked ()),
-             view, SLOT (selectAll ()));
+    connect (select_all, &QPushButton::clicked,
+             view, &QListView::selectAll);
 
-    connect (buttonOk, SIGNAL (clicked ()),
-             this, SLOT (buttonOk_clicked ()));
+    connect (buttonOk, &QPushButton::clicked,
+             this, &ListDialog::buttonOk_clicked);
 
-    connect (buttonCancel, SIGNAL (clicked ()),
-             this, SLOT (buttonCancel_clicked ()));
+    connect (buttonCancel, &QPushButton::clicked,
+             this, &ListDialog::buttonCancel_clicked);
 
-    connect (view, SIGNAL (doubleClicked (const QModelIndex&)),
-             this, SLOT (item_double_clicked (const QModelIndex&)));
-  }
-
-  ListDialog::~ListDialog (void)
-  {
-    delete m_model;
+    connect (view, &QListView::doubleClicked,
+             this, &ListDialog::item_double_clicked);
   }
 
   void ListDialog::buttonOk_clicked (void)
@@ -619,11 +584,11 @@
     // If empty, make blank rather than use default OS behavior.
     setWindowTitle (title.isEmpty () ? " " : title);
 
-    connect (buttonOk, SIGNAL (clicked ()),
-             this, SLOT (buttonOk_clicked ()));
+    connect (buttonOk, &QPushButton::clicked,
+             this, &InputDialog::buttonOk_clicked);
 
-    connect (buttonCancel, SIGNAL (clicked ()),
-             this, SLOT (buttonCancel_clicked ()));
+    connect (buttonCancel, &QPushButton::clicked,
+             this, &InputDialog::buttonCancel_clicked);
   }
 
   void InputDialog::buttonOk_clicked (void)
@@ -699,9 +664,9 @@
 
     selectFile (filename);
 
-    connect (this, SIGNAL (accepted ()), this, SLOT (acceptSelection ()));
+    connect (this, &FileDialog::accepted, this, &FileDialog::acceptSelection);
 
-    connect (this, SIGNAL (rejected ()), this, SLOT (rejectSelection ()));
+    connect (this, &FileDialog::rejected, this, &FileDialog::rejectSelection);
   }
 
   void FileDialog::rejectSelection (void)
--- a/libgui/src/dialog.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/dialog.h	Sun May 16 09:44:35 2021 +0200
@@ -181,6 +181,8 @@
                    const QStringList& button, const QString& defbutton,
                    const QStringList& role);
 
+    ~MessageDialog (void) = default;
+
   private:
 
     void closeEvent (QCloseEvent *)
@@ -205,7 +207,7 @@
                 const QStringList& prompt, const QString& ok_string,
                 const QString& cancel_string);
 
-    ~ListDialog (void);
+    ~ListDialog (void) = default;
 
   signals:
 
@@ -238,6 +240,8 @@
                  const QString& title, const QFloatList& nr,
                  const QFloatList& nc, const QStringList& defaults);
 
+    ~InputDialog (void) = default;
+
   signals:
 
     void finish_input (const QStringList&, int);
@@ -261,6 +265,8 @@
                 const QString& title, const QString& filename,
                 const QString& dirname, const QString& multimode);
 
+    ~FileDialog (void) = default;
+
   signals:
 
     void finish_input (const QStringList&, const QString&, int);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/documentation-bookmarks.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,548 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2018-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <QCompleter>
+#include <QMenu>
+#include <QShortcut>
+#include <QVBoxLayout>
+#include <QWidget>
+
+#include "documentation.h"
+#include "documentation-bookmarks.h"
+
+#include "gui-settings.h"
+#include "gui-preferences-global.h"
+#include "gui-preferences-dc.h"
+#include "gui-preferences-sc.h"
+#include "octave-qtutils.h"
+#include "shortcut-manager.h"
+
+#include "defaults.h"
+#include "file-ops.h"
+#include "oct-env.h"
+
+namespace octave
+{
+  documentation_bookmarks::documentation_bookmarks (
+                      documentation *doc, documentation_browser *browser,
+                      base_qobject& oct_qobj, QWidget *p)
+    : QWidget (p),
+      m_doc (doc), m_browser (browser), m_octave_qobj (oct_qobj),
+      m_ctx_menu_item (nullptr)
+  {
+    setObjectName ("documentation_tab_bookmarks");
+
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+    // Setup the tree view with the bookmarks
+    m_tree = new QTreeWidget (p);
+
+    m_tree->setContextMenuPolicy (Qt::CustomContextMenu);
+    m_tree->setSelectionMode (QAbstractItemView::ExtendedSelection);
+    m_tree->setSortingEnabled (false);
+    m_tree->setDragEnabled(true);
+    m_tree->viewport()->setAcceptDrops(true);
+    m_tree->setDropIndicatorShown(true);
+    m_tree->setDragDropMode(QAbstractItemView::InternalMove);
+    m_tree->setColumnCount (1);
+    m_tree->setHeaderHidden (true);
+    m_tree->setEditTriggers (QAbstractItemView::EditKeyPressed
+                                      | QAbstractItemView::SelectedClicked);
+
+    connect (m_tree, &QTreeWidget::customContextMenuRequested,
+             this, &documentation_bookmarks::ctx_menu);
+    connect (m_tree, &QTreeWidget::itemDoubleClicked,
+             this, &documentation_bookmarks::handle_double_click);
+
+    // Define the icons for the tree view
+    icon_folder.addPixmap (style ()->standardPixmap(QStyle::SP_DirClosedIcon),
+                           QIcon::Normal, QIcon::Off);
+    icon_folder.addPixmap (style ()->standardPixmap(QStyle::SP_DirOpenIcon),
+                           QIcon::Normal, QIcon::On);
+    icon_bookmark.addPixmap (style ()->standardPixmap(QStyle::SP_FileIcon));
+
+    // Setup and read the bookmarkfile
+    QFileInfo f (settings->fileName ());
+    QString f_path = f.absolutePath ();
+    f.setFile (QDir (f_path), dc_bookmark_file);
+    m_xbel_file.setFileName (f.absoluteFilePath ());
+
+    if (m_xbel_file.exists ())
+      {
+        QString err = read_bookmarks ();
+        if ( !err.isEmpty ())
+          {
+            err.append (tr ("\nNo documentation bookmarks loaded!"));
+            QMessageBox::warning (this,
+                                  tr ("Octave: Loading Documentation Bookmarks"),
+                                  err);
+            m_xbel_file.close ();
+          }
+      }
+
+    // Setup the filter widget
+    m_filter_widget = new QWidget (p);
+    m_filter = new QComboBox (m_filter_widget);
+
+    m_filter->setToolTip (tr ("Enter text to search the bookmarks"));
+    m_filter->setEditable (true);
+    m_filter->setInsertPolicy (QComboBox::NoInsert);
+    m_filter->setMaxCount (10);
+    m_filter->setMaxVisibleItems (10);
+    m_filter->setSizeAdjustPolicy (QComboBox::AdjustToMinimumContentsLengthWithIcon);
+    QSizePolicy size_pol (QSizePolicy::Expanding, QSizePolicy::Preferred);
+    m_filter->setSizePolicy (size_pol);
+    m_filter->completer ()->setCaseSensitivity (Qt::CaseSensitive);
+
+    m_filter->addItems (settings->value (dc_bookmark_filter_mru).toStringList ());
+
+    connect (m_filter, &QComboBox::editTextChanged,
+             this, &documentation_bookmarks::filter_bookmarks);
+    connect (m_filter->lineEdit (), &QLineEdit::editingFinished,
+             this, &documentation_bookmarks::update_filter_history);
+
+    m_filter_checkbox = new QCheckBox (m_filter_widget);
+    bool filter_state = settings->value (dc_bookmark_filter_active).toBool ();
+    m_filter_checkbox->setChecked (filter_state);
+    filter_activate (filter_state);
+
+    connect (m_filter_checkbox, &QCheckBox::toggled,
+             this, &documentation_bookmarks::filter_activate);
+
+    QLabel *filter_label = new QLabel (tr ("Filter"), m_filter_widget);
+    QHBoxLayout *h_box_bm = new QHBoxLayout (m_filter_widget);
+    h_box_bm->addWidget (filter_label);
+    h_box_bm->addWidget (m_filter_checkbox);
+    h_box_bm->addWidget (m_filter);
+    h_box_bm->setMargin (2);
+    m_filter_widget->setLayout (h_box_bm);
+
+    m_filter_shown = settings->value (dc_bookmark_filter_shown).toBool ();
+    m_filter_widget->setVisible (m_filter_shown);
+
+    // Resulting Layout of this widget
+    QVBoxLayout *v_box_bm = new QVBoxLayout (this);
+    v_box_bm->addWidget (m_filter_widget);
+    v_box_bm->addWidget (m_tree);
+    setLayout (v_box_bm);
+  }
+
+  // Slot for adding the current page as a bookmark
+  void documentation_bookmarks::add_bookmark (void)
+  {
+    QUrl url = m_browser->historyUrl (0);
+
+    // Check if bookmark already exists and select if yes
+    QTreeWidgetItemIterator it (m_tree);
+    while (*it)
+      {
+        QUrl url_i = (*it)->data (0, url_role).toUrl ();
+        if (url == url_i)
+          {
+            m_tree->setCurrentItem (*it);
+            (*it)->setExpanded (true);
+            return;
+          }
+        it++;
+      }
+
+    // Add the anchor name to the title of the page and add the bookmark
+    // as top-level-item
+    QString title = m_doc->title_and_anchor (m_browser->historyTitle (0), url);
+    add_bookmark (title, url.toString ());
+  }
+
+  // Function for actually adding a bookmark to the tree
+  void documentation_bookmarks::add_bookmark (const QString& title,
+                                              const QString& url,
+                                              QTreeWidgetItem* item)
+  {
+    // Create new bookmark
+    QTreeWidgetItem *new_item = new QTreeWidgetItem (QStringList (title));
+    new_item->setData (0, tag_role, QVariant (bookmark_tag));
+    new_item->setData (0, url_role, QVariant (url));
+    new_item->setFlags ((new_item->flags () & (~Qt::ItemIsDropEnabled))
+                                            | Qt::ItemIsEditable
+                                            | Qt::ItemIsDragEnabled);
+    new_item->setIcon (0, icon_bookmark);
+
+    // Insert as top level or child item
+    // TODO: Open dialog allowing to select a target folder if this
+    //       bookmark is added manually and not by reading a bookmark file
+    if (item)
+      item->addChild (new_item);
+    else
+      m_tree->addTopLevelItem (new_item);
+  }
+
+  // Slot for adding a folder from the context menu
+  void documentation_bookmarks::add_folder (bool)
+  {
+    QTreeWidgetItem *parent_item = nullptr;
+
+    if (m_ctx_menu_item)
+      {
+        if (m_ctx_menu_item->data (0, tag_role).toInt () == folder_tag)
+          parent_item = m_ctx_menu_item;
+        else
+          {
+            QTreeWidgetItem *p = m_ctx_menu_item->parent ();
+            if (p)
+              parent_item = p;
+          }
+      }
+
+    QTreeWidgetItem *new_folder = add_folder (tr ("New Folder"), parent_item);
+
+    m_tree->setCurrentItem (new_folder);
+    m_tree->editItem (new_folder);
+  }
+
+  // Function for actually adding a folder to the tree
+  QTreeWidgetItem* documentation_bookmarks::add_folder (const QString& folder,
+                                            QTreeWidgetItem *item, bool expanded)
+  {
+    QTreeWidgetItem *new_folder = new QTreeWidgetItem (QStringList (folder));
+    new_folder->setData (0, tag_role, QVariant (folder_tag));
+    new_folder->setFlags (new_folder->flags() | Qt::ItemIsEditable
+                                              | Qt::ItemIsDragEnabled
+                                              | Qt::ItemIsDropEnabled);
+    new_folder->setChildIndicatorPolicy (QTreeWidgetItem::DontShowIndicatorWhenChildless);
+    new_folder->setIcon (0, icon_folder);
+    new_folder->setExpanded (expanded);
+
+    // Insert as top level or child item
+    if (item)
+      item->addChild (new_folder);
+    else
+      m_tree->addTopLevelItem (new_folder);
+
+    return new_folder;
+  }
+
+  void documentation_bookmarks::filter_bookmarks (const QString& pattern)
+  {
+    QTreeWidgetItemIterator it (m_tree);
+
+    while (*it)
+      {
+        if ((*it)->text (0).contains (pattern, Qt::CaseInsensitive))
+          {
+            (*it)->setHidden (false);
+            (*it)->setExpanded (true);
+            QTreeWidgetItem *p = (*it)->parent ();
+            while (p)
+              {
+                p->setHidden (false);
+                p->setExpanded (true);
+                p = p->parent ();
+              }
+          }
+        else
+            (*it)->setHidden (true);
+
+        it++;
+      }
+  }
+
+  void documentation_bookmarks::filter_activate (bool state)
+  {
+    m_filter->setEnabled (state);
+
+    QString pattern;
+    if (state)
+      pattern = m_filter->currentText ();
+
+    filter_bookmarks (pattern);
+  }
+
+  void documentation_bookmarks::update_filter_history (void)
+  {
+    QString text = m_filter->currentText ();   // get current text
+    int index = m_filter->findText (text);     // and its actual index
+
+    if (index > -1)
+      m_filter->removeItem (index);    // remove if already existing
+
+    m_filter->insertItem (0, text);    // (re)insert at beginning
+    m_filter->setCurrentIndex (0);
+  }
+
+  void documentation_bookmarks::handle_double_click (QTreeWidgetItem *item, int)
+  {
+    int tag = item->data (0, tag_role).toInt ();
+
+    if (tag == folder_tag)
+      {
+        item->setExpanded (! item->isExpanded ());
+        return;
+      }
+
+    if (tag == bookmark_tag)
+      {
+        QUrl url = item->data (0, url_role).toUrl ();
+        if (! url.isEmpty ())
+          m_browser->setSource (url);
+        return;
+      }
+  }
+
+  void documentation_bookmarks::ctx_menu (const QPoint& xpos)
+  {
+    QMenu menu (this);
+
+    m_ctx_menu_item = m_tree->itemAt (xpos);
+
+    if (m_ctx_menu_item)
+      {
+        resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+
+        menu.addAction (tr ("&Open"), this, &documentation_bookmarks::open);
+        menu.addAction (tr ("&Rename"), this, &documentation_bookmarks::edit);
+        menu.addAction (rmgr.icon ("window-close"), tr ("Remo&ve"),
+                        this, &documentation_bookmarks::remove);
+        menu.addSeparator ();
+      }
+
+    menu.addAction (tr ("&Add Folder"), this,
+                    QOverload<bool>::of (&documentation_bookmarks::add_folder));
+
+    menu.addSeparator ();
+
+    if (m_filter_shown)
+      menu.addAction (tr ("Hide &Filter"),
+                      this, &documentation_bookmarks::show_filter);
+    else
+      menu.addAction (tr ("Show &Filter"),
+                      this, &documentation_bookmarks::show_filter);
+
+    menu.exec (m_tree->mapToGlobal (xpos));
+  }
+
+  void documentation_bookmarks::open (bool)
+  {
+    QList<QTreeWidgetItem *> items = m_tree->selectedItems ();
+
+    if (items.size () > 0)
+      handle_double_click (items.at (0));
+  }
+
+  void documentation_bookmarks::edit (bool)
+  {
+    QList<QTreeWidgetItem *> items = m_tree->selectedItems ();
+
+    if (items.size () > 0)
+      m_tree->editItem (items.at (0));
+  }
+
+  void documentation_bookmarks::remove (bool)
+  {
+    QList<QTreeWidgetItem *> items = m_tree->selectedItems ();
+
+    for (auto it = items.begin () ; it != items.end (); it++)
+      {
+        if (*it)
+          m_tree->takeTopLevelItem (
+                    m_tree->indexOfTopLevelItem (*it));
+      }
+  }
+
+  void documentation_bookmarks::show_filter (bool)
+  {
+    m_filter_shown = ! m_filter_shown;
+    m_filter_widget->setVisible (m_filter_shown);
+  }
+
+  void documentation_bookmarks::save_settings (void)
+  {
+    // Write the bookmarks to the xbel-file
+    write_bookmarks ();
+
+    // Store settings
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+    settings->setValue (dc_bookmark_filter_active.key, m_filter_checkbox->isChecked ());
+    settings->setValue (dc_bookmark_filter_shown.key, m_filter_shown);
+
+    QStringList mru;
+    for (int i = 0; i < m_filter->count (); i++)
+      mru.append (m_filter->itemText (i));
+    settings->setValue (dc_bookmark_filter_mru.key, mru);
+
+    settings->sync ();
+  }
+
+  void documentation_bookmarks::write_bookmarks (void)
+  {
+    if (! m_xbel_file.open (QFile::WriteOnly | QFile::Text))
+      {
+        QMessageBox::warning (this, tr("Octave: Saving Documentation Bookmarks"),
+                              tr("Unable to write file %1:\n%2.\n\n"
+                                 "Documentation bookmarks are not saved!\n")
+                                .arg (m_xbel_file.fileName ())
+                                .arg (m_xbel_file.errorString()));
+        return;
+      }
+
+    QXmlStreamWriter xml_writer (&m_xbel_file);
+    xml_writer.setAutoFormatting (true);
+
+    xml_writer.writeStartDocument ();
+    xml_writer.writeDTD (dc_xbel_doctype);
+    xml_writer.writeStartElement (dc_xbel_name_format);
+    xml_writer.writeAttribute (dc_xbel_attr_version, dc_xbel_value_version);
+
+    for (int i = 0; i < m_tree->topLevelItemCount(); i++)
+      write_tree_item (&xml_writer, m_tree->topLevelItem (i));
+
+    xml_writer.writeEndDocument();
+
+    m_xbel_file.flush ();
+    m_xbel_file.close ();
+  }
+
+  void documentation_bookmarks::write_tree_item (QXmlStreamWriter* xml_writer,
+                                                 const QTreeWidgetItem *item)
+  {
+    switch (item->data (0, tag_role).toInt ())
+      {
+        case folder_tag:
+          xml_writer->writeStartElement (dc_xbel_name_folder);
+          xml_writer->writeAttribute (dc_xbel_attr_folded,
+                    item->isExpanded () ? dc_xbel_value_no : dc_xbel_value_yes);
+          xml_writer->writeTextElement (dc_xbel_name_title, item->text(0));
+          for (int i = 0; i < item->childCount (); i++)
+            write_tree_item (xml_writer, item->child (i));
+          xml_writer->writeEndElement ();
+          break;
+
+        case bookmark_tag:
+          xml_writer->writeStartElement (dc_xbel_name_bookmark);
+          xml_writer->writeAttribute (dc_xbel_attr_href, item->data (0, url_role).toString ());
+          xml_writer->writeTextElement (dc_xbel_name_title, item->text (0));
+          xml_writer->writeEndElement ();
+          break;
+      }
+  }
+
+  QString documentation_bookmarks::read_bookmarks (void)
+  {
+    QString error_message;
+
+    // Check the file
+    if (! m_xbel_file.open (QFile::ReadOnly | QFile::Text))
+      {
+        error_message = tr ("Unable to read file %1:\n%2.")
+                            .arg (m_xbel_file.fileName ())
+                            .arg (m_xbel_file.errorString());
+        return error_message;
+      }
+
+    QXmlStreamReader xml_reader (&m_xbel_file);
+
+    if (! xml_reader.readNextStartElement ())
+      {
+        error_message = tr ("No start element found in %1.\n"
+                            "Invalid bookmark file?")
+                            .arg (m_xbel_file.fileName ());
+        return error_message;
+      }
+
+    if (xml_reader.name() != dc_xbel_name_format
+        || xml_reader.attributes ().value (dc_xbel_attr_version) != dc_xbel_value_version)
+      {
+        error_message = tr ("The file\n"
+                            "%1\n"
+                            "is not a valid XBEL file verison 1.0.")
+                            .arg (m_xbel_file.fileName ());
+        return error_message;
+      }
+
+    // Read the elements from the file
+    while (xml_reader.readNextStartElement ())
+      {
+        if (xml_reader.name () == dc_xbel_name_folder)
+          read_next_item (&xml_reader, folder_tag);
+        else if (xml_reader.name () == dc_xbel_name_bookmark)
+          read_next_item (&xml_reader, bookmark_tag);
+        else
+          xml_reader.skipCurrentElement ();
+      }
+
+     m_xbel_file.close ();
+
+     return error_message;
+  }
+
+  void documentation_bookmarks::read_next_item (QXmlStreamReader *xml_reader,
+                                                item_tag tag, QTreeWidgetItem *item)
+  {
+    QString title (tr ("Unknown title"));
+    if (tag == folder_tag)
+      {
+        // Next item is a folder, which might also have children
+        bool expanded = (xml_reader->attributes().value (dc_xbel_attr_folded) == dc_xbel_value_no);
+
+        QTreeWidgetItem *new_folder = add_folder (title, item, expanded);
+
+        // Check elements of this folder for title and for recursively
+        // adding sub-items
+        while (xml_reader->readNextStartElement ())
+          {
+            if (xml_reader->name () == dc_xbel_name_title)
+              {
+                title = xml_reader->readElementText();
+                new_folder->setText (0, title);
+              }
+            else if (xml_reader->name () == dc_xbel_name_folder)
+              read_next_item (xml_reader, folder_tag, new_folder);
+            else if (xml_reader->name () == dc_xbel_name_bookmark)
+              read_next_item (xml_reader, bookmark_tag, new_folder);
+            else
+              xml_reader->skipCurrentElement ();
+          }
+      }
+    else if (tag == bookmark_tag)
+      {
+        // Next item is a bookmark, without children
+        QString url = xml_reader->attributes().value (dc_xbel_attr_href).toString ();
+        while (xml_reader->readNextStartElement ())
+          {
+            if (xml_reader->name() == dc_xbel_name_title)
+              title = xml_reader->readElementText();
+            else
+              xml_reader->skipCurrentElement ();
+          }
+        add_bookmark (title, url, item);
+      }
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/documentation-bookmarks.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,125 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2018-2021 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_documentation_bookmarks_h)
+#define octave_documentation_bookmarks_h 1
+
+#include <QCheckBox>
+#include <QComboBox>
+#include <QTreeWidget>
+#include <QXmlStreamWriter>
+
+#include "documentation.h"
+#include "octave-qobject.h"
+
+
+namespace octave
+{
+  class base_qobject;
+  class documentation;
+
+  class documentation_bookmarks : public QWidget
+  {
+    Q_OBJECT
+
+  public:
+
+    documentation_bookmarks (
+                documentation *doc, documentation_browser *browser,
+                base_qobject& oct_qobj, QWidget *p = nullptr);
+
+    ~documentation_bookmarks (void) = default;
+
+  public slots:
+
+    void add_bookmark (void);
+    void add_folder (bool);
+    void save_settings (void);
+
+  private slots:
+
+    void filter_bookmarks (const QString& pattern);
+    void filter_activate (bool state);
+    void update_filter_history (void);
+    void handle_double_click (QTreeWidgetItem *item, int col = 0);
+    void ctx_menu (const QPoint& xpos);
+    void open (bool);
+    void edit (bool);
+    void remove (bool);
+    void show_filter (bool);
+
+  private:
+
+    enum item_role
+    {
+      url_role = Qt::UserRole,
+      tag_role = Qt::UserRole + 1
+    };
+    enum item_tag
+    {
+      bookmark_tag,
+      folder_tag
+    };
+
+    void add_bookmark (const QString& title, const QString& url,
+                       QTreeWidgetItem *item = nullptr);
+    QTreeWidgetItem* add_folder (const QString& folder,
+                                 QTreeWidgetItem *item = nullptr,
+                                 bool expanded = true);
+
+    /*!
+        Writing to and reading bookmarks from an xbel-file as
+        proposed in the qt example
+        [QXmlStream Bookmarks Example](https://doc.qt.io/qt-5/qtxml-streambookmarks-example.html)
+    */
+    void write_bookmarks (void);
+    void write_tree_item (QXmlStreamWriter *xml_writer,
+                          const QTreeWidgetItem *item);
+    QString read_bookmarks (void);
+    void read_next_item (QXmlStreamReader *xml_writer, item_tag tag,
+                         QTreeWidgetItem *item = nullptr);
+
+    documentation *m_doc;
+    documentation_browser *m_browser;
+    base_qobject& m_octave_qobj;
+
+    QComboBox *m_filter;
+    QTreeWidget *m_tree;
+
+    QTreeWidgetItem *m_ctx_menu_item;
+
+    QIcon icon_folder;
+    QIcon icon_bookmark;
+
+    QWidget *m_filter_widget;
+    QCheckBox *m_filter_checkbox;
+    bool m_filter_shown;
+
+    QFile m_xbel_file;
+  };
+
+}
+
+#endif
--- a/libgui/src/documentation-dock-widget.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/documentation-dock-widget.cc	Sun May 16 09:44:35 2021 +0200
@@ -35,29 +35,17 @@
 {
   documentation_dock_widget::documentation_dock_widget (QWidget *p,
                                                         base_qobject& oct_qobj)
-    : octave_dock_widget ("DocumentationDockWidget", p, oct_qobj)
+    : octave_dock_widget ("DocumentationDockWidget", p, oct_qobj),
+      m_docs (new documentation (this, oct_qobj))
   {
     setWindowIcon (QIcon (":/actions/icons/logo.png"));
     set_title (tr ("Documentation"));
     setStatusTip (tr ("See the documentation for help."));
 
-    m_docs = new documentation (this, oct_qobj);
     setWidget (m_docs);
 
-    connect (p, SIGNAL (show_doc_signal (const QString&)),
-             this, SLOT (showDoc (const QString&)));
-
-    connect (p, SIGNAL (register_doc_signal (const QString&)),
-             this, SLOT (registerDoc (const QString&)));
-
-    connect (p, SIGNAL (unregister_doc_signal (const QString&)),
-             this, SLOT (unregisterDoc (const QString&)));
-  }
-
-  documentation_dock_widget::~documentation_dock_widget (void)
-  {
-    if (m_docs)
-      delete m_docs;
+    if (! p)
+      make_window ();
   }
 
   void documentation_dock_widget::notice_settings (const gui_settings *settings)
@@ -65,6 +53,12 @@
     m_docs->notice_settings (settings);
   }
 
+  void documentation_dock_widget::save_settings (void)
+  {
+    emit save_settings_signal ();
+    octave_dock_widget::save_settings ();
+  }
+
   void documentation_dock_widget::copyClipboard (void)
   {
     m_docs->copyClipboard ();
--- a/libgui/src/documentation-dock-widget.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/documentation-dock-widget.h	Sun May 16 09:44:35 2021 +0200
@@ -40,13 +40,17 @@
   public:
 
     documentation_dock_widget (QWidget *parent, base_qobject& oct_qobj);
-    ~documentation_dock_widget (void);
+
+    ~documentation_dock_widget (void) = default;
+
+  signals:
+
+    void save_settings_signal (void);
 
   public slots:
 
     void notice_settings (const gui_settings *settings);
-
-  protected slots:
+    void save_settings (void);
 
     void copyClipboard (void);
     void pasteClipboard (void);
--- a/libgui/src/documentation.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/documentation.cc	Sun May 16 09:44:35 2021 +0200
@@ -50,6 +50,7 @@
 #include <QVBoxLayout>
 
 #include "documentation.h"
+#include "documentation-bookmarks.h"
 #include "gui-preferences-global.h"
 #include "gui-preferences-sc.h"
 #include "octave-qobject.h"
@@ -65,15 +66,15 @@
   // of the doc dock widget
   documentation::documentation (QWidget *p, base_qobject& oct_qobj)
     : QSplitter (Qt::Horizontal, p),
-      m_octave_qobj (oct_qobj), m_doc_widget (p),
-      m_tool_bar (new QToolBar (p)),
+      m_octave_qobj (oct_qobj), m_doc_widget (this),
+      m_tool_bar (new QToolBar (this)),
       m_query_string (QString ()),
-      m_prev_pages_menu (new QMenu (p)),
-      m_next_pages_menu (new QMenu (p)),
+      m_prev_pages_menu (new QMenu (this)),
+      m_next_pages_menu (new QMenu (this)),
       m_prev_pages_count (0),
       m_next_pages_count (0),
-      m_findnext_shortcut (new QShortcut (p)),
-      m_findprev_shortcut (new QShortcut (p))
+      m_findnext_shortcut (new QShortcut (this)),
+      m_findprev_shortcut (new QShortcut (this))
   {
     // Get original collection
     QString collection = getenv ("OCTAVE_QTHELP_COLLECTION");
@@ -131,8 +132,8 @@
     // The browser
     QWidget *browser_find = new QWidget (this);
     m_doc_browser = new documentation_browser (m_help_engine, browser_find);
-    connect (m_doc_browser, SIGNAL (cursorPositionChanged (void)),
-             this, SLOT(handle_cursor_position_change (void)));
+    connect (m_doc_browser, &documentation_browser::cursorPositionChanged,
+             this, &documentation::handle_cursor_position_change);
 
     // Tool bar
     construct_tool_bar ();
@@ -141,23 +142,23 @@
     QWidget *find_footer = new QWidget (browser_find);
     QLabel *find_label = new QLabel (tr ("Find:"), find_footer);
     m_find_line_edit = new QLineEdit (find_footer);
-    connect (m_find_line_edit, SIGNAL (returnPressed (void)),
-             this, SLOT(find (void)));
-    connect (m_find_line_edit, SIGNAL (textEdited (const QString&)),
-             this, SLOT(find_forward_from_anchor (const QString&)));
+    connect (m_find_line_edit, &QLineEdit::returnPressed,
+             this, [=] () { find (); });
+    connect (m_find_line_edit, &QLineEdit::textEdited,
+             this, &documentation::find_forward_from_anchor);
     QToolButton *forward_button = new QToolButton (find_footer);
     forward_button->setText (tr ("Search forward"));
     forward_button->setToolTip (tr ("Search forward"));
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
     forward_button->setIcon (rmgr.icon ("go-down"));
-    connect (forward_button, SIGNAL (pressed (void)),
-             this, SLOT(find (void)));
+    connect (forward_button, &QToolButton::pressed,
+             this, [=] () { find (); });
     QToolButton *backward_button = new QToolButton (find_footer);
     backward_button->setText (tr ("Search backward"));
     backward_button->setToolTip (tr ("Search backward"));
     backward_button->setIcon (rmgr.icon ("go-up"));
-    connect (backward_button, SIGNAL (pressed (void)),
-             this, SLOT(find_backward (void)));
+    connect (backward_button, &QToolButton::pressed,
+             this, &documentation::find_backward);
     QHBoxLayout *h_box_find_footer = new QHBoxLayout (find_footer);
     h_box_find_footer->addWidget (find_label);
     h_box_find_footer->addWidget (m_find_line_edit);
@@ -175,11 +176,11 @@
     notice_settings (rmgr.get_settings ());
 
     m_findnext_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
-    connect (m_findnext_shortcut, SIGNAL (activated (void)),
-             this, SLOT(find (void)));
+    connect (m_findnext_shortcut, &QShortcut::activated,
+             this, [=] () { find (); });
     m_findprev_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
-    connect (m_findprev_shortcut, SIGNAL (activated (void)),
-             this, SLOT(find_backward (void)));
+    connect (m_findprev_shortcut, &QShortcut::activated,
+             this, &documentation::find_backward);
 
     find_footer->hide ();
     m_search_anchor_position = 0;
@@ -200,9 +201,10 @@
         content->setObjectName ("documentation_tab_contents");
         navi->addTab (content, tr ("Contents"));
 
-        connect(m_help_engine->contentWidget (),
-                SIGNAL (linkActivated (const QUrl&)),
-                m_doc_browser, SLOT(handle_index_clicked (const QUrl&)));
+        connect (m_help_engine->contentWidget (),
+                 &QHelpContentWidget::linkActivated,
+                 m_doc_browser, [=] (const QUrl& url) {
+                   m_doc_browser->handle_index_clicked (url); });
 
         // Index
         QHelpIndexWidget *index = m_help_engine->indexWidget ();
@@ -238,20 +240,29 @@
 #if defined (HAVE_NEW_QHELPINDEXWIDGET_API)
         connect (m_help_engine->indexWidget (),
                  &QHelpIndexWidget::documentActivated,
-                 this, [this](const QHelpLink &link) {
-                        m_doc_browser->handle_index_clicked (link.url);});
+                 this, [=] (const QHelpLink &link) {
+                   m_doc_browser->handle_index_clicked (link.url); });
 #else
         connect (m_help_engine->indexWidget (),
-                 SIGNAL (linkActivated (const QUrl&, const QString&)),
-                 m_doc_browser, SLOT(handle_index_clicked (const QUrl&,
-                                                           const QString&)));
+                 &QHelpIndexWidget::linkActivated,
+                 m_doc_browser, &documentation_browser::handle_index_clicked);
 #endif
 
-        connect (m_filter, SIGNAL (editTextChanged (const QString&)),
-                 this, SLOT(filter_update (const QString&)));
+        connect (m_filter, &QComboBox::editTextChanged,
+                 this, &documentation::filter_update);
+
+        connect (m_filter->lineEdit (), &QLineEdit::editingFinished,
+                 this, &documentation::filter_update_history);
 
-        connect (m_filter->lineEdit (), SIGNAL (editingFinished (void)),
-                 this, SLOT(filter_update_history (void)));
+        // Bookmarks (own class)
+        documentation_bookmarks *bookmarks
+          = new documentation_bookmarks (this, m_doc_browser, m_octave_qobj, navi);
+        navi->addTab (bookmarks, tr ("Bookmarks"));
+
+        connect (m_action_bookmark, &QAction::triggered,
+                 bookmarks, [=] () { bookmarks->add_bookmark (); });
+        connect (p, SIGNAL (save_settings_signal (void)),
+                 bookmarks, SLOT (save_settings (void)));
 
         // Search
         QHelpSearchEngine *search_engine = m_help_engine->searchEngine ();
@@ -265,18 +276,17 @@
         search_all->setObjectName ("documentation_tab_search");
         navi->addTab (search_all, tr ("Search"));
 
-        connect (search, SIGNAL (search (void)),
-                 this, SLOT(global_search (void)));
+        connect (search, &QHelpSearchQueryWidget::search,
+                 this, &documentation::global_search);
 
-        connect (search_engine, SIGNAL (searchingStarted (void)),
-                 this, SLOT(global_search_started (void)));
-        connect (search_engine, SIGNAL (searchingFinished (int)),
-                 this, SLOT(global_search_finished (int)));
+        connect (search_engine, &QHelpSearchEngine::searchingStarted,
+                 this, &documentation::global_search_started);
+        connect (search_engine, &QHelpSearchEngine::searchingFinished,
+                 this, &documentation::global_search_finished);
 
         connect (search_engine->resultWidget (),
-                 SIGNAL (requestShowLink (const QUrl&)),
-                 this,
-                 SLOT(handle_search_result_clicked (const QUrl&)));
+                 &QHelpSearchResultWidget::requestShowLink,
+                 this, &documentation::handle_search_result_clicked);
 
         // Fill the splitter
         insertWidget (0, navi);
@@ -291,9 +301,6 @@
 
   documentation::~documentation (void)
   {
-    if (m_help_engine)
-      delete m_help_engine;
-
     // Cleanup temporary file and directory
     QFile file (m_collection);
     if (file.exists ())
@@ -324,7 +331,9 @@
       r = receiver;
 
     a = new QAction (icon, text, this);
-    connect (a, SIGNAL (triggered ()), r, member);
+
+    if (member)
+      connect (a, SIGNAL (triggered ()), r, member);
 
     if (tool_bar)
       tool_bar->addAction (a);
@@ -342,6 +351,7 @@
     m_action_go_home
       = add_action (rmgr.icon ("go-home"), tr ("Go home"), SLOT (home (void)),
                     m_doc_browser, m_tool_bar);
+
     m_action_go_prev
       = add_action (rmgr.icon ("go-previous"), tr ("Go back"),
                     SLOT (backward (void)), m_doc_browser, m_tool_bar);
@@ -356,6 +366,7 @@
     popdown_button_prev_pages->setCheckable (false);
     popdown_button_prev_pages->setArrowType(Qt::DownArrow);
     m_tool_bar->addWidget (popdown_button_prev_pages);
+
     m_action_go_next
       = add_action (rmgr.icon ("go-next"), tr ("Go forward"),
                     SLOT (forward (void)), m_doc_browser, m_tool_bar);
@@ -370,16 +381,16 @@
     popdown_button_next_pages->setArrowType(Qt::DownArrow);
     m_tool_bar->addWidget (popdown_button_next_pages);
 
-    connect (m_doc_browser, SIGNAL (backwardAvailable (bool)),
-             m_action_go_prev, SLOT (setEnabled (bool)));
-    connect (m_doc_browser, SIGNAL (backwardAvailable (bool)),
-             popdown_button_prev_pages, SLOT (setEnabled (bool)));
-    connect (m_doc_browser, SIGNAL (forwardAvailable (bool)),
-             m_action_go_next, SLOT (setEnabled (bool)));
-    connect (m_doc_browser, SIGNAL (forwardAvailable (bool)),
-             popdown_button_next_pages, SLOT (setEnabled (bool)));
-    connect (m_doc_browser, SIGNAL (historyChanged (void)),
-             this, SLOT (update_history_menus (void)));
+    connect (m_doc_browser, &documentation_browser::backwardAvailable,
+             m_action_go_prev, &QAction::setEnabled);
+    connect (m_doc_browser, &documentation_browser::backwardAvailable,
+             popdown_button_prev_pages, &QToolButton::setEnabled);
+    connect (m_doc_browser, &documentation_browser::forwardAvailable,
+             m_action_go_next, &QAction::setEnabled);
+    connect (m_doc_browser, &documentation_browser::forwardAvailable,
+             popdown_button_next_pages, &QToolButton::setEnabled);
+    connect (m_doc_browser, &documentation_browser::historyChanged,
+             this, &documentation::update_history_menus);
 
     // Init prev/next menus
     for (int i = 0; i < max_history_entries; ++i)
@@ -392,10 +403,10 @@
         m_next_pages_menu->addAction (m_next_pages_actions[i]);
       }
 
-    connect (m_prev_pages_menu, SIGNAL (triggered (QAction *)),
-             this, SLOT (open_hist_url (QAction *)));
-    connect (m_next_pages_menu, SIGNAL (triggered (QAction *)),
-             this, SLOT (open_hist_url (QAction *)));
+    connect (m_prev_pages_menu, &QMenu::triggered,
+             this, &documentation::open_hist_url);
+    connect (m_next_pages_menu, &QMenu::triggered,
+             this, &documentation::open_hist_url);
 
     // Find
     m_tool_bar->addSeparator ();
@@ -414,6 +425,12 @@
     m_action_zoom_original
       = add_action (rmgr.icon ("zoom-original"), tr ("Zoom original"),
                     SLOT (zoom_original (void)), m_doc_browser, m_tool_bar);
+
+    // Bookmarks (connect slots later)
+    m_tool_bar->addSeparator ();
+    m_action_bookmark
+      = add_action (rmgr.icon ("bookmark-new"), tr ("Bookmark current page"),
+                    nullptr, nullptr, m_tool_bar);
   }
 
   void documentation::global_search (void)
@@ -517,9 +534,8 @@
 
                 if (! url.isEmpty ())
                   {
-                    connect (this, SIGNAL (show_single_result (const QUrl&)),
-                             this,
-                             SLOT (handle_search_result_clicked (const QUrl&)));
+                    connect (this, &documentation::show_single_result,
+                             this, &documentation::handle_search_result_clicked);
 
                     emit show_single_result (url);
                   }
@@ -613,6 +629,7 @@
     scmgr.set_shortcut (m_action_go_home, sc_doc_go_home);
     scmgr.set_shortcut (m_action_go_prev, sc_doc_go_back);
     scmgr.set_shortcut (m_action_go_next, sc_doc_go_next);
+    scmgr.set_shortcut (m_action_bookmark, sc_doc_bookmark);
   }
 
   void documentation::copyClipboard (void)
@@ -870,37 +887,9 @@
     // Fill used menu entries
     for (int i = 0; i < count; i++)
       {
-        QString title = m_doc_browser->historyTitle (prev_next*(i+1));
-        title.remove (QRegExp ("\\s*\\(*GNU Octave \\(version [^\\)]*\\)[: \\)]*"));
-
-        // Since the title only contains the section name and not the
-        // specific anchor, extract the latter from the url and append
-        // it to the title
-        QString url = m_doc_browser->historyUrl (prev_next*(i+1)).toString ();
-        if (url.contains ('#'))
-          {
-            // Get the anchor from the url
-            QString anchor = url.split ('#').last ();
-
-            // Remove internal string parts
-            anchor.remove (QRegExp ("^index-"));
-            anchor.remove (QRegExp ("^SEC_"));
-            anchor.remove (QRegExp ("^XREF"));
-            anchor.remove ("Concept-Index_cp_letter-");
-            anchor.replace ("-"," ");
-
-            // replace encoded special chars by their unencoded versions
-            QRegExp rx = QRegExp ("_00([0-7][0-9a-f])");
-            int pos = 0;
-            while ((pos = rx.indexIn(anchor, pos)) != -1)
-              {
-                anchor.replace ("_00"+rx.cap (1), QChar (rx.cap (1).toInt (nullptr,16)));
-                pos += rx.matchedLength();
-              }
-
-            if (title != anchor)
-              title = title + ": " + anchor;
-          }
+        QString title
+          = title_and_anchor (m_doc_browser->historyTitle (prev_next*(i+1)),
+                              m_doc_browser->historyUrl (prev_next*(i+1)));
 
         if (i == 0)
           a->setText (title); // set tool tip for prev/next buttons
@@ -924,19 +913,59 @@
     m_doc_browser->setSource (a->data ().toUrl ());
   }
 
+  // Utility functions
 
+  QString documentation::title_and_anchor (const QString& title, const QUrl& url)
+  {
+    QString retval = title;
+    QString u = url.toString ();
+
+    retval.remove (QRegExp ("\\s*\\(*GNU Octave \\(version [^\\)]*\\)[: \\)]*"));
+
+    // Since the title only contains the section name and not the
+    // specific anchor, extract the latter from the url and append
+    // it to the title
+    if (u.contains ('#'))
+      {
+        // Get the anchor from the url
+        QString anchor = u.split ('#').last ();
+        // Remove internal string parts
+        anchor.remove (QRegExp ("^index-"));
+        anchor.remove (QRegExp ("^SEC_"));
+        anchor.remove (QRegExp ("^XREF"));
+        anchor.remove ("Concept-Index_cp_letter-");
+        anchor.replace ("-"," ");
+
+        // replace encoded special chars by their unencoded versions
+        QRegExp rx = QRegExp ("_00([0-7][0-9a-f])");
+        int pos = 0;
+        while ((pos = rx.indexIn(anchor, pos)) != -1)
+          {
+            anchor.replace ("_00"+rx.cap (1), QChar (rx.cap (1).toInt (nullptr,16)));
+            pos += rx.matchedLength();
+          }
+
+        if (retval != anchor)
+          retval = retval + ": " + anchor;
+      }
+
+    return retval;
+  }
+
+
+
+  //
   // The documentation browser
+  //
+
   documentation_browser::documentation_browser (QHelpEngine *he, QWidget *p)
     : QTextBrowser (p), m_help_engine (he), m_zoom_level (0)
   {
     setOpenLinks (false);
-    connect (this, SIGNAL (anchorClicked (QUrl)),
-             this, SLOT (handle_index_clicked (QUrl)));
+    connect (this, &documentation_browser::anchorClicked,
+             this, [=] (const QUrl& url) { handle_index_clicked (url); });
   }
 
-  documentation_browser::~documentation_browser (void)
-  { }
-
   void documentation_browser::handle_index_clicked (const QUrl& url,
                                                     const QString&)
   {
--- a/libgui/src/documentation.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/documentation.h	Sun May 16 09:44:35 2021 +0200
@@ -32,6 +32,7 @@
 #include <QSplitter>
 #include <QTextBrowser>
 #include <QToolBar>
+#include <QListWidget>
 #include <QToolButton>
 #include <QWidget>
 #include <QtHelp/QHelpEngine>
@@ -41,6 +42,7 @@
 namespace octave
 {
   class base_qobject;
+  class documentation;
 
   //! Documentation browser derived from Textbrowser
 
@@ -51,7 +53,7 @@
   public:
 
     documentation_browser (QHelpEngine *help_engine, QWidget *parent = nullptr);
-    ~documentation_browser (void);
+    ~documentation_browser (void) = default;
 
     virtual QVariant loadResource (int type, const QUrl &url);
 
@@ -101,6 +103,17 @@
     documentation (QWidget *parent, base_qobject& oct_qobj);
     ~documentation (void);
 
+    /*!
+        Generate a string with page name @p title and current anchor
+        from @p url for using in prev/next or bookmarks menu:
+
+          @param title current title of the page as QString
+          @param url   current url  as QUrl
+
+          @return QString "title: anchor"
+    */
+    QString title_and_anchor (const QString& title, const QUrl& url);
+
   signals:
 
     void show_single_result (const QUrl&);
@@ -172,6 +185,8 @@
     QAction *m_prev_pages_actions[max_history_entries];
     QAction *m_next_pages_actions[max_history_entries];
 
+    QAction *m_action_bookmark;
+
     QAction *m_action_find;
     QShortcut *m_findnext_shortcut;
     QShortcut *m_findprev_shortcut;
@@ -180,6 +195,7 @@
     QAction *m_action_zoom_out;
     QAction *m_action_zoom_original;
   };
+
 }
 
 #endif
--- a/libgui/src/files-dock-widget.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/files-dock-widget.cc	Sun May 16 09:44:35 2021 +0200
@@ -48,6 +48,7 @@
 #include "gui-preferences-fb.h"
 #include "gui-preferences-global.h"
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 #include "qt-interpreter-events.h"
 
 #include "interpreter.h"
@@ -105,18 +106,6 @@
 
     setWidget (container);
 
-    connect (this, SIGNAL (open_file (const QString&)),
-             main_win (), SLOT (open_file (const QString&)));
-
-    connect (this, SIGNAL (displayed_directory_changed (const QString&)),
-             main_win (),
-             SLOT (set_current_working_directory (const QString&)));
-
-    connect (this,
-             SIGNAL (modify_path_signal (const octave_value_list&, bool, bool)),
-             main_win (),
-             SLOT (modify_path (const octave_value_list&, bool, bool)));
-
     // Create a toolbar
     m_navigation_tool_bar = new QToolBar ("", container);
     m_navigation_tool_bar->setAllowedAreas (Qt::TopToolBarArea);
@@ -165,29 +154,29 @@
     popdown_menu->addSeparator ();
     popdown_menu->addAction (rmgr.icon ("folder"),
                              tr ("Set Browser Directory..."),
-                             this, SLOT (popdownmenu_search_dir (bool)));
+                             this, &files_dock_widget::popdownmenu_search_dir);
     popdown_menu->addSeparator ();
     popdown_menu->addAction (rmgr.icon ("edit-find"),
                              tr ("Find Files..."),
-                             this, SLOT (popdownmenu_findfiles (bool)));
+                             this, &files_dock_widget::popdownmenu_findfiles);
     popdown_menu->addSeparator ();
     popdown_menu->addAction (rmgr.icon ("document-new"),
                              tr ("New File..."),
-                             this, SLOT (popdownmenu_newfile (bool)));
+                             this, &files_dock_widget::popdownmenu_newfile);
     popdown_menu->addAction (rmgr.icon ("folder-new"),
                              tr ("New Directory..."),
-                             this, SLOT (popdownmenu_newdir (bool)));
+                             this, &files_dock_widget::popdownmenu_newdir);
 
     m_navigation_tool_bar->addWidget (m_current_directory);
     m_navigation_tool_bar->addAction (directory_up_action);
     m_navigation_tool_bar->addWidget (popdown_button);
 
-    connect (directory_up_action, SIGNAL (triggered ()), this,
-             SLOT (change_directory_up ()));
-    connect (m_sync_octave_directory_action, SIGNAL (triggered ()), this,
-             SLOT (do_sync_octave_directory ()));
-    connect (m_sync_browser_directory_action, SIGNAL (triggered ()), this,
-             SLOT (do_sync_browser_directory ()));
+    connect (directory_up_action, &QAction::triggered,
+             this, &files_dock_widget::change_directory_up);
+    connect (m_sync_octave_directory_action, &QAction::triggered,
+             this, &files_dock_widget::do_sync_octave_directory);
+    connect (m_sync_browser_directory_action, &QAction::triggered,
+             this, &files_dock_widget::do_sync_browser_directory);
 
     gui_settings *settings = rmgr.get_settings ();
     // FIXME: what should happen if settings is 0?
@@ -245,16 +234,8 @@
         (settings->value (fb_column_state.key).toByteArray ());
 
     // Set header properties for sorting
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
     m_file_tree_view->header ()->setSectionsClickable (true);
-#else
-    m_file_tree_view->header ()->setClickable (true);
-#endif
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSMOVABLE)
     m_file_tree_view->header ()->setSectionsMovable (true);
-#else
-    m_file_tree_view->header ()->setMovable (true);
-#endif
     m_file_tree_view->header ()->setSortIndicatorShown (true);
 
     QStringList mru_dirs =
@@ -264,19 +245,18 @@
     m_current_directory->setEditText
       (m_file_system_model->fileInfo (rootPathIndex). absoluteFilePath ());
 
-    connect (m_file_tree_view, SIGNAL (activated (const QModelIndex &)),
-             this, SLOT (item_double_clicked (const QModelIndex &)));
+    connect (m_file_tree_view, &FileTreeViewer::activated,
+             this, &files_dock_widget::item_double_clicked);
 
     // add context menu to tree_view
     m_file_tree_view->setContextMenuPolicy (Qt::CustomContextMenu);
-    connect (m_file_tree_view,
-             SIGNAL (customContextMenuRequested (const QPoint &)),
-             this, SLOT (contextmenu_requested (const QPoint &)));
+    connect (m_file_tree_view, &FileTreeViewer::customContextMenuRequested,
+             this, &files_dock_widget::contextmenu_requested);
 
     m_file_tree_view->header ()->setContextMenuPolicy (Qt::CustomContextMenu);
     connect (m_file_tree_view->header (),
-             SIGNAL (customContextMenuRequested (const QPoint &)),
-             this, SLOT (headercontextmenu_requested (const QPoint &)));
+             &QHeaderView::customContextMenuRequested,
+             this, &files_dock_widget::headercontextmenu_requested);
 
     // Layout the widgets vertically with the toolbar on top
     QVBoxLayout *vbox_layout = new QVBoxLayout ();
@@ -290,15 +270,27 @@
     // FIXME: Add right-click contextual menus for copying, pasting,
     //        deleting files (and others).
 
-    connect (m_current_directory->lineEdit (), SIGNAL (returnPressed ()),
-             this, SLOT (accept_directory_line_edit ()));
+    connect (m_current_directory->lineEdit (), &QLineEdit::returnPressed,
+             this, &files_dock_widget::accept_directory_line_edit);
+
+    // FIXME: We could use
+    //
+    //    connect (m_current_directory,
+    //             QOverload<const QString&>::of (&QComboBox::activated),
+    //             this, &files_dock_widget::set_current_directory);
+    //
+    // but referring to QComboBox::activated will generate deprecated
+    // function warnings from GCC.  We could also use
+    //
+    //    connect (m_current_directory, &QComboBox::textActivated,
+    //             this, &files_dock_widget::set_current_directory);
+    //
+    // but the function textActivated was not introduced until Qt 5.14
+    // so we'll need a feature test.
 
     connect (m_current_directory, SIGNAL (activated (const QString &)),
              this, SLOT (set_current_directory (const QString &)));
 
-    connect (this, SIGNAL (run_file_signal (const QFileInfo&)),
-             main_win (), SLOT (run_file_in_terminal (const QFileInfo&)));
-
     QCompleter *completer = new QCompleter (m_file_system_model, this);
     m_current_directory->setCompleter (completer);
 
@@ -306,6 +298,9 @@
 
     m_sync_octave_dir = true;   // default, overwritten with notice_settings ()
     m_octave_dir = "";
+
+    if (! p)
+      make_window ();
   }
 
   void files_dock_widget::save_settings (void)
@@ -491,6 +486,20 @@
                             m_columns_shown_defs.at (i)).toBool ());
       }
 
+    // FIXME: We could use
+    //
+    //   connect (&m_sig_mapper, QOverload<int>::of (&QSignalMapper::mapped),
+    //            this, &workspace_view::toggle_header);
+    //
+    // but referring to QSignalMapper::mapped will generate deprecated
+    // function warnings from GCC.  We could also use
+    //
+    //   connect (&m_sig_mapper, &QSignalMapper::mappedInt,
+    //            this, &workspace_view::toggle_header);
+    //
+    // but the function mappedInt was not introduced until Qt 5.15 so
+    // we'll need a feature test.
+
     connect (m_sig_mapper, SIGNAL (mapped (int)),
              this, SLOT (toggle_header (int)));
 
@@ -525,70 +534,68 @@
 
         // construct the context menu depending on item
         menu.addAction (rmgr.icon ("document-open"), tr ("Open"),
-                        this, SLOT (contextmenu_open (bool)));
+                        this, &files_dock_widget::contextmenu_open);
 
         if (info.isDir ())
           {
             menu.addAction (tr ("Open in System File Explorer"),
-                            this, SLOT (contextmenu_open_in_app (bool)));
+                            this, &files_dock_widget::contextmenu_open_in_app);
           }
 
         if (info.isFile ())
           menu.addAction (tr ("Open in Text Editor"),
-                          this, SLOT (contextmenu_open_in_editor (bool)));
+                          this, &files_dock_widget::contextmenu_open_in_editor);
 
         menu.addAction (tr ("Copy Selection to Clipboard"),
-                        this, SLOT (contextmenu_copy_selection (bool)));
+                        this, &files_dock_widget::contextmenu_copy_selection);
 
         if (info.isFile () && info.suffix () == "m")
-          menu.addAction (rmgr.icon ("media-playback-start"),
-                          tr ("Run"), this, SLOT (contextmenu_run (bool)));
+          menu.addAction (rmgr.icon ("media-playback-start"), tr ("Run"),
+                          this, &files_dock_widget::contextmenu_run);
 
         if (info.isFile ())
-          menu.addAction (tr ("Load Data"), this, SLOT (contextmenu_load (bool)));
+          menu.addAction (tr ("Load Data"),
+                          this, &files_dock_widget::contextmenu_load);
 
         if (info.isDir ())
           {
             menu.addSeparator ();
-            menu.addAction (rmgr.icon ("go-first"),
-                            tr ("Set Current Directory"),
-                            this, SLOT (contextmenu_setcurrentdir (bool)));
+            menu.addAction (rmgr.icon ("go-first"), tr ("Set Current Directory"),
+                            this, &files_dock_widget::contextmenu_setcurrentdir);
 
             QMenu *add_path_menu = menu.addMenu (tr ("Add to Path"));
 
             add_path_menu->addAction (tr ("Selected Directories"),
-                                      this, SLOT (contextmenu_add_to_path (bool)));
+                                      this, [=] (bool checked) { contextmenu_add_to_path (checked); });
             add_path_menu->addAction (tr ("Selected Directories and Subdirectories"),
-                                      this, SLOT (contextmenu_add_to_path_subdirs (bool)));
+                                      this, &files_dock_widget::contextmenu_add_to_path_subdirs);
 
             QMenu *rm_path_menu = menu.addMenu (tr ("Remove from Path"));
 
-            rm_path_menu->addAction (tr ("Selected Directories"), this,
-                                     SLOT (contextmenu_rm_from_path (bool)));
+            rm_path_menu->addAction (tr ("Selected Directories"),
+                                     this, &files_dock_widget::contextmenu_rm_from_path);
             rm_path_menu->addAction (tr ("Selected Directories and Subdirectories"),
-                                     this, SLOT (contextmenu_rm_from_path_subdirs (bool)));
+                                     this, &files_dock_widget::contextmenu_rm_from_path_subdirs);
 
             menu.addSeparator ();
 
-            menu.addAction (rmgr.icon ("edit-find"),
-                            tr ("Find Files..."), this,
-                            SLOT (contextmenu_findfiles (bool)));
+            menu.addAction (rmgr.icon ("edit-find"), tr ("Find Files..."),
+                            this, &files_dock_widget::contextmenu_findfiles);
           }
 
         menu.addSeparator ();
-        menu.addAction (tr ("Rename..."), this, SLOT (contextmenu_rename (bool)));
-        menu.addAction (rmgr.icon ("edit-delete"),
-                        tr ("Delete..."), this, SLOT (contextmenu_delete (bool)));
+        menu.addAction (tr ("Rename..."),
+                        this, &files_dock_widget::contextmenu_rename);
+        menu.addAction (rmgr.icon ("edit-delete"), tr ("Delete..."),
+                        this, &files_dock_widget::contextmenu_delete);
 
         if (info.isDir ())
           {
             menu.addSeparator ();
-            menu.addAction (rmgr.icon ("document-new"),
-                            tr ("New File..."),
-                            this, SLOT (contextmenu_newfile (bool)));
-            menu.addAction (rmgr.icon ("folder-new"),
-                            tr ("New Directory..."),
-                            this, SLOT (contextmenu_newdir (bool)));
+            menu.addAction (rmgr.icon ("document-new"), tr ("New File..."),
+                            this, &files_dock_widget::contextmenu_newfile);
+            menu.addAction (rmgr.icon ("folder-new"), tr ("New Directory..."),
+                            this, &files_dock_widget::contextmenu_newdir);
           }
 
         // show the menu
@@ -723,17 +730,38 @@
     QItemSelectionModel *m = m_file_tree_view->selectionModel ();
     QModelIndexList rows = m->selectedRows ();
 
+    int file_cnt = rows.size ();
+    bool multiple_files = (file_cnt > 1);
+
     for (auto it = rows.begin (); it != rows.end (); it++)
       {
         QModelIndex index = *it;
 
         QFileInfo info = m_file_system_model->fileInfo (index);
 
-        if (QMessageBox::question (this, tr ("Delete file/directory"),
-                                   tr ("Are you sure you want to delete\n")
-                                   + info.filePath (),
-                                   QMessageBox::Yes | QMessageBox::No)
-            == QMessageBox::Yes)
+        QMessageBox::StandardButton dlg_answer;
+        if (multiple_files)
+          if (it == rows.begin ())
+            {
+               dlg_answer = QMessageBox::question (this,
+                              tr ("Delete file/directory"),
+                              tr ("Are you sure you want to delete all %1 selected files?\n").arg (file_cnt),
+                              QMessageBox::Yes | QMessageBox::No);
+               if (dlg_answer != QMessageBox::Yes)
+                 return;
+            }
+          else
+            dlg_answer = QMessageBox::Yes;
+        else
+          {
+            dlg_answer = QMessageBox::question (this,
+                           tr ("Delete file/directory"),
+                           tr ("Are you sure you want to delete\n")
+                           + info.filePath (),
+                           QMessageBox::Yes | QMessageBox::No);
+          }
+
+        if (dlg_answer)
           {
             if (info.isDir ())
               {
--- a/libgui/src/find-files-dialog.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/find-files-dialog.cc	Sun May 16 09:44:35 2021 +0200
@@ -64,8 +64,8 @@
     m_dir_iterator = nullptr;
 
     m_timer = new QTimer (this);
-    connect (m_timer, SIGNAL (timeout (void)),
-             this, SLOT (look_for_files (void)));
+    connect (m_timer, &QTimer::timeout,
+             this, &find_files_dialog::look_for_files);
 
     gui_settings *settings = rmgr.get_settings ();
 
@@ -86,8 +86,8 @@
 
     m_browse_button = new QPushButton (tr ("Browse..."));
     m_browse_button->setToolTip (tr ("Browse for start directory"));
-    connect (m_browse_button, SIGNAL (clicked (void)),
-             this, SLOT (browse_folders (void)));
+    connect (m_browse_button, &QPushButton::clicked,
+             this, &find_files_dialog::browse_folders);
 
     m_recurse_dirs_check = new QCheckBox (tr ("Search subdirectories"));
     m_recurse_dirs_check->setChecked (settings->value (ff_recurse_dirs).toBool ());
@@ -126,11 +126,7 @@
     m_file_list->setSortingEnabled (true);
     m_file_list->horizontalHeader ()->restoreState (settings->value (ff_column_state.key).toByteArray ());
     m_file_list->horizontalHeader ()->setSortIndicatorShown (true);
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
     m_file_list->horizontalHeader ()->setSectionsClickable (true);
-#else
-    m_file_list->horizontalHeader ()->setClickable (true);
-#endif
     m_file_list->horizontalHeader ()->setStretchLastSection (true);
     m_file_list->sortByColumn (settings->value (ff_sort_files_by_column).toInt (),
                                static_cast<Qt::SortOrder>
@@ -138,22 +134,22 @@
                 // FIXME: use value<Qt::SortOrder> instead of static cast after
                 //        dropping support of Qt 5.4
 
-    connect (m_file_list, SIGNAL (doubleClicked (const QModelIndex&)),
-             this, SLOT (item_double_clicked (const QModelIndex &)));
+    connect (m_file_list, &QTableView::doubleClicked,
+             this, &find_files_dialog::item_double_clicked);
 
     m_status_bar = new QStatusBar;
     m_status_bar->showMessage (tr ("Idle."));
 
     m_find_button = new QPushButton (tr ("Find"));
     m_find_button->setToolTip (tr ("Start search for matching files"));
-    connect (m_find_button, SIGNAL (clicked (void)),
-             this, SLOT (start_find (void)));
+    connect (m_find_button, &QPushButton::clicked,
+             this, &find_files_dialog::start_find);
 
     m_stop_button = new QPushButton (tr ("Stop"));
     m_stop_button->setToolTip (tr ("Stop searching"));
     m_stop_button->setEnabled (false);
-    connect (m_stop_button, SIGNAL (clicked (void)),
-             this, SLOT (stop_find (void)));
+    connect (m_stop_button, &QPushButton::clicked,
+             this, &find_files_dialog::stop_find);
 
     // layout everything
     QDialogButtonBox *button_box = new QDialogButtonBox (Qt::Vertical);
@@ -162,7 +158,8 @@
 
     // add dialog close button
     m_close_button = button_box->addButton (QDialogButtonBox::Close);
-    connect (button_box, SIGNAL (rejected (void)), this, SLOT (close (void)));
+    connect (button_box, &QDialogButtonBox::rejected,
+             this, &find_files_dialog::close);
 
     // name options
     QGroupBox *name_group = new QGroupBox (tr ("Filename/location"));
@@ -201,7 +198,8 @@
 
     setLayout (main_layout);
 
-    connect (this, SIGNAL (finished (int)), this, SLOT (handle_done (int)));
+    connect (this, &find_files_dialog::finished,
+             this, &find_files_dialog::handle_done);
   }
 
   find_files_dialog::~find_files_dialog (void)
--- a/libgui/src/graphics-init.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/graphics-init.cc	Sun May 16 09:44:35 2021 +0200
@@ -63,7 +63,7 @@
 
     graphics_toolkit tk (qt_gtk);
 
-    octave::gtk_manager& gtk_mgr = interp.get_gtk_manager ();
+    gtk_manager& gtk_mgr = interp.get_gtk_manager ();
 
     gtk_mgr.register_toolkit ("qt");
 
--- a/libgui/src/gui-preferences-cs.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-preferences-cs.h	Sun May 16 09:44:35 2021 +0200
@@ -27,6 +27,7 @@
 #define octave_gui_preferences_cs_h 1
 
 #include "gui-preferences.h"
+#include "gui-settings.h"
 
 // Console preferences
 
@@ -55,13 +56,20 @@
 const gui_pref
 cs_hist_buffer ("terminal/history_buffer", QVariant (1000));
 
+const gui_pref
+cs_color_mode ("terminal/color_mode", QVariant (0));
+
 const unsigned int cs_colors_count = 4;
-const gui_pref cs_colors[cs_colors_count] =
+const gui_pref cs_colors[2*cs_colors_count] =
 {
-  {"terminal/color_f", QVariant (QColor(0,0,0))},
-  {"terminal/color_b", QVariant (QColor(255,255,255))},
-  {"terminal/color_s", QVariant (QColor(192,192,192))},
-  {"terminal/color_c", QVariant (QColor(128,128,128))}
+  {"terminal/color_f" + settings_color_modes_ext[0], QVariant (QPalette::WindowText)},
+  {"terminal/color_b" + settings_color_modes_ext[0], QVariant (QPalette::Base)},
+  {"terminal/color_s" + settings_color_modes_ext[0], QVariant (QPalette::Highlight)},
+  {"terminal/color_c" + settings_color_modes_ext[0], QVariant (QPalette::QPalette::WindowText)},
+  {"terminal/color_f" + settings_color_modes_ext[1], QVariant ()}, // Default colors for 2nd mode empty,
+  {"terminal/color_b" + settings_color_modes_ext[1], QVariant ()}, // since they are determined at runtime
+  {"terminal/color_s" + settings_color_modes_ext[1], QVariant ()}, // by inverting the lightness of the
+  {"terminal/color_c" + settings_color_modes_ext[1], QVariant ()}  // default colors in light mode
 };
 const QStringList
 cs_color_names (QStringList ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/gui-preferences-dc.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,57 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2017-2021 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_gui_preferences_dc_h)
+#define octave_gui_preferences_dc_h 1
+
+#include "gui-preferences.h"
+
+// documentation properties
+
+const QString
+dc_bookmark_file ("octave-doc-bookmarks.xbel");
+const gui_pref
+dc_bookmark_filter_active ("documentation_widget/filter_active", QVariant (false));
+
+const gui_pref
+dc_bookmark_filter_shown ("documentation_widget/filter_shown", QVariant (true));
+
+const gui_pref
+dc_bookmark_filter_mru ("documentation_widget/bookmark_filter_mru", QVariant ());
+
+// Constants for the xbel file format
+const QLatin1String dc_xbel_doctype ("<!DOCTYPE xbel>");
+const QLatin1String dc_xbel_attr_href ("href");
+const QLatin1String dc_xbel_attr_folded ("folded");
+const QLatin1String dc_xbel_attr_version ("version");
+const QLatin1String dc_xbel_value_version ("1.0");
+const QLatin1String dc_xbel_value_yes ("yes");
+const QLatin1String dc_xbel_value_no ("no");
+const QLatin1String dc_xbel_name_title ("title");
+const QLatin1String dc_xbel_name_folder ("folder");
+const QLatin1String dc_xbel_name_bookmark ("bookmark");
+const QLatin1String dc_xbel_name_format ("xbel");
+
+#endif
--- a/libgui/src/gui-preferences-dw.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-preferences-dw.h	Sun May 16 09:44:35 2021 +0200
@@ -29,6 +29,9 @@
 #include "gui-preferences.h"
 
 const gui_pref
+dw_focus_follows_mouse ("DockWidgets/focus_follows_mouse", QVariant (false));
+
+const gui_pref
 dw_title_custom_style ("DockWidgets/widget_title_custom_style",
                        QVariant (false));
 
--- a/libgui/src/gui-preferences-ed.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-preferences-ed.h	Sun May 16 09:44:35 2021 +0200
@@ -35,6 +35,14 @@
 
 // Editor preferences
 
+// Lexer
+
+const gui_pref
+ed_color_mode ("editor/color_mode", QVariant (0));
+
+const int ed_max_lexer_styles = 64;
+const int ed_max_style_number = 128;
+
 // Code completion
 
 const gui_pref
@@ -117,6 +125,8 @@
 const gui_pref
 ed_break_lines_comments ("editor/break_lines_comments", QVariant (false));
 
+// Other
+
 const gui_pref
 ed_highlight_all_occurrences ("editor/highlight_all_occurrences",
                               QVariant (true));
@@ -134,10 +144,6 @@
 ed_highlight_current_line ("editor/highlightCurrentLine", QVariant (true));
 
 const gui_pref
-ed_highlight_current_line_color ("editor/highlight_current_line_color",
-                                 QVariant (QColor (240, 240, 240)));
-
-const gui_pref
 ed_show_white_space ("editor/show_white_space", QVariant (false));
 
 const gui_pref
@@ -204,16 +210,19 @@
 const gui_pref
 ed_tab_position ("editor/tab_position", QVariant (QTabWidget::North));
 
+const gui_pref
+ed_tabs_rotated ("editor/tabs_rotated", QVariant (false));
+
+const gui_pref
+ed_tabs_max_width ("editor/tabs_max_width", QVariant (0));
+
 // File handling
 
 const gui_pref
-ed_long_window_title ("editor/longWindowTitle", QVariant (false));
+ed_force_newline ("editor/force_newline", QVariant (true));
 
 const gui_pref
-ed_notebook_tab_width_min ("editor/notebook_tab_width_min", QVariant (160));
-
-const gui_pref
-ed_notebook_tab_width_max ("editor/notebook_tab_width_max", QVariant (300));
+ed_rm_trailing_spaces ("editor/rm_trailing_spaces", QVariant (true));
 
 #if defined (HAVE_QSCINTILLA)
 #if defined (Q_OS_WIN32)
@@ -232,10 +241,7 @@
 ed_show_dbg_file ("editor/show_dbg_file", QVariant (true));
 
 const gui_pref
-ed_default_enc ("editor/default_encoding",
-                QVariant (QString ("SYSTEM (") +
-                          QString (octave_locale_charset_wrapper ()).toUpper () +
-                          QString (")")));
+ed_default_enc ("editor/default_encoding", QVariant ("UTF-8"));
 
 const gui_pref
 ed_create_new_file ("editor/create_new_file", QVariant (false));
--- a/libgui/src/gui-preferences-global.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-preferences-global.h	Sun May 16 09:44:35 2021 +0200
@@ -49,8 +49,6 @@
 
 const QString
 global_toolbar_style ("QToolBar {"
-                      "spacing-top: 0px;"
-                      "spacing-bottom: 0px;"
                       "margin-top: 0px;"
                       "margin-bottom: 0px;"
                       "padding-top: 0px;"
@@ -61,8 +59,6 @@
 
 const QString
 global_menubar_style ("QMenuBar {"
-                      "spacing-top: 0px;"
-                      "spacing-bottom: 0px;"
                       "margin-top: 0px;"
                       "margin-bottom: 0px;"
                       "padding-top: 0px;"
@@ -115,8 +111,14 @@
 
 const gui_pref
 global_use_custom_editor ("useCustomFileEditor", QVariant (false));
+
+#if defined (Q_OS_WIN32)
+const gui_pref
+global_custom_editor ("customFileEditor", QVariant ("notepad++ -n%l %f"));
+#else
 const gui_pref
 global_custom_editor ("customFileEditor", QVariant ("emacs +%l %f"));
+#endif
 
 const gui_pref
 global_prompt_to_exit ("prompt_to_exit", QVariant (false));
@@ -136,4 +138,13 @@
 const gui_pref
 global_proxy_pass ("proxyPassword", QVariant (QString ()));
 
+const QStringList
+global_proxy_all_types (QStringList ()
+             << "HttpProxy"
+             << "Socks5Proxy"
+             << QT_TRANSLATE_NOOP ("octave::settings_dialog", "Environment Variables")
+);
+const QList<int>
+global_proxy_manual_types (QList<int> () << 0 << 1);
+
 #endif
--- a/libgui/src/gui-preferences-sc.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-preferences-sc.h	Sun May 16 09:44:35 2021 +0200
@@ -96,6 +96,13 @@
 const sc_pref sc_main_debug_continue (sc_main_debug + ":continue", PRE + Qt::Key_F5);
 const sc_pref sc_main_debug_quit (sc_main_debug + ":quit", PRE + Qt::ShiftModifier + Qt::Key_F5);
 
+// tools
+const QString sc_main_tools ("main_tools");
+const sc_pref sc_main_tools_start_profiler (sc_main_tools + ":start_profiler", CTRL_SHIFT + Qt::Key_P);
+const sc_pref sc_main_tools_resume_profiler (sc_main_tools + ":resume_profiler", QKeySequence::UnknownKey);
+const sc_pref sc_main_tools_show_profiler (sc_main_tools + ":show_profiler", Qt::AltModifier + Qt::ShiftModifier + Qt::Key_P);
+
+
 // window
 const QString sc_main_window ("main_window");
 const sc_pref sc_main_window_show_command (sc_main_window + ":show_command", PRE + CTRL_SHIFT + Qt::Key_0);
@@ -248,6 +255,7 @@
 const sc_pref sc_doc_go_home (sc_doc + ":go_home", Qt::AltModifier + Qt::Key_Home);
 const sc_pref sc_doc_go_back (sc_doc + ":go_back", QKeySequence::Back);
 const sc_pref sc_doc_go_next (sc_doc + ":go_next", QKeySequence::Forward);
+const sc_pref sc_doc_bookmark (sc_doc + ":bookmark", CTRL + Qt::Key_D);
 
 
 // Other normal, shortcut related options
@@ -257,5 +265,7 @@
 
 const gui_pref
 sc_prevent_rl_conflicts ("shortcuts/prevent_readline_conflicts", QVariant (true));
+const gui_pref
+sc_prevent_rl_conflicts_menu ("shortcuts/prevent_readline_conflicts_menu", QVariant (false));
 
 #endif
--- a/libgui/src/gui-preferences-ve.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-preferences-ve.h	Sun May 16 09:44:35 2021 +0200
@@ -50,17 +50,24 @@
 const gui_pref
 ve_alternate_rows ("variable_editor/alternate_rows", QVariant (false));
 
-const int ve_colors_count = 5;
+const gui_pref
+ve_color_mode ("variable_editor/color_mode", QVariant (0));
 
 const QString ve_color_chars ("fbsha");
 
-const gui_pref ve_colors[ve_colors_count] =
+const int ve_colors_count = 5;
+const gui_pref ve_colors[2*ve_colors_count] =
 {
-  {"variable_editor/color_f", QVariant (QPalette::WindowText)},
-  {"variable_editor/color_b", QVariant (QPalette::Base)},
-  {"variable_editor/color_s", QVariant (QPalette::HighlightedText)},
-  {"variable_editor/color_h", QVariant (QPalette::Highlight)},
-  {"variable_editor/color_a", QVariant (QPalette::AlternateBase)}
+  {"variable_editor/color_f" + settings_color_modes_ext[0], QVariant (QPalette::WindowText)},
+  {"variable_editor/color_b" + settings_color_modes_ext[0], QVariant (QPalette::Base)},
+  {"variable_editor/color_s" + settings_color_modes_ext[0], QVariant (QPalette::HighlightedText)},
+  {"variable_editor/color_h" + settings_color_modes_ext[0], QVariant (QPalette::Highlight)},
+  {"variable_editor/color_a" + settings_color_modes_ext[0], QVariant (QPalette::AlternateBase)},
+  {"variable_editor/color_f" + settings_color_modes_ext[1], QVariant ()},
+  {"variable_editor/color_b" + settings_color_modes_ext[1], QVariant ()},
+  {"variable_editor/color_s" + settings_color_modes_ext[1], QVariant ()},
+  {"variable_editor/color_h" + settings_color_modes_ext[1], QVariant ()},
+  {"variable_editor/color_a" + settings_color_modes_ext[1], QVariant ()}
 };
 
 const QStringList ve_color_names (QStringList ()
@@ -70,4 +77,37 @@
     << QT_TRANSLATE_NOOP ("octave::settings_dialog", "Selected Background")
     << QT_TRANSLATE_NOOP ("octave::settings_dialog", "Alternate Background"));
 
+const QStringList ve_save_formats (QStringList ()
+                << "ascii"
+                << "binary"
+                << "float-binary"
+                << "hdf5"
+                << "float-hdf5"
+                << "text"
+                << "mat7-binary"
+                << "mat-binary"
+                << "mat4-binary"
+                << "zip");
+
+// The following list is a relation between save format and fiel extension.
+// The format string are case insensitive.
+const QStringList ve_save_formats_ext (QStringList ()
+                << "-ascii"         << "dat"
+                << "-hdf5"          << "h5"
+                << "-text"          << "txt"
+                << "-v7.3"          << "mat"
+                << "-7.3"           << "mat"
+                << "-v7"            << "mat"
+                << "-7"             << "mat"
+                << "-mat7-binary"   << "mat"
+                << "-v6"            << "mat"
+                << "-6"             << "mat"
+                << "-mat-binary"    << "mat"
+                << "-v4"            << "mat"
+                << "-4"             << "mat"
+                << "-mat4-binary"   << "mat"
+                << "-binary"        << "bin"    // after other fmt incl. "-binary"
+                << "-z"             << "txt.gz" // gzipped -text
+              );
+
 #endif
--- a/libgui/src/gui-preferences-ws.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-preferences-ws.h	Sun May 16 09:44:35 2021 +0200
@@ -27,6 +27,7 @@
 #define octave_gui_preferences_ws_h 1
 
 #include "gui-preferences.h"
+#include "gui-settings.h"
 
 // Workspace view
 
@@ -69,13 +70,18 @@
 const gui_pref
 ws_max_filter_history ("workspaceview/max_filter_history", QVariant (10));
 
-const int ws_colors_count = 3;
+const gui_pref
+ws_color_mode ("workspaceview/color_mode", QVariant (0));
 
-const gui_pref ws_colors[ws_colors_count] =
+const int ws_colors_count = 3;
+const gui_pref ws_colors[2*ws_colors_count] =
 {
-  {"terminal/color_a", QVariant (QColor(190,255,255))},
-  {"terminal/color_g", QVariant (QColor(255,255,190))},
-  {"terminal/color_p", QVariant (QColor(255,190,255))}
+  {"workspaceview/color_a" + settings_color_modes_ext[0], QVariant (QPalette::Highlight)},
+  {"workspaceview/color_g" + settings_color_modes_ext[0], QVariant (QPalette::Midlight)},
+  {"workspaceview/color_p" + settings_color_modes_ext[0], QVariant (QPalette::Dark)},
+  {"workspaceview/color_a" + settings_color_modes_ext[1], QVariant ()},
+  {"workspaceview/color_g" + settings_color_modes_ext[1], QVariant ()},
+  {"workspaceview/color_p" + settings_color_modes_ext[1], QVariant ()}
 };
 
 const QString ws_class_chars ("agp");
--- a/libgui/src/gui-settings.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-settings.cc	Sun May 16 09:44:35 2021 +0200
@@ -27,6 +27,7 @@
 #  include "config.h"
 #endif
 
+#include <QApplication>
 #include <QSettings>
 
 #include "gui-settings.h"
@@ -34,6 +35,56 @@
 namespace octave
 {
 
+  QColor gui_settings::get_color_value (const QVariant& def, int mode) const
+  {
+    QColor default_color;
+
+    // Determine whether the default value in pref is given as
+    // QPalette::ColorRole or as QColor
+    if (def.canConvert (QMetaType::QColor))
+      default_color = def.value<QColor> ();
+    else
+      {
+        // The default colors are given as color roles for
+        // the application's palette
+        default_color = QApplication::palette ().color
+                        (static_cast<QPalette::ColorRole> (def.toInt ()));
+                  // FIXME: use value<QPalette::ColorRole> instead of static cast after
+                  //        dropping support of Qt 5.4
+      }
+
+    if ((mode == 1) && (default_color != settings_color_no_change))
+      {
+        // In second mode, determine the default color from the first mode
+        qreal h, s, l, a;
+        default_color.getHslF (&h, &s, &l, &a);
+        qreal l_new = 1.0-l*0.85;
+        if (l < 0.3)
+          l_new = 1.0-l*0.7;  // convert darker into lighter colors
+        default_color.setHslF (h, s, l_new, a);
+      }
+
+    return default_color;
+  }
+
+  QColor gui_settings::color_value (const gui_pref& pref, int mode) const
+  {
+    QColor default_color = get_color_value (pref.def, mode);
+
+    return value (pref.key + settings_color_modes_ext[mode],
+                  QVariant (default_color)).value<QColor> ();
+  }
+
+  void gui_settings::set_color_value (const gui_pref& pref,
+                                      const QColor& color, int mode)
+  {
+    int m = mode;
+    if (m > 1)
+      m = 1;
+
+    setValue (pref.key + settings_color_modes_ext[m], QVariant (color));
+  }
+
   QString gui_settings::sc_value (const sc_pref& pref) const
   {
     QKeySequence key_seq = sc_def_value (pref);
--- a/libgui/src/gui-settings.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/gui-settings.h	Sun May 16 09:44:35 2021 +0200
@@ -68,12 +68,91 @@
       return value (pref.key, pref.def);
     }
 
+    /*!
+      Reading a color from the given QVaraitn @p def taking different
+      color modes into account. The default value for a second color mode
+      @p mode=1 is deterimined from the standard default value @p mode=0
+      by inverting the lightness
+        \f{eqnarray*}{
+           H_1 &=& H_0\\
+           S_1 &=& S_0\\
+           L_1 &=& 1.0 - 0.85 L_0    L_0 > 0.3
+           L_1 &=& 1.0 - 0.70 L_0    L_0 < 0.3
+        \f}
+
+      @param def  Color default value given by a QVariant of QColor
+                  or QPalette::ColorRole
+      @param mode Color mode (currently 0 or 1, default is 0)
+
+      @return Color as QColor
+    */
+    QColor get_color_value (const QVariant& def, int mode = 0) const;
+
+    /*!
+      Reading a color from the gui_settings taking possible color modes
+      into account. The default value for a second color mode @p mode=1 is
+      deterimined from the standard default value @p mode=0 by inverting
+      the lightness (see get_color_value())
+
+      @param pref gui preference (key string, default value); the default
+                  value can be given by QColor or QPalette::ColorRole
+      @param mode Color mode (currently 0 or 1, default is 0)
+
+      @return Color as QColor
+    */
+    QColor color_value (const gui_pref& pref, int mode = 0) const;
+
+    /*!
+      Writing a color to the gui_settings taking possible color modes
+      into account. When @p mode is not zero (standard mode), the
+      extension related to the mode is appended to the settings key string
+
+      @param pref gui preference where the color should be written
+      @param color QColor to write to the settings
+      @param mode Color mode (currently 0 or 1, default is 0)
+
+    */
+    void set_color_value (const gui_pref& pref, const QColor& color,
+                          int mode = 0);
+
     QString sc_value (const sc_pref& pref) const;
 
     QKeySequence sc_def_value (const sc_pref& pref) const;
 
   };
+
 }
 
+// Some constants used several times in the settings
+
+// Special color indicating no change compared to default color
+const QColor settings_color_no_change (255,0,255);
+
+// Other color schemes (currently one extra, but possibly more in the future)
+const QString settings_color_modes = QT_TRANSLATE_NOOP (
+    "octave::settings_dialog",
+    "Second color mode (light/dark)");
+const QString settings_color_modes_tooltip = QT_TRANSLATE_NOOP (
+    "octave::settings_dialog",
+    "Switches to another set of colors.\n"
+    "Useful for defining a dark/light mode.\n"
+    "Discards non-applied current changes!");
+const QStringList settings_color_modes_ext (QStringList () << "" << "_2");
+// Reset colors (reload default values)
+const QString settings_reload_colors = QT_TRANSLATE_NOOP (
+    "octave::settings_dialog",
+    "&Reload default colors");
+const QString settings_reload_colors_tooltip = QT_TRANSLATE_NOOP (
+    "octave::settings_dialog",
+    "Reloads the default colors,\n"
+    "depending on currently selected mode.");
+const QString settings_reload_styles = QT_TRANSLATE_NOOP (
+    "octave::settings_dialog",
+    "&Reload default styles");
+const QString settings_reload_styles_tooltip = QT_TRANSLATE_NOOP (
+    "octave::settings_dialog",
+    "Reloads the default values of the styles,\n"
+    "depending on currently selected mode.");
+const int settings_reload_default_colors_flag = -1;
 #endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/gui-utils.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,45 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2000-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "gui-utils.h"
+
+namespace octave
+{
+  OCTGUI_API QColor
+  interpolate_color (const QColor& col1, const QColor& col2,
+                     double fs, double fv)
+  {
+    qreal h1, s1, v1, h2, s2, v2;
+
+    col1.getHsvF (&h1, &s1, &v1);
+    col2.getHsvF (&h2, &s2, &v2);
+
+    return QColor::fromHsvF (h1, s1*fs, v1 + fv*(v2 - v1));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/gui-utils.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 1993-2021 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_gui_utils_h)
+#define octave_gui_utils_h 1
+
+#include <QColor>
+
+namespace octave
+{
+
+  /*!
+      Deterimine an alternative color to @p col1 with less contrast
+      to @p col2. The HSV representation of the new color is calculated by
+        \f{eqnarray*}{
+           H &=& H_1\\
+           S &=& f_s S_1\\
+           V &=& V_1 + f_s (V_2 - V_1)
+        \f}
+
+      @param col1 Base color to which the alternative has to be computed
+      @param col2 Color to which the the new color should have less contrast
+      @param fs Factor for changing the saturation \f$(0\ldots\infty)\f$
+      @param fv Factor for interpolating the brightness \f$(0\ldots 1)\f$.
+             For 0, \f$V = V_1\f$ and for 1, \f$V = V_2\f$.
+
+      @return New color as QColor
+  */
+
+  extern OCTGUI_API QColor
+  interpolate_color (const QColor& col1, const QColor& col2,
+                     double fs, double fv);
+
+}
+
+#endif
--- a/libgui/src/history-dock-widget.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/history-dock-widget.cc	Sun May 16 09:44:35 2021 +0200
@@ -52,16 +52,10 @@
   {
     setStatusTip (tr ("Browse and search the command history."));
 
-    connect (this, SIGNAL (command_create_script (const QString&)),
-             p, SLOT (new_file (const QString&)));
+    construct ();
 
-    connect (this, SIGNAL (information (const QString&)),
-             p, SLOT (report_status_message (const QString&)));
-
-    connect (this, SIGNAL (command_double_clicked (const QString&)),
-             p, SLOT (execute_command_in_terminal (const QString&)));
-
-    construct ();
+    if (! p)
+      make_window ();
   }
 
   void history_dock_widget::set_history (const QStringList& hist)
@@ -124,6 +118,20 @@
     m_filter->setCurrentIndex (0);
   }
 
+  void history_dock_widget::set_filter_focus (bool focus)
+  {
+    if (focus)
+      {
+        m_filter->setFocus ();
+        setFocusProxy (m_filter);
+      }
+    else
+      {
+        m_history_list_view->setFocus ();
+        setFocusProxy (m_history_list_view);
+      }
+  }
+
   void history_dock_widget::filter_activate (bool state)
   {
     m_filter->setEnabled (state);
@@ -133,6 +141,8 @@
       m_sort_filter_proxy_model.setFilterWildcard (m_filter->currentText ());
     else
       m_sort_filter_proxy_model.setFilterWildcard (QString ());
+
+    set_filter_focus (state);
   }
 
   void history_dock_widget::ctxMenu (const QPoint& xpos)
@@ -146,18 +156,18 @@
         resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
 
         menu.addAction (rmgr.icon ("edit-copy"), tr ("Copy"), this,
-                        SLOT (handle_contextmenu_copy (bool)));
+                        &history_dock_widget::handle_contextmenu_copy);
         menu.addAction (tr ("Evaluate"), this,
-                        SLOT (handle_contextmenu_evaluate (bool)));
+                        &history_dock_widget::handle_contextmenu_evaluate);
         menu.addAction (rmgr.icon ("document-new"), tr ("Create script"), this,
-                        SLOT (handle_contextmenu_create_script (bool)));
+                        &history_dock_widget::handle_contextmenu_create_script);
       }
     if (m_filter_shown)
       menu.addAction (tr ("Hide filter"), this,
-                      SLOT (handle_contextmenu_filter ()));
+                      &history_dock_widget::handle_contextmenu_filter);
     else
       menu.addAction (tr ("Show filter"), this,
-                      SLOT (handle_contextmenu_filter ()));
+                      &history_dock_widget::handle_contextmenu_filter);
 
     menu.exec (m_history_list_view->mapToGlobal (xpos));
   }
@@ -223,6 +233,8 @@
   {
     m_filter_shown = ! m_filter_shown;
     m_filter_widget->setVisible (m_filter_shown);
+
+    set_filter_focus (m_filter_shown && m_filter_checkbox->isChecked ()) ;
   }
 
   void history_dock_widget::copyClipboard (void)
@@ -280,9 +292,8 @@
       (tr ("Double-click a command to transfer it to the Command Window."));
     m_history_list_view->setSelectionMode (QAbstractItemView::ExtendedSelection);
     m_history_list_view->setContextMenuPolicy (Qt::CustomContextMenu);
-    connect (m_history_list_view,
-             SIGNAL (customContextMenuRequested (const QPoint &)), this,
-             SLOT (ctxMenu (const QPoint &)));
+    connect (m_history_list_view, &QListView::customContextMenuRequested,
+             this, &history_dock_widget::ctxMenu);
 
     m_filter = new QComboBox (this);
     m_filter->setToolTip (tr ("Enter text to filter the command history"));
@@ -335,16 +346,16 @@
     filter_activate (filter_state);
 
     // Connect signals and slots
-    connect (m_filter, SIGNAL (editTextChanged (const QString&)),
+    connect (m_filter, &QComboBox::editTextChanged,
              &m_sort_filter_proxy_model,
-             SLOT (setFilterWildcard (const QString&)));
-    connect (m_filter_checkbox, SIGNAL (toggled (bool)),
-             this, SLOT (filter_activate (bool)));
-    connect (m_filter->lineEdit (), SIGNAL (editingFinished (void)),
-             this, SLOT (update_filter_history (void)));
+             &QSortFilterProxyModel::setFilterWildcard);
+    connect (m_filter_checkbox, &QCheckBox::toggled,
+             this, &history_dock_widget::filter_activate);
+    connect (m_filter->lineEdit (), &QLineEdit::editingFinished,
+             this, &history_dock_widget::update_filter_history);
 
-    connect (m_history_list_view, SIGNAL (doubleClicked (QModelIndex)),
-             this, SLOT (handle_double_click (QModelIndex)));
+    connect (m_history_list_view, &QListView::doubleClicked,
+             this, &history_dock_widget::handle_double_click);
 
     m_history_list_view->setTextElideMode (Qt::ElideRight);
   }
--- a/libgui/src/history-dock-widget.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/history-dock-widget.h	Sun May 16 09:44:35 2021 +0200
@@ -92,6 +92,7 @@
   private:
 
     void construct (void);
+    void set_filter_focus (bool focus);
 
     QListView *m_history_list_view;
     QSortFilterProxyModel m_sort_filter_proxy_model;
Binary file libgui/src/icons/bookmark-new.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/bookmark-new.svg	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,672 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   inkscape:export-ydpi="240.00000"
+   inkscape:export-xdpi="240.00000"
+   inkscape:export-filename="/home/jimmac/gfx/novell/pdes/trunk/docs/BIGmime-text.png"
+   sodipodi:docname="bookmark-new.svg"
+   sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions"
+   inkscape:version="0.46"
+   sodipodi:version="0.32"
+   id="svg249"
+   height="48.000000px"
+   width="48.000000px"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs3">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 24 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="48 : 24 : 1"
+       inkscape:persp3d-origin="24 : 16 : 1"
+       id="perspective100" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient5031"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+       cx="605.71429"
+       cy="486.64789"
+       fx="605.71429"
+       fy="486.64789"
+       r="117.14286" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient5060">
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0"
+         id="stop5062" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop5064" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5060"
+       id="radialGradient5029"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+       cx="605.71429"
+       cy="486.64789"
+       fx="605.71429"
+       fy="486.64789"
+       r="117.14286" />
+    <linearGradient
+       id="linearGradient5048">
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="0"
+         id="stop5050" />
+      <stop
+         id="stop5056"
+         offset="0.5"
+         style="stop-color:black;stop-opacity:1;" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop5052" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5048"
+       id="linearGradient5027"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
+       x1="302.85715"
+       y1="366.64789"
+       x2="302.85715"
+       y2="609.50507" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2906">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop2908" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop2910" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient2896">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop2898" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop2900" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2598">
+      <stop
+         style="stop-color:#859dbc;stop-opacity:1;"
+         offset="0"
+         id="stop2600" />
+      <stop
+         style="stop-color:#547299;stop-opacity:1;"
+         offset="1"
+         id="stop2602" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2590">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop2592" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop2594" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5897">
+      <stop
+         style="stop-color:#000000;stop-opacity:0.0000000;"
+         offset="0.0000000"
+         id="stop5899" />
+      <stop
+         id="stop5905"
+         offset="0.50000000"
+         style="stop-color:#000000;stop-opacity:0.56701028;" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0.0000000;"
+         offset="1.0000000"
+         id="stop5901" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient5866">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop5868" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop5870" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4404">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop4406" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop4408" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient4542">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop4544" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop4546" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient15662">
+      <stop
+         id="stop15664"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         id="stop15666"
+         offset="1.0000000"
+         style="stop-color:#f8f8f8;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient269">
+      <stop
+         id="stop270"
+         offset="0.0000000"
+         style="stop-color:#a3a3a3;stop-opacity:1.0000000;" />
+      <stop
+         id="stop271"
+         offset="1.0000000"
+         style="stop-color:#4c4c4c;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient259">
+      <stop
+         id="stop260"
+         offset="0.0000000"
+         style="stop-color:#fafafa;stop-opacity:1.0000000;" />
+      <stop
+         id="stop261"
+         offset="1.0000000"
+         style="stop-color:#bbbbbb;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient12512">
+      <stop
+         id="stop12513"
+         offset="0.0000000"
+         style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+      <stop
+         id="stop12517"
+         offset="0.50000000"
+         style="stop-color:#fff520;stop-opacity:0.89108908;" />
+      <stop
+         id="stop12514"
+         offset="1.0000000"
+         style="stop-color:#fff300;stop-opacity:0.0000000;" />
+    </linearGradient>
+    <radialGradient
+       r="14.375000"
+       fy="125.00000"
+       fx="55.000000"
+       cy="125.00000"
+       cx="55.000000"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient278"
+       xlink:href="#linearGradient12512"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient269"
+       id="radialGradient15656"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.968273,0.000000,0.000000,1.036374,3.250000,0.489522)"
+       cx="8.8244190"
+       cy="3.7561285"
+       fx="8.8244190"
+       fy="3.7561285"
+       r="37.751713" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient259"
+       id="radialGradient15658"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.960493,0.000000,0.000000,1.044769,-0.103553,-0.159183)"
+       cx="33.966679"
+       cy="35.736916"
+       fx="33.966679"
+       fy="35.736916"
+       r="86.708450" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient15662"
+       id="radialGradient15668"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.973033,0.000000,0.000000,1.034937,3.168754,0.555277)"
+       cx="8.1435566"
+       cy="7.2678967"
+       fx="8.1435566"
+       fy="7.2678967"
+       r="38.158695" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4542"
+       id="radialGradient4548"
+       cx="24.306795"
+       cy="42.07798"
+       fx="24.306795"
+       fy="42.07798"
+       r="15.821514"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,0.284916,0.000000,30.08928)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4404"
+       id="linearGradient4410"
+       x1="16.812500"
+       y1="1.8750000"
+       x2="16.812500"
+       y2="4.7187500"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.319549,0.000000,0.000000,1.362060,40.38853,-0.362057)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5866"
+       id="linearGradient5872"
+       x1="19.452349"
+       y1="13.174174"
+       x2="19.685436"
+       y2="27.095339"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.224255,0.000000,0.000000,1.282176,0.371569,0.264657)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5897"
+       id="linearGradient5903"
+       x1="19.000000"
+       y1="9.7738247"
+       x2="19.000000"
+       y2="15.635596"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.319549,0.000000,0.000000,2.133926,-4.476133,-14.64845)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2590"
+       id="linearGradient2596"
+       x1="19.970377"
+       y1="6.1167107"
+       x2="19.970377"
+       y2="2.53125"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.319549,0.000000,0.000000,1.280356,-5.745298,0.249007)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2598"
+       id="linearGradient2604"
+       x1="18.431311"
+       y1="19.119474"
+       x2="18.402472"
+       y2="4.2702327"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.319549,0.000000,0.000000,1.299013,-3.106200,-1.336165)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2896"
+       id="linearGradient2902"
+       x1="14.584077"
+       y1="1.6392649"
+       x2="14.552828"
+       y2="2.4912448"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,1.594214,0.000000,-0.790249)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2906"
+       id="linearGradient2912"
+       x1="13.354311"
+       y1="1.4866425"
+       x2="14.075844"
+       y2="2.4017651"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.000000,0.000000,0.000000,1.184816,0.000000,-0.727880)" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-y="158"
+     inkscape:window-x="433"
+     inkscape:window-height="690"
+     inkscape:window-width="872"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showgrid="false"
+     inkscape:current-layer="layer6"
+     inkscape:cy="16.785697"
+     inkscape:cx="-154.12746"
+     inkscape:zoom="1"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="0.25490196"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     inkscape:showpageshadow="false"
+     showguides="true"
+     inkscape:guide-bbox="true" />
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>New Bookmark</dc:title>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>bookmark</rdf:li>
+            <rdf:li>remember</rdf:li>
+            <rdf:li>favorite</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Andreas Nilsson</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source />
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+        <dc:description>create bookmark action</dc:description>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/publicdomain/">
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer6"
+     inkscape:label="Shadow">
+    <g
+       style="display:inline"
+       id="g5022"
+       transform="matrix(2.165152e-2,0,0,1.485743e-2,43.0076,42.68539)">
+      <rect
+         y="-150.69685"
+         x="-1559.2523"
+         height="478.35718"
+         width="1339.6335"
+         id="rect4173"
+         style="opacity:0.40206185;color:black;fill:url(#linearGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <path
+         sodipodi:nodetypes="cccc"
+         id="path5058"
+         d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z "
+         style="opacity:0.40206185;color:black;fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+      <path
+         style="opacity:0.40206185;color:black;fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+         d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z "
+         id="path5018"
+         sodipodi:nodetypes="cccc" />
+    </g>
+  </g>
+  <g
+     style="display:inline"
+     inkscape:groupmode="layer"
+     inkscape:label="Base"
+     id="layer1">
+    <rect
+       style="color:#000000;fill:url(#radialGradient15658);fill-opacity:1.0000000;fill-rule:nonzero;stroke:url(#radialGradient15656);stroke-width:0.99999982;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:block;overflow:visible"
+       id="rect15391"
+       width="34.875000"
+       height="41.063431"
+       x="6.5000000"
+       y="3.5000000"
+       ry="1.1490481"
+       rx="1.1490486" />
+    <rect
+       style="color:#000000;fill:none;fill-opacity:1.0000000;fill-rule:nonzero;stroke:url(#radialGradient15668);stroke-width:0.99999958;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;visibility:visible;display:block;overflow:visible"
+       id="rect15660"
+       width="32.937012"
+       height="39.028210"
+       x="7.5024552"
+       y="4.5010486"
+       ry="0.14904849"
+       rx="0.14904852" />
+    <path
+       style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.98855311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:0.017543854"
+       d="M 11.505723,5.4942766 L 11.505723,43.400869"
+       id="path15672"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:0.20467831"
+       d="M 12.500000,5.0205154 L 12.500000,43.038228"
+       id="path15674"
+       sodipodi:nodetypes="cc" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer5"
+     inkscape:label="Text"
+     style="display:inline">
+    <g
+       id="g2188">
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15686"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999994"
+         y="9.0000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15688"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999994"
+         y="11.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15690"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999994"
+         y="13.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15692"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999994"
+         y="15.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15694"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999994"
+         y="17.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15696"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999994"
+         y="19.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15698"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999994"
+         y="21.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15700"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999994"
+         y="23.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15732"
+         width="9.0000057"
+         height="1.0000000"
+         x="15.999986"
+         y="25.000000"
+         rx="0.062003858"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15736"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999986"
+         y="29.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15738"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999986"
+         y="31.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15740"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999986"
+         y="33.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15742"
+         width="20.000006"
+         height="1.0000000"
+         x="15.999986"
+         y="35.000000"
+         rx="0.13778631"
+         ry="0.065390877" />
+      <rect
+         style="color:#000000;fill:#9b9b9b;fill-opacity:0.54970759;fill-rule:nonzero;stroke:none;stroke-width:1.0000000;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:0.081871338;visibility:visible;display:block;overflow:visible"
+         id="rect15744"
+         width="14.000014"
+         height="1.0000000"
+         x="15.999986"
+         y="37.000000"
+         rx="0.096450485"
+         ry="0.065390877" />
+    </g>
+    <path
+       style="opacity:0.28021976;fill:url(#linearGradient5872);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.25pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 28.245858,31.324906 L 21.147869,27.133701 L 14.30757,30.8838 L 13.761859,3.9475667 L 28.549598,3.9475667 L 28.245858,31.324906 z "
+       id="path5138"
+       sodipodi:nodetypes="cccccc" />
+    <path
+       style="fill:url(#linearGradient2604);fill-opacity:1;fill-rule:evenodd;stroke:#364878;stroke-width:0.99999988;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+       d="M 12.427339,3.5180202 C 12.427339,3.5180202 12.240033,0.60520607 15.107867,0.54270607 L 25.119343,0.50728624 C 26.277287,0.50728624 26.581888,1.1910178 26.581888,2.1095589 L 26.581888,29.729916 L 20.545426,24.533862 L 14.674346,29.729916 L 14.591655,3.519629 L 12.427339,3.5180202 z "
+       id="path2204"
+       sodipodi:nodetypes="ccccccccc" />
+    <path
+       style="opacity:0.4450549;fill:url(#linearGradient4410);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.25pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 13.030252,3.0117919 C 13.011046,2.225362 13.312918,1.0801307 15.375418,1.0176307 L 25.027906,1 C 25.640922,1 26.090152,1.1674319 26.090152,1.7994802 L 26.060994,10.491851 L 15.317102,10.491851 L 15.192102,2.9993251 C 15.192102,2.9993251 13.030252,3.0117919 13.030252,3.0117919 z "
+       id="path3668"
+       sodipodi:nodetypes="cccccccs" />
+    <rect
+       style="opacity:0.28021976;fill:url(#linearGradient5903);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect5895"
+       width="10.556392"
+       height="12.803556"
+       x="15.317101"
+       y="6.6907959"
+       rx="0.062003858"
+       ry="0.065390877" />
+    <path
+       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2596);stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.19125683;display:inline"
+       d="M 24.476832,2.2095507 L 25.575535,3.113139 L 25.547445,27.511911 L 20.497463,23.203758 L 15.704084,27.415203 L 15.699081,2.7495618 L 24.476832,2.2095507 z "
+       id="path5969"
+       sodipodi:nodetypes="ccccccc" />
+    <path
+       sodipodi:type="arc"
+       style="color:#000000;fill:url(#radialGradient278);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block"
+       id="path12511"
+       sodipodi:cx="55"
+       sodipodi:cy="125"
+       sodipodi:rx="14.375"
+       sodipodi:ry="14.375"
+       d="M 69.375 125 A 14.375 14.375 0 1 1  40.625,125 A 14.375 14.375 0 1 1  69.375 125 z"
+       transform="matrix(0.611127,0.000000,0.000000,0.611127,5.632438,-67.28175)"
+       inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/stock_new-16.png"
+       inkscape:export-xdpi="33.852203"
+       inkscape:export-ydpi="33.852203" />
+    <path
+       style="opacity:0.48295456;color:#000000;fill:url(#linearGradient2912);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10533953;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+       d="M 15.158602,3.9384083 L 15.114407,1.0335178 C 12.983906,1.0335178 12.993087,2.9680775 12.993087,3.9384083 L 15.158602,3.9384083 z "
+       id="path2894"
+       sodipodi:nodetypes="cccc" />
+    <path
+       sodipodi:nodetypes="cccc"
+       id="path2904"
+       d="M 15.158602,3.9384086 L 15.114407,1.8247593 C 12.81631,1.8426926 12.993087,3.9384086 12.993087,3.9384086 L 15.158602,3.9384086 z "
+       style="opacity:0.35795455;color:#000000;fill:url(#linearGradient2902);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10533953;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+  </g>
+</svg>
Binary file libgui/src/icons/graphic_logo_Figure.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/icons/graphic_logo_Figure.svg	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1226 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="283.28909"
+   height="283.28833"
+   id="svg2872"
+   sodipodi:docname="graphic_logo_Figure.svg"
+   inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+   inkscape:export-filename="/home/lilge/Software/octave/dev-default/libgui/src/icons/graphic_logo_Figure.png"
+   inkscape:export-xdpi="86.752602"
+   inkscape:export-ydpi="86.752602">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1024"
+     id="namedview218"
+     showgrid="false"
+     inkscape:zoom="2.04"
+     inkscape:cx="142.78284"
+     inkscape:cy="161.252"
+     inkscape:window-x="0"
+     inkscape:window-y="30"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2872"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <metadata
+     id="metadata2942">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs2874">
+    <radialGradient
+       cx="182.9837"
+       cy="395.04871"
+       r="148.95309"
+       fx="182.9837"
+       fy="395.04871"
+       id="radialGradient3033"
+       xlink:href="#linearGradient3755"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.22914334,-0.24901479,0.7643572,0.83064268,-272.85337,-159.69482)" />
+    <linearGradient
+       id="linearGradient3755">
+      <stop
+         id="stop3757"
+         style="stop-color:#008cbe;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3759"
+         style="stop-color:#b2ffff;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="182.9837"
+       cy="395.04871"
+       r="148.95309"
+       fx="182.9837"
+       fy="395.04871"
+       id="radialGradient2996"
+       xlink:href="#linearGradient3755"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.9367132,-2.1046661,6.4603259,7.0205689,-2817.9548,-2144.284)" />
+    <linearGradient
+       id="linearGradient2994">
+      <stop
+         id="stop2996"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2998"
+         style="stop-color:#c9c9c9;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2974">
+      <stop
+         id="stop2976"
+         style="stop-color:#c1c1c1;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2978"
+         style="stop-color:#acacac;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2966">
+      <stop
+         id="stop2968"
+         style="stop-color:#ffd1d1;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3006"
+         style="stop-color:#ff1d1d;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop2970"
+         style="stop-color:#6f0000;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2846">
+      <stop
+         id="stop2848"
+         style="stop-color:#8a8a8a;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2850"
+         style="stop-color:#484848;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2366">
+      <stop
+         id="stop2368"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2374"
+         style="stop-color:#ffffff;stop-opacity:0.21904762"
+         offset="0.5" />
+      <stop
+         id="stop2370"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4467">
+      <stop
+         id="stop4469"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop4471"
+         style="stop-color:#ffffff;stop-opacity:0.24761905"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4454">
+      <stop
+         id="stop4456"
+         style="stop-color:#729fcf;stop-opacity:0.20784314"
+         offset="0" />
+      <stop
+         id="stop4458"
+         style="stop-color:#729fcf;stop-opacity:0.6761905"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4440">
+      <stop
+         id="stop4442"
+         style="stop-color:#7d7d7d;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop4448"
+         style="stop-color:#b1b1b1;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop4444"
+         style="stop-color:#686868;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="24.306795"
+       cy="42.07798"
+       r="15.821514"
+       fx="24.306795"
+       fy="42.07798"
+       id="radialGradient4548"
+       xlink:href="#linearGradient4542"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.284916,0,30.08928)" />
+    <linearGradient
+       id="linearGradient259">
+      <stop
+         id="stop260"
+         style="stop-color:#fafafa;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop261"
+         style="stop-color:#bbbbbb;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient269">
+      <stop
+         id="stop270"
+         style="stop-color:#a3a3a3;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop271"
+         style="stop-color:#4c4c4c;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="20.892099"
+       cy="114.5684"
+       r="5.256"
+       fx="20.892099"
+       fy="114.5684"
+       id="aigrd2"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         id="stop15566"
+         style="stop-color:#f0f0f0;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop15568"
+         style="stop-color:#9a9a9a;stop-opacity:1"
+         offset="1" />
+    </radialGradient>
+    <radialGradient
+       cx="20.892099"
+       cy="64.567902"
+       r="5.257"
+       fx="20.892099"
+       fy="64.567902"
+       id="aigrd3"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         id="stop15573"
+         style="stop-color:#f0f0f0;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop15575"
+         style="stop-color:#9a9a9a;stop-opacity:1"
+         offset="1" />
+    </radialGradient>
+    <linearGradient
+       id="linearGradient15662">
+      <stop
+         id="stop15664"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop15666"
+         style="stop-color:#f8f8f8;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4542">
+      <stop
+         id="stop4544"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop4546"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient5048">
+      <stop
+         id="stop5050"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0" />
+      <stop
+         id="stop5056"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop5052"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="33.966679"
+       cy="35.736916"
+       r="86.70845"
+       fx="33.966679"
+       fy="35.736916"
+       id="radialGradient3540"
+       xlink:href="#linearGradient259"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(0.960493,1.041132)" />
+    <radialGradient
+       cx="8.824419"
+       cy="3.7561285"
+       r="37.751713"
+       fx="8.824419"
+       fy="3.7561285"
+       id="radialGradient3542"
+       xlink:href="#linearGradient269"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)" />
+    <radialGradient
+       cx="8.1435566"
+       cy="7.2678967"
+       r="38.158695"
+       fx="8.1435566"
+       fy="7.2678967"
+       id="radialGradient3544"
+       xlink:href="#linearGradient15662"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)" />
+    <linearGradient
+       x1="25.71875"
+       y1="31.046875"
+       x2="25.514589"
+       y2="30.703125"
+       id="linearGradient3556"
+       xlink:href="#linearGradient2994-0"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.825542,0.125)" />
+    <radialGradient
+       cx="29.053354"
+       cy="27.640751"
+       r="3.2408545"
+       fx="29.053354"
+       fy="27.640751"
+       id="radialGradient3554"
+       xlink:href="#linearGradient2984"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.923565,0,0,2.029717,-61.55532,-27.88417)" />
+    <linearGradient
+       x1="46"
+       y1="19.8125"
+       x2="47.6875"
+       y2="22.625"
+       id="linearGradient3552"
+       xlink:href="#linearGradient2974-0"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.669292)" />
+    <linearGradient
+       x1="48.90625"
+       y1="17.376184"
+       x2="50.988335"
+       y2="22.250591"
+       id="linearGradient3550"
+       xlink:href="#linearGradient2966-9"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.669292)" />
+    <radialGradient
+       cx="20.892099"
+       cy="64.567902"
+       r="5.257"
+       fx="20.892099"
+       fy="64.567902"
+       id="radialGradient3548-0"
+       xlink:href="#aigrd3-9"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.229703,0,0,0.229703,4.613529,3.979808)" />
+    <radialGradient
+       cx="20.892099"
+       cy="114.5684"
+       r="5.256"
+       fx="20.892099"
+       fy="114.5684"
+       id="radialGradient3546-5"
+       xlink:href="#aigrd2-8"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.229703,0,0,0.229703,4.613529,3.979808)" />
+    <radialGradient
+       cx="8.1435566"
+       cy="7.2678967"
+       r="38.158695"
+       fx="8.1435566"
+       fy="7.2678967"
+       id="radialGradient3544-8"
+       xlink:href="#linearGradient15662-2"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)" />
+    <radialGradient
+       cx="8.824419"
+       cy="3.7561285"
+       r="37.751713"
+       fx="8.824419"
+       fy="3.7561285"
+       id="radialGradient3542-6"
+       xlink:href="#linearGradient269-7"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)" />
+    <radialGradient
+       cx="33.966679"
+       cy="35.736916"
+       r="86.70845"
+       fx="33.966679"
+       fy="35.736916"
+       id="radialGradient3540-4"
+       xlink:href="#linearGradient259-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(0.960493,1.041132)" />
+    <radialGradient
+       cx="20.892099"
+       cy="64.567902"
+       r="5.257"
+       fx="20.892099"
+       fy="64.567902"
+       id="radialGradient3417"
+       xlink:href="#aigrd3-9"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.229703,0,0,0.229703,4.613529,3.979808)" />
+    <radialGradient
+       cx="20.892099"
+       cy="114.5684"
+       r="5.256"
+       fx="20.892099"
+       fy="114.5684"
+       id="radialGradient3415"
+       xlink:href="#aigrd2-8"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.229703,0,0,0.229703,4.613529,3.979808)" />
+    <radialGradient
+       cx="8.1435566"
+       cy="7.2678967"
+       r="38.158695"
+       fx="8.1435566"
+       fy="7.2678967"
+       id="radialGradient3413"
+       xlink:href="#linearGradient15662-2"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)" />
+    <radialGradient
+       cx="8.824419"
+       cy="3.7561285"
+       r="37.751713"
+       fx="8.824419"
+       fy="3.7561285"
+       id="radialGradient3411"
+       xlink:href="#linearGradient269-7"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.968273,0,0,1.032767,3.353553,0.646447)" />
+    <radialGradient
+       cx="33.966679"
+       cy="35.736916"
+       r="86.70845"
+       fx="33.966679"
+       fy="35.736916"
+       id="radialGradient3409"
+       xlink:href="#linearGradient259-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(0.960493,1.041132)" />
+    <linearGradient
+       x1="25.71875"
+       y1="31.046875"
+       x2="25.514589"
+       y2="30.703125"
+       id="linearGradient3405"
+       xlink:href="#linearGradient2994-0"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.825542,0.125)" />
+    <radialGradient
+       cx="29.053354"
+       cy="27.640751"
+       r="3.2408545"
+       fx="29.053354"
+       fy="27.640751"
+       id="radialGradient3403"
+       xlink:href="#linearGradient2984"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.923565,0,0,2.029717,-61.55532,-27.88417)" />
+    <linearGradient
+       x1="46"
+       y1="19.8125"
+       x2="47.6875"
+       y2="22.625"
+       id="linearGradient3401"
+       xlink:href="#linearGradient2974-0"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.669292)" />
+    <linearGradient
+       x1="48.90625"
+       y1="17.376184"
+       x2="50.988335"
+       y2="22.250591"
+       id="linearGradient3399"
+       xlink:href="#linearGradient2966-9"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-5.669292)" />
+    <linearGradient
+       id="linearGradient5048-2">
+      <stop
+         id="stop5050-4"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0" />
+      <stop
+         id="stop5056-7"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop5052-1"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4542-3">
+      <stop
+         id="stop4544-5"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop4546-5"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient15662-2">
+      <stop
+         id="stop15664-5"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop15666-8"
+         style="stop-color:#f8f8f8;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="20.892099"
+       cy="64.567902"
+       r="5.257"
+       fx="20.892099"
+       fy="64.567902"
+       id="aigrd3-9"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         id="stop15573-3"
+         style="stop-color:#f0f0f0;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop15575-4"
+         style="stop-color:#9a9a9a;stop-opacity:1"
+         offset="1" />
+    </radialGradient>
+    <radialGradient
+       cx="20.892099"
+       cy="114.5684"
+       r="5.256"
+       fx="20.892099"
+       fy="114.5684"
+       id="aigrd2-8"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         id="stop15566-1"
+         style="stop-color:#f0f0f0;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop15568-5"
+         style="stop-color:#9a9a9a;stop-opacity:1"
+         offset="1" />
+    </radialGradient>
+    <linearGradient
+       id="linearGradient269-7">
+      <stop
+         id="stop270-6"
+         style="stop-color:#a3a3a3;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop271-9"
+         style="stop-color:#4c4c4c;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient259-5">
+      <stop
+         id="stop260-8"
+         style="stop-color:#fafafa;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop261-0"
+         style="stop-color:#bbbbbb;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="24.306795"
+       cy="42.07798"
+       r="15.821514"
+       fx="24.306795"
+       fy="42.07798"
+       id="radialGradient4548-4"
+       xlink:href="#linearGradient4542-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.284916,0,30.08928)" />
+    <linearGradient
+       id="linearGradient4440-9">
+      <stop
+         id="stop4442-2"
+         style="stop-color:#7d7d7d;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop4448-4"
+         style="stop-color:#b1b1b1;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop4444-9"
+         style="stop-color:#686868;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4454-6">
+      <stop
+         id="stop4456-3"
+         style="stop-color:#729fcf;stop-opacity:0.20784314"
+         offset="0" />
+      <stop
+         id="stop4458-2"
+         style="stop-color:#729fcf;stop-opacity:0.6761905"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4467-0">
+      <stop
+         id="stop4469-9"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop4471-9"
+         style="stop-color:#ffffff;stop-opacity:0.24761905"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2366-7">
+      <stop
+         id="stop2368-7"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2374-8"
+         style="stop-color:#ffffff;stop-opacity:0.21904762"
+         offset="0.5" />
+      <stop
+         id="stop2370-7"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2846-2">
+      <stop
+         id="stop2848-1"
+         style="stop-color:#8a8a8a;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2850-1"
+         style="stop-color:#484848;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2966-9">
+      <stop
+         id="stop2968-2"
+         style="stop-color:#ffd1d1;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3006-7"
+         style="stop-color:#ff1d1d;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop2970-1"
+         style="stop-color:#6f0000;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2974-0">
+      <stop
+         id="stop2976-3"
+         style="stop-color:#c1c1c1;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2978-3"
+         style="stop-color:#acacac;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2984">
+      <stop
+         id="stop2986"
+         style="stop-color:#e7e2b8;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2988"
+         style="stop-color:#e7e2b8;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2994-0">
+      <stop
+         id="stop2996-5"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2998-9"
+         style="stop-color:#c9c9c9;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="182.9837"
+       cy="395.04871"
+       r="148.95309"
+       fx="182.9837"
+       fy="395.04871"
+       id="radialGradient2996-4"
+       xlink:href="#linearGradient3755-2"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.22914334,-0.24901479,0.7643572,0.83064268,-272.85338,-159.69482)" />
+    <linearGradient
+       id="linearGradient3755-2">
+      <stop
+         id="stop3757-8"
+         style="stop-color:#008cbe;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3759-9"
+         style="stop-color:#b2ffff;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="182.9837"
+       cy="395.04871"
+       r="148.95309"
+       fx="182.9837"
+       fy="395.04871"
+       id="radialGradient3033-0"
+       xlink:href="#linearGradient3755-2"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.22914334,-0.24901479,0.7643572,0.83064268,-272.85337,-159.69482)" />
+    <filter
+       x="0"
+       y="0"
+       width="1"
+       height="1"
+       id="filter3683"
+       style="color-interpolation-filters:sRGB">
+      <feColorMatrix
+         values="0"
+         type="saturate"
+         id="feColorMatrix3685" />
+    </filter>
+    <filter
+       x="0"
+       y="0"
+       width="1"
+       height="1"
+       id="filter3827"
+       style="color-interpolation-filters:sRGB">
+      <feColorMatrix
+         result="result1"
+         values="0"
+         type="saturate"
+         id="feColorMatrix3829" />
+      <feFlood
+         result="result2"
+         flood-color="rgb(9,111,152)"
+         id="feFlood3831" />
+      <feBlend
+         in2="result1"
+         mode="screen"
+         result="result2"
+         id="feBlend3833" />
+      <feComposite
+         in2="SourceGraphic"
+         operator="in"
+         in="result2"
+         id="feComposite3835" />
+    </filter>
+    <radialGradient
+       cx="55"
+       cy="125"
+       r="14.375"
+       fx="55"
+       fy="125"
+       id="radialGradient1758"
+       xlink:href="#linearGradient12512"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient12512">
+      <stop
+         id="stop12513"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop12517"
+         style="stop-color:#fff520;stop-opacity:0.89108908"
+         offset="0.5" />
+      <stop
+         id="stop12514"
+         style="stop-color:#fff300;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="22.175976"
+       y1="36.987999"
+       x2="22.065331"
+       y2="32.050499"
+       id="linearGradient9772"
+       xlink:href="#linearGradient9766"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="18.112709"
+       y1="31.36775"
+       x2="15.514889"
+       y2="6.1802502"
+       id="linearGradient3104"
+       xlink:href="#linearGradient3096"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="13.035696"
+       y1="32.567184"
+       x2="12.853771"
+       y2="46.689312"
+       id="linearGradient322"
+       xlink:href="#linearGradient319"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.317489,0,0,0.816256,-0.879573,-1.318166)" />
+    <linearGradient
+       x1="6.2297964"
+       y1="13.773066"
+       x2="9.8980894"
+       y2="66.834053"
+       id="linearGradient491"
+       xlink:href="#linearGradient3983"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.516844,0,0,0.708978,-0.879573,-1.318166)" />
+    <linearGradient
+       id="linearGradient3983">
+      <stop
+         id="stop3984"
+         style="stop-color:#ffffff;stop-opacity:0.87628865"
+         offset="0" />
+      <stop
+         id="stop3985"
+         style="stop-color:#fffffe;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="20.706017"
+       cy="37.517986"
+       r="30.905205"
+       fx="20.706017"
+       fy="37.517986"
+       id="radialGradient238"
+       xlink:href="#linearGradient1789"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.055022,-0.02734504,0.177703,1.190929,-3.572177,-7.125301)" />
+    <linearGradient
+       id="linearGradient1789">
+      <stop
+         id="stop1790"
+         style="stop-color:#202020;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop1791"
+         style="stop-color:#b9b9b9;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient319">
+      <stop
+         id="stop320"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop321"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3096">
+      <stop
+         id="stop3098"
+         style="stop-color:#424242;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3100"
+         style="stop-color:#777777;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient9766">
+      <stop
+         id="stop9768"
+         style="stop-color:#6194cb;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop9770"
+         style="stop-color:#729fcf;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="302.85715"
+       y1="366.64789"
+       x2="302.85715"
+       y2="609.50507"
+       id="linearGradient5027"
+       xlink:href="#linearGradient5048-8"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" />
+    <linearGradient
+       id="linearGradient5048-8">
+      <stop
+         id="stop5050-5"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0" />
+      <stop
+         id="stop5056-5"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop5052-2"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="605.71429"
+       cy="486.64789"
+       r="117.14286"
+       fx="605.71429"
+       fy="486.64789"
+       id="radialGradient5029"
+       xlink:href="#linearGradient5060"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" />
+    <linearGradient
+       id="linearGradient5060">
+      <stop
+         id="stop5062"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop5064"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="605.71429"
+       cy="486.64789"
+       r="117.14286"
+       fx="605.71429"
+       fy="486.64789"
+       id="radialGradient5031"
+       xlink:href="#linearGradient5060"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" />
+    <filter
+       x="0"
+       y="0"
+       width="1"
+       height="1"
+       id="filter3827-2"
+       style="color-interpolation-filters:sRGB">
+      <feColorMatrix
+         result="result1"
+         values="0"
+         type="saturate"
+         id="feColorMatrix3829-1" />
+      <feFlood
+         result="result2"
+         flood-color="rgb(9,111,152)"
+         id="feFlood3831-3" />
+      <feBlend
+         in2="result1"
+         mode="screen"
+         result="result2"
+         id="feBlend3833-2" />
+      <feComposite
+         in2="SourceGraphic"
+         operator="in"
+         in="result2"
+         id="feComposite3835-8" />
+    </filter>
+    <filter
+       x="0"
+       y="0"
+       width="1"
+       height="1"
+       id="filter3827-6"
+       style="color-interpolation-filters:sRGB">
+      <feColorMatrix
+         result="result1"
+         values="0"
+         type="saturate"
+         id="feColorMatrix3829-7" />
+      <feFlood
+         result="result2"
+         flood-color="rgb(9,111,152)"
+         id="feFlood3831-1" />
+      <feBlend
+         in2="result1"
+         mode="screen"
+         result="result2"
+         id="feBlend3833-9" />
+      <feComposite
+         in2="SourceGraphic"
+         operator="in"
+         in="result2"
+         id="feComposite3835-3" />
+    </filter>
+    <linearGradient
+       x1="174.83363"
+       y1="84.263489"
+       x2="174.74524"
+       y2="105.49083"
+       id="linearGradient3979"
+       xlink:href="#linearGradient2817"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.2553876,0,0,0.60128935,-385.70745,-46.744834)" />
+    <linearGradient
+       id="linearGradient2817">
+      <stop
+         id="stop2819"
+         style="stop-color:#729fcf;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2821"
+         style="stop-color:#ffffff;stop-opacity:0.48453608"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="143.31842"
+       cy="108.89388"
+       r="11"
+       fx="143.31842"
+       fy="108.89388"
+       id="radialGradient3938-5"
+       xlink:href="#linearGradient4391"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.09090829,-2.0909091,2.5430488,-0.11063222,-242.64984,363.89573)" />
+    <linearGradient
+       id="linearGradient4391">
+      <stop
+         offset="0"
+         style="stop-color:#b3cce5;stop-opacity:1"
+         id="stop4393" />
+      <stop
+         offset="1"
+         style="stop-color:#f6f7f5;stop-opacity:1"
+         id="stop4395" />
+    </linearGradient>
+    <linearGradient
+       xlink:href="#linearGradient2697"
+       id="linearGradient4387"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.1474179,0,0,0.57248618,-366.76727,-43.981034)"
+       x1="169"
+       y1="110.33805"
+       x2="169"
+       y2="93.204849" />
+    <linearGradient
+       id="linearGradient2697">
+      <stop
+         id="stop2699"
+         style="stop-color:#729fcf;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2701"
+         style="stop-color:#3d556f;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       xlink:href="#linearGradient319"
+       id="linearGradient4389"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.5782224,0,0,0.56998736,-68.52461,-3.3020389)"
+       x1="24.674307"
+       y1="44.50301"
+       x2="24.674307"
+       y2="98.890182" />
+  </defs>
+  <path
+     inkscape:connector-curvature="0"
+     style="fill:url(#radialGradient2996);fill-opacity:1;stroke:none;stroke-width:8.45197201"
+     id="path5874"
+     d="M 49.676747,29.423848 C 5.7616507,77.147343 16.404628,166.08407 73.435833,228.06103 130.46703,290.03807 212.29311,301.58938 256.20826,253.86591 300.12344,206.14244 289.51072,117.20208 232.47947,55.225124 175.44826,-6.7520309 93.591927,-18.299707 49.676747,29.423848 Z M 89.49813,49.248202 c 34.50568,-37.497936 97.9499,-29.341191 141.71768,18.22214 43.76783,47.563478 51.2736,116.509678 16.76792,154.007608 -34.50565,37.49786 -97.96652,29.35954 -141.73439,-18.20394 C 62.481485,155.71054 54.992446,86.746332 89.49813,49.248202 Z" />
+  <rect
+     width="4.349854"
+     height="4.349854"
+     rx="0.76958966"
+     ry="0.76958966"
+     x="85.381561"
+     y="99.493881"
+     transform="matrix(8.4519724,0,0,8.4519724,-511.80557,-794.54775)"
+     id="rect5876"
+     style="fill:#ff7f2a;fill-opacity:1;fill-rule:nonzero;stroke:#d45500;stroke-width:0.74403799;stroke-miterlimit:4;stroke-dasharray:none;filter:url(#filter3827)" />
+  <rect
+     width="34.875"
+     height="40.920494"
+     rx="1.1449448"
+     ry="1.1468204"
+     x="6.6035528"
+     y="3.6464462"
+     transform="matrix(5.1226198,0,0,5.1142435,66.188968,-14.496546)"
+     id="rect15391"
+     style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#radialGradient3540);fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient3542);stroke-width:0.99724436;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;filter:url(#filter3827)" />
+  <rect
+     width="32.775887"
+     height="38.946384"
+     rx="0.14851625"
+     ry="0.14875954"
+     x="7.6660538"
+     y="4.5839462"
+     transform="matrix(5.1226198,0,0,5.1142435,66.188968,-14.496546)"
+     id="rect15660"
+     style="color:#000000;display:block;overflow:visible;visibility:visible;fill:none;stroke:url(#radialGradient3544);stroke-width:0.99724436;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;filter:url(#filter3827)" />
+  <text
+     x="148.18649"
+     y="64.117371"
+     id="text3260"
+     xml:space="preserve"
+     style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:24px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter3827)"><tspan
+       x="148.18649"
+       y="64.117371"
+       id="tspan3262"
+       style="font-weight:bold;font-size:32px;-inkscape-font-specification:'Sans Bold'" /></text>
+  <rect
+     style="fill:#ff7f2a;fill-opacity:1;fill-rule:nonzero;stroke:#d45500;stroke-width:6.28858852;stroke-miterlimit:4;stroke-dasharray:none"
+     id="rect5878"
+     y="94.806831"
+     x="3.1442943"
+     ry="15.320505"
+     rx="15.320505"
+     height="86.594139"
+     width="86.594139" />
+  <rect
+     style="fill:#ff7f2a;fill-opacity:1;fill-rule:nonzero;stroke:#d45500;stroke-width:6.28858852;stroke-miterlimit:4;stroke-dasharray:none"
+     id="rect5880"
+     y="208.16928"
+     x="226.93687"
+     ry="9.2558413"
+     rx="9.2558413"
+     height="52.31562"
+     width="52.31562" />
+  <path
+     style="fill:none;stroke:#43b7d6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.75294118"
+     d="m 119.10397,28.486379 c 143.65725,-0.51811 143.65725,-0.51811 143.65725,-0.51811"
+     id="path1187"
+     inkscape:connector-curvature="0" />
+  <use
+     x="0"
+     y="0"
+     xlink:href="#path1187"
+     id="use1189"
+     transform="translate(0,42)"
+     width="100%"
+     height="100%" />
+  <use
+     x="0"
+     y="0"
+     xlink:href="#use1189"
+     id="use1191"
+     transform="translate(0,40)"
+     width="100%"
+     height="100%" />
+  <use
+     x="0"
+     y="0"
+     xlink:href="#use1191"
+     id="use1193"
+     transform="translate(0,38)"
+     width="100%"
+     height="100%" />
+  <use
+     x="0"
+     y="0"
+     xlink:href="#use1193"
+     id="use1195"
+     transform="translate(0,42)"
+     width="100%"
+     height="100%" />
+  <path
+     style="fill:none;stroke:#42b6d6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.75294118"
+     d="m 119.10397,28.486379 c 0,160.000001 0,162.453661 0,162.453661"
+     id="path1199"
+     inkscape:connector-curvature="0" />
+  <use
+     x="0"
+     y="0"
+     xlink:href="#path1199"
+     id="use1201"
+     transform="translate(48)"
+     width="100%"
+     height="100%" />
+  <use
+     x="0"
+     y="0"
+     xlink:href="#use1201"
+     id="use1203"
+     transform="translate(48)"
+     width="100%"
+     height="100%" />
+  <use
+     x="0"
+     y="0"
+     xlink:href="#use1203"
+     id="use1205"
+     transform="translate(48)"
+     width="100%"
+     height="100%" />
+  <path
+     inkscape:connector-curvature="0"
+     d="m 253.70314,122.99143 c 0,0 -37.8439,33.69118 -61.56862,38.39216 -22.07101,4.37329 -66.56863,-11.17648 -66.56863,-11.17648"
+     id="path4307"
+     style="color:#000000;display:block;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#0690c0;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+     sodipodi:nodetypes="cac" />
+  <path
+     inkscape:connector-curvature="0"
+     style="color:#000000;display:block;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ff7f2a;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+     id="path1432"
+     d="m 253.68355,43.834571 c 0,0 -26.93417,36.533276 -44.67349,50.217805 -12.18881,9.402734 -26.48873,16.290374 -41.16667,20.931134 -13.57364,4.29161 -20.09338,5.25588 -42.27749,6.04713"
+     sodipodi:nodetypes="caac" />
+</svg>
--- a/libgui/src/icons/icons_license	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/icons/icons_license	Sun May 16 09:44:35 2021 +0200
@@ -17,6 +17,7 @@
 ===========================================
 
 applications-system.svg
+bookmark-new.svg
 dialog-error.svg
 dialog-information.svg
 dialog-warning.svg
@@ -54,7 +55,6 @@
 
 ===========================================
 Icons created by the Octave developers
-with elements from the Tango theme
 ===========================================
 
 figure-axes.svg
@@ -69,6 +69,7 @@
 
 figure-pan.svg
 graphic_logo_DocumentationDockWidget.svg
+graphic_logo_Figure.svg
 graphic_logo_FileEditor.svg
 graphic_logo_FilesDockWidget.svg
 graphic_logo_HistoryDockWidget.svg
--- a/libgui/src/interpreter-qobject.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/interpreter-qobject.cc	Sun May 16 09:44:35 2021 +0200
@@ -53,8 +53,12 @@
     event_manager& evmgr = interp.get_event_manager ();
 
     evmgr.connect_link (m_octave_qobj.get_qt_interpreter_events ());
+    evmgr.install_qt_event_handlers (m_octave_qobj.get_qt_interpreter_events ());
     evmgr.enable ();
 
+    connect (this, &interpreter_qobject::ready,
+             &m_octave_qobj, &base_qobject::interpreter_ready);
+
     int exit_status = 0;
 
     try
@@ -63,7 +67,8 @@
 
         interp.initialize ();
 
-        if (app_context.start_gui_p ())
+        if (app_context.start_gui_p ()
+            && ! m_octave_qobj.experimental_terminal_widget ())
           {
             input_system& input_sys = interp.get_input_system ();
 
@@ -87,34 +92,23 @@
             exit_status = interp.execute ();
           }
       }
-    catch (const exit_exception& ex)
+    catch (const exit_exception& xe)
       {
-        exit_status = ex.exit_status ();
+        exit_status = xe.exit_status ();
       }
 
-    // Signal that the interpreter is done executing code in the main
-    // REPL, from script files, or command line eval arguments.  By
-    // using a signal here, we give the GUI a chance to process any
-    // pending events, then signal that it is safe to shutdown the
-    // interpreter.  Our notification here allows the GUI to insert the
-    // request to shutdown the interpreter in the event queue after any
-    // other pending signals.  The application context owns the
-    // interpreter and will be responsible for deleting it later, when
-    // the application object destructor is executed.
+    interp.shutdown ();
 
-    emit execution_finished (exit_status);
-  }
-
-  // This function is expected to be executed when the GUI signals that
-  // it is finished processing events and ready for the interpreter to
-  // perform shutdown actions.
-
-  void interpreter_qobject::shutdown (int exit_status)
-  {
-    if (m_interpreter)
-      m_interpreter->shutdown ();
-
-    // Signal that the interpreter has executed shutdown actions.
+    // Signal that the interpreter is done executing code in the
+    // main REPL, from script files, or command line eval arguments.
+    // By using a signal here, we give the GUI a chance to process
+    // any pending events, then signal that it is safe to shutdown
+    // the interpreter.  Our notification here allows the GUI to
+    // insert the request to shutdown the interpreter in the event
+    // queue after any other pending signals.  The application
+    // context owns the interpreter and will be responsible for
+    // deleting it later, when the application object destructor is
+    // executed.
 
     emit shutdown_finished (exit_status);
   }
@@ -139,6 +133,71 @@
     evmgr.post_event (meth);
   }
 
+  void interpreter_qobject::interrupt (void)
+  {
+    if (! m_interpreter)
+      return;
+
+    // The following is a direct function call across threads.
+    // We need to ensure that it uses thread-safe functions.
+
+    m_interpreter->interrupt ();
+  }
+
+  void interpreter_qobject::pause (void)
+  {
+    // FIXME: Should we make this action work with the old terminal
+    // widget?
+
+    if (m_octave_qobj.experimental_terminal_widget ())
+      {
+        if (! m_interpreter)
+          return;
+
+        // The following is a direct function call across threads.
+        // We need to ensure that it uses thread-safe functions.
+
+        m_interpreter->pause ();
+      }
+  }
+
+  void interpreter_qobject::stop (void)
+  {
+    // FIXME: Should we make this action work with the old terminal
+    // widget?
+
+    if (m_octave_qobj.experimental_terminal_widget ())
+      {
+        if (! m_interpreter)
+          return;
+
+        // The following is a direct function call across threads.
+        // We need to ensure that it uses thread-safe functions.
+
+        m_interpreter->stop ();
+      }
+  }
+
+  void interpreter_qobject::resume (void)
+  {
+    // FIXME: Should we make this action work with the old terminal
+    // widget?
+
+    if (m_octave_qobj.experimental_terminal_widget ())
+      {
+        // FIXME: This action should only be available when the
+        // interpreter is paused.
+
+        interpreter_event
+          ([=] (interpreter& interp)
+          {
+            // INTERPRETER THREAD
+
+            interp.resume ();
+          });
+      }
+  }
+
   qt_interpreter_events * interpreter_qobject::qt_link (void)
   {
     return m_octave_qobj.qt_link ();
--- a/libgui/src/interpreter-qobject.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/interpreter-qobject.h	Sun May 16 09:44:35 2021 +0200
@@ -52,12 +52,18 @@
 
     void interpreter_event (const meth_callback& meth);
 
+    void interrupt (void);
+
+    // Note: PAUSE, STOP, and RESUME are currently only used by the new
+    // experimental terminal widget.
+    void pause (void);
+    void stop (void);
+    void resume (void);
+
   signals:
 
     void ready (void);
 
-    void execution_finished (int);
-
     void shutdown_finished (int);
 
   public slots:
@@ -84,8 +90,6 @@
 
     void execute (void);
 
-    void shutdown (int);
-
   private:
 
     base_qobject& m_octave_qobj;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/led-indicator.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,79 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2013-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <QColor>
+
+#include "gui-utils.h"
+#include "led-indicator.h"
+
+namespace octave
+{
+
+  led_indicator::led_indicator (led_state initial_state, QWidget *p)
+    : QLabel (p)
+  {
+    setFixedSize(12,12);
+    set_state (initial_state);
+  }
+
+  void led_indicator::set_state (led_state state)
+  {
+    QColor col (Qt::gray);
+
+    switch (state)
+      {
+        case LED_STATE_NO:
+          break;
+
+        case LED_STATE_INACTIVE:
+          col = QColor (Qt::darkRed);
+          break;
+
+        case LED_STATE_ACTIVE:
+          col = QColor (Qt::darkGreen);
+          break;
+      }
+
+    setStyleSheet (style_sheet (col));
+  }
+
+  QString led_indicator::style_sheet (const QColor& col)
+  {
+    QColor col_light = interpolate_color (col, QColor (Qt::white), 0.25, 0.9);
+
+    const QString style = QString (
+        "border-radius: %1; background-color: "
+        "qlineargradient(spread:pad, x1:0.2, y1:0.2, x2:1, y2:1, stop:0 "
+        "%2, stop:1 %3);"
+      ).arg (width ()/2).arg (col_light.name ()).arg (col.name ());
+
+    return style;
+  }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/led-indicator.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,61 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2013-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (led_indicator_h)
+#define led_indicator_h 1
+
+#include <QLabel>
+
+namespace octave
+{
+
+  class led_indicator: public QLabel
+  {
+    Q_OBJECT
+
+  public:
+
+    enum led_state
+    {
+      LED_STATE_NO = -1,
+      LED_STATE_INACTIVE,
+      LED_STATE_ACTIVE
+    };
+
+    led_indicator (led_state initial_state = LED_STATE_INACTIVE,
+                   QWidget *parent = 0);
+
+  public slots:
+
+    void set_state (led_state state);
+
+  private:
+
+    QString style_sheet (const QColor& col);
+
+  };
+}
+
+#endif
\ No newline at end of file
--- a/libgui/src/m-editor/file-editor-interface.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/m-editor/file-editor-interface.h	Sun May 16 09:44:35 2021 +0200
@@ -27,6 +27,7 @@
 #define octave_file_editor_interface_h 1
 
 #include <QMenu>
+#include <QMenuBar>
 #include <QToolBar>
 
 #include "gui-settings.h"
@@ -51,6 +52,7 @@
     virtual QMenu * get_mru_menu (void) = 0;
     virtual QMenu * debug_menu (void) = 0;
     virtual QToolBar * toolbar (void) = 0;
+    virtual QMenuBar * menubar (void) = 0;
 
     virtual void insert_global_actions (QList<QAction*>) = 0;
     virtual void handle_enter_debug_mode (void) = 0;
--- a/libgui/src/m-editor/file-editor-tab.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/m-editor/file-editor-tab.cc	Sun May 16 09:44:35 2021 +0200
@@ -44,6 +44,7 @@
 #include <QMessageBox>
 #include <QPrintDialog>
 #include <QPushButton>
+#include <QScrollBar>
 #include <QStyle>
 #include <QTextBlock>
 #include <QTextCodec>
@@ -59,6 +60,7 @@
 #include <Qsci/qscilexerbash.h>
 #include <Qsci/qscilexerbatch.h>
 #include <Qsci/qscilexercpp.h>
+#include <Qsci/qscilexerjava.h>
 #include <Qsci/qscilexerdiff.h>
 #include <Qsci/qscilexerperl.h>
 #include <Qsci/qsciprinter.h>
@@ -68,8 +70,10 @@
 #include "gui-preferences-cs.h"
 #include "gui-preferences-ed.h"
 #include "gui-preferences-global.h"
+#include "gui-utils.h"
 #include "marker.h"
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 #include "octave-txt-lexer.h"
 
 #include "cmd-edit.h"
@@ -127,20 +131,20 @@
     // Initialize last modification date to now
     m_last_modified = QDateTime::currentDateTimeUtc();
 
-    connect (m_edit_area, SIGNAL (cursorPositionChanged (int, int)),
-             this, SLOT (handle_cursor_moved (int,int)));
-
-    connect (m_edit_area, SIGNAL (SCN_CHARADDED (int)),
-             this, SLOT (handle_char_added (int)));
-
-    connect (m_edit_area, SIGNAL (SCN_DOUBLECLICK (int, int, int)),
-             this, SLOT (handle_double_click (int, int, int)));
-
-    connect (m_edit_area, SIGNAL (linesChanged ()),
-             this, SLOT (handle_lines_changed ()));
-
-    connect (m_edit_area, SIGNAL (context_menu_edit_signal (const QString&)),
-             this, SLOT (handle_context_menu_edit (const QString&)));
+    connect (m_edit_area, &octave_qscintilla::cursorPositionChanged,
+             this, &file_editor_tab::handle_cursor_moved);
+
+    connect (m_edit_area, &octave_qscintilla::SCN_CHARADDED,
+             this, &file_editor_tab::handle_char_added);
+
+    connect (m_edit_area, &octave_qscintilla::SCN_DOUBLECLICK,
+             this, &file_editor_tab::handle_double_click);
+
+    connect (m_edit_area, &octave_qscintilla::linesChanged,
+             this, &file_editor_tab::handle_lines_changed);
+
+    connect (m_edit_area, &octave_qscintilla::context_menu_edit_signal,
+             this, &file_editor_tab::handle_context_menu_edit);
 
     // create statusbar for row/col indicator and eol mode
     m_status_bar = new QStatusBar (this);
@@ -190,13 +194,11 @@
     m_edit_area->setMarkerBackgroundColor (QColor (192,192,192),
                                            marker::unsure_debugger_position);
 
-    connect (m_edit_area, SIGNAL (marginClicked (int, int,
-                                  Qt::KeyboardModifiers)),
-             this, SLOT (handle_margin_clicked (int, int,
-                                                Qt::KeyboardModifiers)));
-
-    connect (m_edit_area, SIGNAL (context_menu_break_condition_signal (int)),
-             this, SLOT (handle_context_menu_break_condition (int)));
+    connect (m_edit_area, &octave_qscintilla::marginClicked,
+             this, &file_editor_tab::handle_margin_clicked);
+
+    connect (m_edit_area, &octave_qscintilla::context_menu_break_condition_signal,
+             this, &file_editor_tab::handle_context_menu_break_condition);
 
     // line numbers
     m_edit_area->setMarginsForegroundColor (QColor (96, 96, 96));
@@ -224,40 +226,39 @@
     // Any interpreter_event signal from a file_editor_tab_widget is
     // handled the same as for the parent main_window object.
 
-    connect (m_edit_area, SIGNAL (interpreter_event (const fcn_callback&)),
-             this, SIGNAL (interpreter_event (const fcn_callback&)));
-
-    connect (m_edit_area, SIGNAL (interpreter_event (const meth_callback&)),
-             this, SIGNAL (interpreter_event (const meth_callback&)));
+    connect (m_edit_area, QOverload<const fcn_callback&>::of (&octave_qscintilla::interpreter_event),
+             this, QOverload<const fcn_callback&>::of (&file_editor_tab::interpreter_event));
+
+    connect (m_edit_area, QOverload<const meth_callback&>::of (&octave_qscintilla::interpreter_event),
+             this, QOverload<const meth_callback&>::of (&file_editor_tab::interpreter_event));
 
     // connect modified signal
-    connect (m_edit_area, SIGNAL (modificationChanged (bool)),
-             this, SLOT (update_window_title (bool)));
-
-    connect (m_edit_area, SIGNAL (copyAvailable (bool)),
-             this, SLOT (handle_copy_available (bool)));
-
-    connect (&m_file_system_watcher, SIGNAL (fileChanged (const QString&)),
-             this, SLOT (file_has_changed (const QString&)));
-
-    connect (this, SIGNAL (maybe_remove_next (int)),
-             this, SLOT (handle_remove_next (int)));
-
-    connect (this, SIGNAL (dbstop_if (const QString&, int, const QString&)),
-             this,
-             SLOT (handle_dbstop_if (const QString&, int, const QString&)));
-
-    connect (this, SIGNAL (request_add_breakpoint (int, const QString&)),
-             this, SLOT (handle_request_add_breakpoint (int, const QString&)));
-
-    connect (this, SIGNAL (api_entries_added (void)),
-             this, SLOT (handle_api_entries_added (void)));
-
-    connect (this, SIGNAL (confirm_dbquit_and_save_signal (const QString&, const QString&, bool, bool)),
-             this, SLOT (confirm_dbquit_and_save (const QString&, const QString&, bool, bool)));
-
-    connect (this, SIGNAL (do_save_file_signal (const QString&, bool, bool)),
-             this, SLOT (do_save_file (const QString&, bool, bool)));
+    connect (m_edit_area, &octave_qscintilla::modificationChanged,
+             this, &file_editor_tab::update_window_title);
+
+    connect (m_edit_area, &octave_qscintilla::copyAvailable,
+             this, &file_editor_tab::handle_copy_available);
+
+    connect (&m_file_system_watcher, &QFileSystemWatcher::fileChanged,
+             this, [=] (const QString& path) { file_has_changed (path); });
+
+    connect (this, &file_editor_tab::maybe_remove_next,
+             this, &file_editor_tab::handle_remove_next);
+
+    connect (this, &file_editor_tab::dbstop_if,
+             this, &file_editor_tab::handle_dbstop_if);
+
+    connect (this, &file_editor_tab::request_add_breakpoint,
+             this, &file_editor_tab::handle_request_add_breakpoint);
+
+    connect (this, &file_editor_tab::api_entries_added,
+             this, &file_editor_tab::handle_api_entries_added);
+
+    connect (this, &file_editor_tab::confirm_dbquit_and_save_signal,
+             this, &file_editor_tab::confirm_dbquit_and_save);
+
+    connect (this, &file_editor_tab::do_save_file_signal,
+             this, &file_editor_tab::do_save_file);
 
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
     gui_settings *settings = rmgr.get_settings ();
@@ -265,10 +266,7 @@
       notice_settings (settings, true);
 
     // encoding, not updated with the settings
-    QString locale_enc_name =
-      QString ("SYSTEM (") +
-      QString (octave_locale_charset_wrapper ()).toUpper () + QString (")");
-    m_encoding = settings->value (ed_default_enc.key, locale_enc_name).toString ();
+    m_encoding = settings->value (ed_default_enc.key, "UTF-8").toString ();
     m_enc_indicator->setText (m_encoding);
     // no changes in encoding yet
     m_new_encoding = m_encoding;
@@ -277,7 +275,7 @@
   file_editor_tab::~file_editor_tab (void)
   {
     // Tell all connected markers to self-destruct.
-    emit remove_all_breakpoints ();
+    emit remove_all_breakpoints_signal ();
     emit remove_all_positions ();
 
     // Destroy lexer attached to m_edit_area, which is not the parent
@@ -428,7 +426,7 @@
     if (ok && ! new_cond.isEmpty ())
       {
         emit interpreter_event
-          ([this, line, new_cond] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -456,11 +454,11 @@
 
                  emit request_add_breakpoint (line, new_cond);
                }
-             catch (const execution_exception& e)
+             catch (const execution_exception& ee)
                {
                  interp.recover_from_exception ();
 
-                 msg = e.message ();
+                 msg = ee.message ();
                  eval_error = true;
                }
              catch (const interrupt_exception&)
@@ -617,6 +615,10 @@
           {
             lexer = new QsciLexerCPP ();
           }
+        else if (m_file_name.endsWith (".java"))
+          {
+            lexer = new QsciLexerJava ();
+          }
         else if (m_file_name.endsWith (".pl"))
           {
             lexer = new QsciLexerPerl ();
@@ -669,8 +671,8 @@
         // Build information for auto completion (APIs)
         m_lexer_apis = new QsciAPIs (lexer);
 
-        connect (this, SIGNAL (request_add_octave_apis (const QStringList&)),
-                 this, SLOT (handle_add_octave_apis (const QStringList&)));
+        connect (this, &file_editor_tab::request_add_octave_apis,
+                 this, &file_editor_tab::handle_add_octave_apis);
 
         // Get the settings for this new lexer
         update_lexer_settings ();
@@ -685,8 +687,11 @@
 
 
   // Update settings, which are lexer related and have to be updated
-  // when a) the lexer changes or b) the settings have changed.
-  void file_editor_tab::update_lexer_settings (void)
+  // when
+  //    a) the lexer changes,
+  //    b) the settings have changed, or
+  //    c) a package was loaded/unloaded
+  void file_editor_tab::update_lexer_settings (bool update_apis_only)
   {
     QsciLexer *lexer = m_edit_area->lexer ();
 
@@ -757,7 +762,8 @@
                 // if the file is older than a few minutes preventing from
                 // re-preparing data when the user opens several files.
                 QDateTime apis_time = apis_file.lastModified ();
-                if (QDateTime::currentDateTime () > apis_time.addSecs (180))
+                if (update_apis_only
+                    || QDateTime::currentDateTime () > apis_time.addSecs (180))
                   update_apis = true;
               }
 
@@ -789,10 +795,12 @@
 
             // create raw apis info
 
+            m_lexer_apis->clear (); // Clear current contents
+
             if (m_is_octave_file)
               {
                 emit interpreter_event
-                  ([this, octave_functions, octave_builtins] (interpreter& interp)
+                  ([=] (interpreter& interp)
                    {
                      // INTERPRETER THREAD
 
@@ -854,7 +862,11 @@
           }
       }
 
-    lexer->readSettings (*settings);
+    if (update_apis_only)
+      return;   // We are done here
+
+    int mode = settings->value (ed_color_mode).toInt ();
+    rmgr.read_lexer_settings (lexer, settings, mode);
 
     m_edit_area->setCaretForegroundColor (lexer->color (0));
     m_edit_area->setIndentationGuidesForegroundColor (lexer->color (0));
@@ -863,27 +875,22 @@
     QColor bg = lexer->paper (0);
     QColor fg = lexer->color (0);
 
-    int bh, bs, bv, fh, fs, fv, h, s, v;
-    bg.getHsv (&bh,&bs,&bv);
-    fg.getHsv (&fh,&fs,&fv);
-
-    // margin colors
-    h = bh;
-    s = bs/2;
-    v = bv + (fv - bv)/5;
-
-    bg.setHsv (h,s,v);
-    m_edit_area->setEdgeColor (bg);
-
-    v = bv + (fv - bv)/8;
-    bg.setHsv (h,s,v);
-    v = bv + (fv - bv)/4;
-    fg.setHsv (h,s,v);
+    // margin and current line marker colors
+    QColor bgm, fgm;
+
+    bgm = interpolate_color (bg, fg, 0.5, 0.2);
+    m_edit_area->setEdgeColor (bgm);
 
     m_edit_area->setMarkerForegroundColor (lexer->color (0));
     m_edit_area->setMarginsForegroundColor (lexer->color (0));
-    m_edit_area->setMarginsBackgroundColor (bg);
-    m_edit_area->setFoldMarginColors (bg,fg);
+
+    bgm = interpolate_color (bg, fg, 0.5, 0.125);
+    fgm = interpolate_color (bg, fg, 0.5, 0.25);
+    m_edit_area->setMarginsBackgroundColor (bgm);
+    m_edit_area->setFoldMarginColors (bgm, fgm);
+
+    bgm = interpolate_color (bg, fg, 0.5, 0.1);
+    m_edit_area->setCaretLineBackgroundColor (bgm);
 
     // color indicator for highlighting all occurrences:
     // applications highlight color with more transparency
@@ -924,15 +931,15 @@
   void file_editor_tab::handle_api_entries_added (void)
   {
     // disconnect slot for saving prepared info if already connected
-    disconnect (m_lexer_apis, SIGNAL (apiPreparationFinished ()),
+    disconnect (m_lexer_apis, &QsciAPIs::apiPreparationFinished,
                 nullptr, nullptr);
 
     // check whether path for prepared info exists or can be created
     if (QDir ("/").mkpath (m_prep_apis_path))
       {
         // path exists, apis info can be saved there
-        connect (m_lexer_apis, SIGNAL (apiPreparationFinished ()),
-                 this, SLOT (save_apis_info ()));
+        connect (m_lexer_apis, &QsciAPIs::apiPreparationFinished,
+                 this, &file_editor_tab::save_apis_info);
       }
 
     m_lexer_apis->prepare ();  // prepare apis info
@@ -1117,67 +1124,27 @@
     m_edit_area->markerDeleteAll (marker::bookmark);
   }
 
-  file_editor_tab::bp_info::bp_info (const QString& fname, int l,
-                                     const QString& cond)
-    : line (l), file (fname.toStdString ()), condition (cond.toStdString ())
+  void
+  file_editor_tab::handle_request_add_breakpoint (int line,
+                                                  const QString& condition)
   {
-    QFileInfo file_info (fname);
-
-    QString q_dir = file_info.absolutePath ();
-    QString q_function_name = file_info.fileName ();
-
-    // We have to cut off the suffix, because octave appends it.
-    q_function_name.chop (file_info.suffix ().length () + 1);
-
-    dir = q_dir.toStdString ();
-    function_name = q_function_name.toStdString ();
-
-    // Is the last component of DIR @foo?  If so, strip it and prepend it
-    // to the name of the function.
-
-    std::size_t pos = dir.rfind (sys::file_ops::dir_sep_chars ());
-
-    if (pos != std::string::npos && pos < dir.length () - 1)
-      {
-        if (dir[pos+1] == '@')
-          {
-            function_name = sys::file_ops::concat (dir.substr (pos+1), function_name);
-
-            dir = dir.substr (0, pos);
-          }
-      }
-  }
-
-  void file_editor_tab::handle_request_add_breakpoint (int line,
-                                                       const QString& condition)
-  {
-    bp_info info (m_file_name, line, condition);
-
-    add_breakpoint_event (info);
+    if (! m_is_octave_file)
+      return;
+
+    add_breakpoint_event (line, condition);
   }
 
   void file_editor_tab::handle_request_remove_breakpoint (int line)
   {
-    bp_info info (m_file_name, line);
-
     emit interpreter_event
-      ([info] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         load_path& lp = interp.get_load_path ();
-
-         bp_table::intmap line_info;
-         line_info[0] = info.line;
-
-         if (lp.contains_file_in_dir (info.file, info.dir))
-           {
-             tree_evaluator& tw = interp.get_evaluator ();
-
-             bp_table& bptab = tw.get_bp_table ();
-
-             bptab.remove_breakpoint (info.function_name, line_info);
-           }
+         tree_evaluator& tw = interp.get_evaluator ();
+         bp_table& bptab = tw.get_bp_table ();
+
+         bptab.remove_breakpoint_from_file (m_file_name.toStdString (), line);
        });
   }
 
@@ -1247,23 +1214,16 @@
     if (ID != this)
       return;
 
-    bp_info info (m_file_name);
-
     emit interpreter_event
-      ([info] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
-         load_path& lp = interp.get_load_path ();
-
-         if (lp.contains_file_in_dir (info.file, info.dir))
-           {
-             tree_evaluator& tw = interp.get_evaluator ();
-
-             bp_table& bptab = tw.get_bp_table ();
-
-             bptab.remove_all_breakpoints_in_file (info.function_name, true);
-           }
+         tree_evaluator& tw = interp.get_evaluator ();
+         bp_table& bptab = tw.get_bp_table ();
+
+         bptab.remove_all_breakpoints_from_file (m_file_name.toStdString (),
+                                                 true);
        });
   }
 
@@ -1355,40 +1315,24 @@
     auto_margin_width ();
   }
 
-  void file_editor_tab::add_breakpoint_event (const bp_info& info)
+  void file_editor_tab::add_breakpoint_event (int line, const QString& cond)
   {
     emit interpreter_event
-      ([this, info] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
          // FIXME: note duplication with the code in
          // handle_context_menu_break_condition.
 
-         load_path& lp = interp.get_load_path ();
-
-         bp_table::intmap line_info;
-         line_info[0] = info.line;
-
-         if (lp.contains_file_in_dir (info.file, info.dir))
-           {
-             tree_evaluator& tw = interp.get_evaluator ();
-
-             bp_table& bptab = tw.get_bp_table ();
-
-             bp_table::intmap bpmap
-               = bptab.add_breakpoint (info.function_name, "", line_info,
-                                       info.condition);
-
-             if (! bpmap.empty ())
-               {
-                 bp_table::intmap::iterator bp_it = bpmap.begin ();
-
-                 int remove_line = bp_it->second;
-
-                 emit maybe_remove_next (remove_line);
-               }
-           }
+         tree_evaluator& tw = interp.get_evaluator ();
+         bp_table& bptab = tw.get_bp_table ();
+
+         int lineno = bptab.add_breakpoint_in_file (m_file_name.toStdString (),
+                                                    line, cond.toStdString ());
+
+         if (lineno)
+           emit maybe_remove_next (lineno);
        });
   }
 
@@ -1690,14 +1634,9 @@
       title = tr ("<unnamed>");
     else
       {
-        if (m_long_title)
-          title = m_file_name;
-        else
-          {
-            QFileInfo file (m_file_name);
-            title = file.fileName ();
-            tooltip = m_file_name;
-          }
+        QFileInfo file (m_file_name);
+        title = file.fileName ();
+        tooltip = m_file_name;
       }
 
     emit file_name_changed (title, tooltip, modified);
@@ -1836,7 +1775,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;
@@ -1868,8 +1823,8 @@
         msg_box->addButton (tr ("Chan&ge encoding"), QMessageBox::AcceptRole);
         msg_box->addButton (tr ("&Close"), QMessageBox::RejectRole);
 
-        connect (msg_box, SIGNAL (buttonClicked (QAbstractButton *)),
-                 this, SLOT (handle_decode_warning_answer (QAbstractButton *)));
+        connect (msg_box, &QMessageBox::buttonClicked,
+                 this, &file_editor_tab::handle_decode_warning_answer);
 
         msg_box->setWindowModality (Qt::WindowModal);
         msg_box->setAttribute (Qt::WA_DeleteOnClose);
@@ -1919,14 +1874,14 @@
         resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
         rmgr.combo_encoding (enc_combo);
         m_new_encoding = enc_combo->currentText ();
-        connect (enc_combo, SIGNAL (currentTextChanged (const QString&)),
-                 this, SLOT (handle_current_enc_changed (const QString&)));
+        connect (enc_combo, &QComboBox::currentTextChanged,
+                 this, &file_editor_tab::handle_current_enc_changed);
 
         QDialogButtonBox *buttons
           = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
                                   Qt::Horizontal);
-        connect (buttons, SIGNAL (accepted ()), &dlg, SLOT (accept ()));
-        connect (buttons, SIGNAL (rejected ()), &dlg, SLOT (reject ()));
+        connect (buttons, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
+        connect (buttons, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);
 
         QGridLayout *main_layout = new QGridLayout;
         main_layout->setSizeConstraint (QLayout::SetFixedSize);
@@ -2017,14 +1972,14 @@
     // Create and queue the command object.
 
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
          octave_value_list argout = Fdbstatus (interp, ovl (), 1);
 
-         connect (this, SIGNAL (update_breakpoints_signal (const octave_value_list&)),
-                  this, SLOT (update_breakpoints_handler (const octave_value_list&)),
+         connect (this, &file_editor_tab::update_breakpoints_signal,
+                  this, &file_editor_tab::update_breakpoints_handler,
                   Qt::QueuedConnection);
 
          emit update_breakpoints_signal (argout);
@@ -2080,7 +2035,7 @@
     if (ans == QMessageBox::Save)
       {
         emit interpreter_event
-          ([this, file_to_save, base_name, remove_on_success, restore_breakpoints] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -2135,7 +2090,7 @@
         QString base_name = file_info.baseName ();
 
         emit interpreter_event
-          ([this, file_to_save, base_name, remove_on_success, restore_breakpoints] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -2156,7 +2111,7 @@
                    {
                      sym = symtab.find_user_function (std_base_name);
                    }
-                 catch (const execution_exception& e)
+                 catch (const execution_exception&)
                    {
                      interp.recover_from_exception ();
 
@@ -2258,10 +2213,23 @@
     if (! codec)
       return;   // No valid codec
 
+    // Remove trailing white spaces if desired
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+    if (settings->value (ed_rm_trailing_spaces).toBool ())
+      m_edit_area->replace_all ("[ \\t]+$", "", true, false, false);
+
+    // Save the file
     out.setCodec (codec);
 
     QApplication::setOverrideCursor (Qt::WaitCursor);
+
     out << m_edit_area->text ();
+    if (settings->value (ed_force_newline).toBool ()
+        && m_edit_area->text ().length ())
+      out << m_edit_area->eol_string ();   // Add newline if desired
+
     out.flush ();
     QApplication::restoreOverrideCursor ();
     file.flush ();
@@ -2367,21 +2335,21 @@
         fileDialog->setOption(QFileDialog::DontConfirmOverwrite);
       }
 
-    connect (fileDialog, SIGNAL (filterSelected (const QString&)),
-             this, SLOT (handle_save_as_filter_selected (const QString&)));
+    connect (fileDialog, &QFileDialog::filterSelected,
+             this, &file_editor_tab::handle_save_as_filter_selected);
 
     if (remove_on_success)
       {
-        connect (fileDialog, SIGNAL (fileSelected (const QString&)),
-                 this, SLOT (handle_save_file_as_answer_close (const QString&)));
-
-        connect (fileDialog, SIGNAL (rejected ()),
-                 this, SLOT (handle_save_file_as_answer_cancel ()));
+        connect (fileDialog, &QFileDialog::fileSelected,
+                 this, &file_editor_tab::handle_save_file_as_answer_close);
+
+        connect (fileDialog, &QFileDialog::rejected,
+                 this, &file_editor_tab::handle_save_file_as_answer_cancel);
       }
     else
       {
-        connect (fileDialog, SIGNAL (fileSelected (const QString&)),
-                 this, SLOT (handle_save_file_as_answer (const QString&)));
+        connect (fileDialog, &QFileDialog::fileSelected,
+                 this, &file_editor_tab::handle_save_file_as_answer);
       }
 
     show_dialog (fileDialog, ! valid_file_name ());
@@ -2461,9 +2429,10 @@
                               (u32_str.data ());
 
         std::size_t length;
+        const std::string encoding = m_encoding.toStdString ();
         char *res_str =
-          octave_u32_conv_to_encoding_strict (m_encoding.toStdString ().c_str (),
-                                              src, u32_str.size (), &length);
+          octave_u32_conv_to_encoding_strict (encoding.c_str (), src,
+                                              u32_str.size (), &length);
         if (! res_str)
           {
             if (errno == EILSEQ)
@@ -2527,9 +2496,6 @@
           }
       }
 
-    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);
@@ -2546,13 +2512,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
 
@@ -2615,8 +2574,8 @@
                                  arg (m_file_name),
                                  QMessageBox::Yes | QMessageBox::No, this);
 
-            connect (msgBox, SIGNAL (finished (int)),
-                     this, SLOT (handle_file_reload_answer (int)));
+            connect (msgBox, &QMessageBox::finished,
+                     this, &file_editor_tab::handle_file_reload_answer);
 
             msgBox->setWindowModality (Qt::WindowModal);
             msgBox->setAttribute (Qt::WA_DeleteOnClose);
@@ -2655,8 +2614,8 @@
 
         m_edit_area->setReadOnly (true);
 
-        connect (msgBox, SIGNAL (finished (int)),
-                 this, SLOT (handle_file_resave_answer (int)));
+        connect (msgBox, &QMessageBox::finished,
+                 this, &file_editor_tab::handle_file_resave_answer);
 
         msgBox->setWindowModality (Qt::WindowModal);
         msgBox->setAttribute (Qt::WA_DeleteOnClose);
@@ -2690,11 +2649,10 @@
       m_status_bar->hide ();
 
     //highlight current line color
-    QColor setting_color = settings->value (ed_highlight_current_line_color).value<QColor> ();
-    m_edit_area->setCaretLineBackgroundColor (setting_color);
     m_edit_area->setCaretLineVisible
       (settings->value (ed_highlight_current_line).toBool ());
 
+    // auto completion
     bool match_keywords = settings->value
                           (ed_code_completion_keywords).toBool ();
     bool match_document = settings->value
@@ -2738,13 +2696,14 @@
       {
         m_edit_area->setMarginLineNumbers (2, true);
         auto_margin_width ();
-        connect (m_edit_area, SIGNAL (linesChanged ()),
-                 this, SLOT (auto_margin_width ()));
+        connect (m_edit_area, &octave_qscintilla::linesChanged,
+                 this, &file_editor_tab::auto_margin_width);
       }
     else
       {
         m_edit_area->setMarginLineNumbers (2, false);
-        disconnect (m_edit_area, SIGNAL (linesChanged ()), nullptr, nullptr);
+        disconnect (m_edit_area, &octave_qscintilla::linesChanged,
+                    nullptr, nullptr);
       }
 
     m_smart_indent = settings->value (ed_auto_indent).toBool ();
@@ -2772,7 +2731,6 @@
     m_edit_area->SendScintilla (QsciScintillaBase::SCI_SETSCROLLWIDTH,-1);
     m_edit_area->SendScintilla (QsciScintillaBase::SCI_SETSCROLLWIDTHTRACKING,true);
 
-    m_long_title = settings->value (ed_long_window_title).toBool ();
     update_window_title (m_edit_area->isModified ());
 
     m_auto_endif = settings->value (ed_auto_endif).toInt ();
@@ -2960,10 +2918,11 @@
               }
           }
 
-        connect (this, SIGNAL (remove_position_via_debugger_linenr (int)),
-                 dp,   SLOT (handle_remove_via_original_linenr (int)));
-        connect (this, SIGNAL (remove_all_positions (void)),
-                 dp,   SLOT (handle_remove (void)));
+        connect (this, &file_editor_tab::remove_position_via_debugger_linenr,
+                 dp, &marker::handle_remove_via_original_linenr);
+
+        connect (this, &file_editor_tab::remove_all_positions,
+                 dp, &marker::handle_remove);
 
         center_current_line (false);
       }
@@ -3013,27 +2972,20 @@
                                  cond == "" ? marker::breakpoint
                                  : marker::cond_break, cond);
 
-                connect (this, SIGNAL (remove_breakpoint_via_debugger_linenr
-                                       (int)),
-                         bp,   SLOT (handle_remove_via_original_linenr (int)));
-                connect (this, SIGNAL (request_remove_breakpoint_via_editor_linenr
-                                       (int)),
-                         bp,   SLOT (handle_request_remove_via_editor_linenr
-                                     (int)));
-                connect (this, SIGNAL (remove_all_breakpoints (void)),
-                         bp,   SLOT (handle_remove (void)));
-                connect (this, SIGNAL (find_translated_line_number (int, int&,
-                                                                    marker*&)),
-                         bp,   SLOT (handle_find_translation (int, int&,
-                                                              marker*&)));
-                connect (this, SIGNAL (find_linenr_just_before (int, int&, int&)),
-                         bp,   SLOT (handle_find_just_before (int, int&, int&)));
-                connect (this, SIGNAL (report_marker_linenr (QIntList&,
-                                                             QStringList&)),
-                         bp,   SLOT (handle_report_editor_linenr (QIntList&,
-                                                                  QStringList&)));
-                connect (bp,   SIGNAL (request_remove (int)),
-                         this, SLOT (handle_request_remove_breakpoint (int)));
+                connect (this, &file_editor_tab::remove_breakpoint_via_debugger_linenr,
+                         bp, &marker::handle_remove_via_original_linenr);
+                connect (this, &file_editor_tab::request_remove_breakpoint_via_editor_linenr,
+                         bp, &marker::handle_request_remove_via_editor_linenr);
+                connect (this, &file_editor_tab::remove_all_breakpoints_signal,
+                         bp, &marker::handle_remove);
+                connect (this, &file_editor_tab::find_translated_line_number,
+                         bp, &marker::handle_find_translation);
+                connect (this, &file_editor_tab::find_linenr_just_before,
+                         bp, &marker::handle_find_just_before);
+                connect (this, &file_editor_tab::report_marker_linenr,
+                         bp, &marker::handle_report_editor_linenr);
+                connect (bp, &marker::request_remove,
+                         this, &file_editor_tab::handle_request_remove_breakpoint);
               }
           }
         else
@@ -3206,7 +3158,7 @@
 
                 // remember first visible line and x-offset for restoring the view afterwards
                 int first_line = m_edit_area->firstVisibleLine ();
-                int x_offset = m_edit_area->SendScintilla(QsciScintillaBase::SCI_GETXOFFSET);
+                int x_offset = m_edit_area->SendScintilla (QsciScintillaBase::SCI_GETXOFFSET);
 
                 // search for first occurrence of the detected word
                 bool find_result_available
@@ -3241,7 +3193,7 @@
                 // restore the visible area of the file, the cursor position,
                 // and the selection
                 m_edit_area->setFirstVisibleLine (first_line);
-                m_edit_area->SendScintilla(QsciScintillaBase::SCI_SETXOFFSET, x_offset);
+                m_edit_area->SendScintilla (QsciScintillaBase::SCI_SETXOFFSET, x_offset);
                 m_edit_area->setCursorPosition (line, col);
                 m_edit_area->setSelection (line, col - wlen, line, col);
                 m_edit_area->set_word_selection (word);
--- a/libgui/src/m-editor/file-editor-tab.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/m-editor/file-editor-tab.h	Sun May 16 09:44:35 2021 +0200
@@ -92,7 +92,7 @@
 
     void remove_breakpoint_via_debugger_linenr (int debugger_linenr);
     void request_remove_breakpoint_via_editor_linenr (int editor_linenr);
-    void remove_all_breakpoints (void);
+    void remove_all_breakpoints_signal (void);
     void find_translated_line_number (int original_linenr,
                                       int& translated_linenr, marker*&);
     void find_linenr_just_before (int linenr, int& original_linenr,
@@ -204,6 +204,8 @@
 
     void update_breakpoints_handler (const octave_value_list& argout);
 
+    void update_lexer_settings (bool update_apis_only = false);
+
   private slots:
 
     // When user closes message box for decoding problems
@@ -258,18 +260,7 @@
 
     base_qobject& m_octave_qobj;
 
-    struct bp_info
-    {
-      bp_info (const QString& fname, int l = 0, const QString& cond = "");
-
-      int line;
-      std::string file;
-      std::string dir;
-      std::string function_name;
-      std::string condition;
-    };
-
-    void add_breakpoint_event (const bp_info& info);
+    void add_breakpoint_event (int line, const QString& cond);
 
     bool valid_file_name (const QString& file = QString ());
     void save_file (const QString& saveFileName, bool remove_on_success = false,
@@ -281,7 +272,6 @@
     bool unchanged_or_saved (void);
 
     void update_lexer (void);
-    void update_lexer_settings (void);
 
     void show_dialog (QDialog *dlg, bool modal);
   public:
@@ -317,7 +307,6 @@
     QDateTime m_last_modified;
 
     bool m_autoc_active;
-    bool m_long_title;
     bool m_copy_available;
     bool m_is_octave_file;
     bool m_always_reload_changed_files;
--- a/libgui/src/m-editor/file-editor.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/m-editor/file-editor.cc	Sun May 16 09:44:35 2021 +0200
@@ -32,6 +32,7 @@
 #include <algorithm>
 
 #include <QApplication>
+#include <QClipboard>
 #include <QFile>
 #include <QFileDialog>
 #include <QFont>
@@ -51,6 +52,7 @@
 #include "gui-preferences-global.h"
 #include "main-window.h"
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 #include "shortcut-manager.h"
 
 #include "oct-env.h"
@@ -70,6 +72,7 @@
   {
     tab_bar *bar = new tab_bar (this);
 
+    // FIXME: Making a connection to a grandparent object seems bad.
     connect (bar, SIGNAL (close_current_tab_signal (bool)),
              p->parent (), SLOT (request_close_file (bool)));
 
@@ -77,9 +80,7 @@
 
     setTabsClosable (true);
     setUsesScrollButtons (true);
-#if defined (HAVE_QTABWIDGET_SETMOVABLE)
     setMovable (true);
-#endif
   }
 
   tab_bar * file_editor_tab_widget::get_tab_bar (void) const
@@ -128,11 +129,6 @@
     setFocusPolicy (Qt::StrongFocus);
   }
 
-  file_editor::~file_editor (void)
-  {
-    delete m_mru_file_menu;
-  }
-
   void file_editor::focusInEvent (QFocusEvent *e)
   {
     // The focus is transferred to the active tab and its edit
@@ -193,6 +189,8 @@
       m_run_action->setShortcut (QKeySequence ());  // prevent ambiguous shortcuts
 
     m_run_action->setToolTip (tr ("Continue"));   // update tool tip
+
+    emit enter_debug_mode_signal ();
   }
 
   void file_editor::handle_exit_debug_mode (void)
@@ -200,10 +198,13 @@
     shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager ();
     scmgr.set_shortcut (m_run_action, sc_edit_run_run_file);
     m_run_action->setToolTip (tr ("Save File and Run"));  // update tool tip
+
+    emit exit_debug_mode_signal ();
   }
 
   void file_editor::check_actions (void)
   {
+    // Do not include shared actions not only related to the editor
     bool have_tabs = m_tab_widget->count () > 0;
 
     m_edit_cmd_menu->setEnabled (have_tabs);
@@ -229,7 +230,13 @@
     m_find_next_action->setEnabled (have_tabs);
     m_find_previous_action->setEnabled (have_tabs);
     m_print_action->setEnabled (have_tabs);
-    m_run_action->setEnabled (have_tabs);
+
+    m_run_action->setEnabled (have_tabs && m_is_octave_file);
+
+    m_toggle_breakpoint_action->setEnabled (have_tabs && m_is_octave_file);
+    m_next_breakpoint_action->setEnabled (have_tabs && m_is_octave_file);
+    m_previous_breakpoint_action->setEnabled (have_tabs && m_is_octave_file);
+    m_remove_all_breakpoints_action->setEnabled (have_tabs && m_is_octave_file);
 
     m_edit_function_action->setEnabled (have_tabs);
     m_save_action->setEnabled (have_tabs);
@@ -239,7 +246,7 @@
     m_close_others_action->setEnabled (have_tabs && m_tab_widget->count () > 1);
     m_sort_tabs_action->setEnabled (have_tabs && m_tab_widget->count () > 1);
 
-    emit editor_tabs_changed_signal (have_tabs);
+    emit editor_tabs_changed_signal (have_tabs, m_is_octave_file);
   }
 
   // empty_script determines whether we have to create an empty script
@@ -267,28 +274,33 @@
     if (startup && ! isFloating ())
       {
         // check if editor is really visible or hidden between tabbed widgets
-        QList<QTabBar *> tab_list = main_win ()->findChildren<QTabBar *>();
-
-        bool in_tab = false;
-        int i = 0;
-        while ((i < tab_list.count ()) && (! in_tab))
+        QWidget *parent = parentWidget ();
+
+        if (parent)
           {
-            QTabBar *tab = tab_list.at (i);
-            i++;
-
-            int j = 0;
-            while ((j < tab->count ()) && (! in_tab))
+            QList<QTabBar *> tab_list = parent->findChildren<QTabBar *>();
+
+            bool in_tab = false;
+            int i = 0;
+            while ((i < tab_list.count ()) && (! in_tab))
               {
-                // check all tabs for the editor
-                if (tab->tabText (j) == windowTitle ())
+                QTabBar *tab = tab_list.at (i);
+                i++;
+
+                int j = 0;
+                while ((j < tab->count ()) && (! in_tab))
                   {
-                    // editor is in this tab widget
-                    in_tab = true;
-                    int top = tab->currentIndex ();
-                    if (! (top > -1 && tab->tabText (top) == windowTitle ()))
-                      return; // not current tab -> not visible
+                    // check all tabs for the editor
+                    if (tab->tabText (j) == windowTitle ())
+                      {
+                        // editor is in this tab widget
+                        in_tab = true;
+                        int top = tab->currentIndex ();
+                        if (! (top > -1 && tab->tabText (top) == windowTitle ()))
+                          return; // not current tab -> not visible
+                      }
+                    j++;
                   }
-                j++;
               }
           }
       }
@@ -468,8 +480,8 @@
       {
         // Wait for all editor tabs to have saved their files if required
 
-        connect (fe_tab, SIGNAL (tab_ready_to_close (void)),
-                 this, SLOT (handle_tab_ready_to_close (void)),
+        connect (fe_tab, &file_editor_tab::tab_ready_to_close,
+                 this, &file_editor::handle_tab_ready_to_close,
                  Qt::UniqueConnection);
       }
 
@@ -489,7 +501,7 @@
             m_closing_canceled = true;
 
             for (auto fet : fe_tab_lst)
-              disconnect (fet, SIGNAL (tab_ready_to_close (void)), 0, 0 );
+              disconnect (fet, &file_editor_tab::tab_ready_to_close, 0, 0);
 
             return false;
           }
@@ -503,6 +515,10 @@
     if (m_closing_canceled)
       return;
 
+    // FIXME: Why count down to zero here before doing anything?  Why
+    // not remove and delete each tab that is ready to be closed, one
+    // per invocation?
+
     m_number_of_tabs--;
 
     if (m_number_of_tabs > 0)
@@ -522,7 +538,7 @@
 
     std::list<file_editor_tab *> editor_tab_lst = m_tab_widget->tab_list ();
     for (auto editor_tab : editor_tab_lst)
-      delete editor_tab;
+      editor_tab->deleteLater ();
 
     m_tab_widget->clear ();
 
@@ -582,6 +598,15 @@
       }
   }
 
+  void file_editor::copy_full_file_path (bool)
+  {
+    file_editor_tab *editor_tab
+      = static_cast<file_editor_tab *> (m_tab_widget->currentWidget ());
+
+    if (editor_tab)
+      QGuiApplication::clipboard ()->setText (editor_tab->file_name ());
+  }
+
   // open a file from the mru list
   void file_editor::request_mru_open_file (QAction *action)
   {
@@ -637,7 +662,7 @@
   void file_editor::request_run_file (bool)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -852,7 +877,7 @@
     if (isFloating ())
       m_find_dialog = new find_dialog (m_octave_qobj, this, this);
     else
-      m_find_dialog = new find_dialog (m_octave_qobj, this, main_win ());
+      m_find_dialog = new find_dialog (m_octave_qobj, this, parentWidget ());
 
     // Add required actions
     m_find_dialog->addAction (m_find_next_action);
@@ -873,8 +898,14 @@
     if (! isFloating ())
       {
         // Fix position if editor is docked
-        xp = xp + main_win ()->x();
-        yp = yp + main_win ()->y();
+
+        QWidget *parent = parentWidget ();
+
+        if  (parent)
+          {
+            xp = xp + parent->x ();
+            yp = yp + parent->y ();
+          }
       }
 
     if (yp < 0)
@@ -952,10 +983,10 @@
             if (m_tab_widget->widget (i) == fileEditorTab)
               {
                 m_tab_widget->removeTab (i);
-                // Deleting sender is dodgy, but works because the signal
-                // is the last item in the sender's routines.
-                // FIXME: can we use deleteLater here?
-                delete fileEditorTab;
+
+                // Deleting the sender (even with deleteLater) seems a
+                // bit strange.  Is there a better way?
+                fileEditorTab->deleteLater ();
                 break;
               }
           }
@@ -983,8 +1014,12 @@
         if (m_copy_action)
           m_copy_action->setEnabled (copy_available);
         m_cut_action->setEnabled (copy_available);
+
         m_run_selection_action->setEnabled (copy_available);
         m_run_action->setEnabled (is_octave_file);
+        m_is_octave_file = is_octave_file;
+
+        emit editor_tabs_changed_signal (true, m_is_octave_file);
       }
 
     m_copy_action_enabled = m_copy_action->isEnabled ();
@@ -1225,26 +1260,24 @@
     int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
     m_tool_bar->setIconSize (QSize (icon_size, icon_size));
 
-    // Tab position
+    // Tab position and rotation
     QTabWidget::TabPosition pos
       = static_cast<QTabWidget::TabPosition> (settings->value (ed_tab_position).toInt ());
+    bool rotated = settings->value (ed_tabs_rotated).toBool ();
 
     m_tab_widget->setTabPosition (pos);
 
-    // Update style sheet properties depending on position
-    QString width_str ("width");
-    QString height_str ("height");
-    if (pos == QTabWidget::West || pos == QTabWidget::East)
-      {
-        width_str = QString ("height");
-        height_str = QString ("width");
-      }
-
-    // Min and max width for full path titles
-    int tab_width_min = settings->value (ed_notebook_tab_width_min)
-                        .toInt ();
-    int tab_width_max = settings->value (ed_notebook_tab_width_max)
-                        .toInt ();
+    if (rotated)
+      m_tab_widget->setTabsClosable (false);  // No close buttons
+      // FIXME: close buttons can not be correctly placed in rotated tabs
+
+    // Get the tab bar and set the rotation
+    int rotation = rotated;
+    if (pos == QTabWidget::West)
+      rotation = -rotation;
+
+    tab_bar *bar = m_tab_widget->get_tab_bar ();
+    bar->set_rotated (rotation);
 
     // Get suitable height of a tab related to font and icon size
     int height = 1.5*QFontMetrics (m_tab_widget->font ()).height ();
@@ -1252,35 +1285,40 @@
     if (is > height)
       height = is;
 
-    // Style sheet for tab height
-    QString style_sheet = QString ("QTabBar::tab {max-" + height_str + ": %1px;}")
-                          .arg (height);
-
-    // Style sheet for tab height together with width
-    if (settings->value (ed_long_window_title).toBool ())
+    // Calculate possibly limited width and set the elide mode
+    int chars = settings->value (ed_tabs_max_width).toInt ();
+    int width = 9999;
+    if (chars > 0)
+      width = chars * QFontMetrics (m_tab_widget->font ()).averageCharWidth ();
+
+    // Get tab bar size properties for style sheet depending on rotation
+    QString width_str ("width");
+    QString height_str ("height");
+    if ((pos == QTabWidget::West) || (pos == QTabWidget::East))
       {
-        style_sheet = QString ("QTabBar::tab "
-                               " {max-" + height_str + ": %1px;"
-                               "  min-" + width_str + ": %2px;"
-                               "  max-" + width_str + ": %3px;}")
-                      .arg (height).arg (tab_width_min).arg (tab_width_max);
-        m_tab_widget->setElideMode (Qt::ElideLeft);
+        width_str = QString ("height");
+        height_str = QString ("width");
       }
-    else
-      {
-        m_tab_widget->setElideMode (Qt::ElideNone);
-      }
+
+    QString style_sheet
+        = QString ("QTabBar::tab {max-" + height_str + ": %1px;\n"
+                                 "max-" + width_str + ": %2px; }")
+                          .arg (height).arg (width);
 
 #if defined (Q_OS_MAC)
     // FIXME: This is a workaround for missing tab close buttons on MacOS
     // in several Qt versions (https://bugreports.qt.io/browse/QTBUG-61092)
-    QString close_button_css
-      ("QTabBar::close-button"
-       "  { width: 6px; image: url(:/actions/icons/widget-close.png);}\n"
-       "QTabBar::close-button:hover"
-       "  { background-color: #cccccc; }");
-
-    style_sheet = style_sheet + close_button_css;
+    if (! rotated)
+      {
+        QString close_button_css_mac (
+            "QTabBar::close-button"
+            "  { width: 6px; image: url(:/actions/icons/widget-close.png);"
+            "    subcontrol-position: button; }\n"
+            "QTabBar::close-button:hover"
+            "  { background-color: #cccccc; }");
+
+        style_sheet = style_sheet + close_button_css_mac;
+      }
 #endif
 
     m_tab_widget->setStyleSheet (style_sheet);
@@ -1412,6 +1450,8 @@
   // files and is made visible.
   void file_editor::handle_visibility (bool visible)
   {
+    octave_dock_widget::handle_visibility (visible);
+
     if (m_closed && visible)
       {
         m_closed = false;
@@ -1421,9 +1461,6 @@
       }
 
     empty_script (false, visible);
-
-    if (visible && ! isFloating ())
-      setFocus ();
   }
 
   // This slot is a reimplementation of the virtual slot in octave_dock_widget.
@@ -1807,15 +1844,22 @@
 
   bool file_editor::is_editor_console_tabbed (void)
   {
-    main_window *w = static_cast<main_window *>(main_win ());
-    QList<QDockWidget *> w_list = w->tabifiedDockWidgets (this);
-    QDockWidget *console =
-      static_cast<QDockWidget *> (w->get_dock_widget_list ().at (0));
-
-    for (int i = 0; i < w_list.count (); i++)
+    // FIXME: is there a way to do this job that doesn't require casting
+    // the parent to a main_window object?
+
+    main_window *w = dynamic_cast<main_window *> (parentWidget ());
+
+    if (w)
       {
-        if (w_list.at (i) == console)
-          return true;
+        QList<QDockWidget *> w_list = w->tabifiedDockWidgets (this);
+        QDockWidget *console =
+          static_cast<QDockWidget *> (w->get_dock_widget_list ().at (0));
+
+        for (int i = 0; i < w_list.count (); i++)
+          {
+            if (w_list.at (i) == console)
+              return true;
+          }
       }
 
     return false;
@@ -2279,33 +2323,30 @@
     editor_widget->setLayout (vbox_layout);
     setWidget (editor_widget);
 
-    // create the context menu of the tab bar
+    // Create the basic context menu of the tab bar with editor actions.
+    // Actions for selecting an tab are added when the menu is activated.
     tab_bar *bar = m_tab_widget->get_tab_bar ();
     QMenu *ctx_men = bar->get_context_menu ();
+    ctx_men->addSeparator ();
     ctx_men->addAction (m_close_action);
     ctx_men->addAction (m_close_all_action);
     ctx_men->addAction (m_close_others_action);
     ctx_men->addSeparator ();
     ctx_men->addAction (m_sort_tabs_action);
+    add_action (ctx_men, tr ("Copy Full File &Path"),
+                SLOT (copy_full_file_path (bool)), this);
 
     // signals
-    connect (this, SIGNAL (request_settings_dialog (const QString&)),
-             main_win (),
-             SLOT (process_settings_dialog_request (const QString&)));
-
-    connect (this, SIGNAL (request_dbcont_signal (void)),
-             main_win (), SLOT (debug_continue (void)));
-
-    connect (m_mru_file_menu, SIGNAL (triggered (QAction *)),
-             this, SLOT (request_mru_open_file (QAction *)));
+    connect (m_mru_file_menu, &QMenu::triggered,
+             this, &file_editor::request_mru_open_file);
 
     mru_menu_update ();
 
-    connect (m_tab_widget, SIGNAL (tabCloseRequested (int)),
-             this, SLOT (handle_tab_close_request (int)));
-
-    connect (m_tab_widget, SIGNAL (currentChanged (int)),
-             this, SLOT (active_tab_changed (int)));
+    connect (m_tab_widget, &file_editor_tab_widget::tabCloseRequested,
+             this, &file_editor::handle_tab_close_request);
+
+    connect (m_tab_widget, &file_editor_tab_widget::currentChanged,
+             this, &file_editor::active_tab_changed);
 
     resize (500, 400);
     setWindowIcon (QIcon (":/actions/icons/logo.png"));
@@ -2354,195 +2395,198 @@
     file_editor_tab *f = new file_editor_tab (m_octave_qobj, directory);
 
     // signals from the qscintilla edit area
-    connect (f->qsci_edit_area (), SIGNAL (status_update (bool, bool)),
-             this, SLOT (edit_status_update (bool, bool)));
-
-    connect (f->qsci_edit_area (), SIGNAL (show_doc_signal (const QString&)),
-             main_win (), SLOT (handle_show_doc (const QString&)));
-
-    connect (f->qsci_edit_area (), SIGNAL (create_context_menu_signal (QMenu *)),
-             this, SLOT (create_context_menu (QMenu *)));
-
-    connect (f->qsci_edit_area (),
-             SIGNAL (execute_command_in_terminal_signal (const QString&)),
-             main_win (), SLOT (execute_command_in_terminal (const QString&)));
-
-    connect (f->qsci_edit_area (),
-             SIGNAL (focus_console_after_command_signal (void)),
-             main_win (), SLOT (focus_console_after_command (void)));
-
-    connect (f->qsci_edit_area (),
-             SIGNAL (SCN_AUTOCCOMPLETED (const char*, int, int, int)),
-             this, SLOT (reset_focus (void)));
-
-    connect (f->qsci_edit_area (), SIGNAL (SCN_AUTOCCANCELLED (void)),
-             this, SLOT (handle_autoc_cancelled (void)));
+    connect (f->qsci_edit_area (), &octave_qscintilla::status_update,
+             this, &file_editor::edit_status_update);
+
+    connect (f->qsci_edit_area (), &octave_qscintilla::create_context_menu_signal,
+             this, &file_editor::create_context_menu);
+
+    connect (f->qsci_edit_area (), &octave_qscintilla::SCN_AUTOCCOMPLETED,
+             this, &file_editor::reset_focus);
+
+    connect (f->qsci_edit_area (), &octave_qscintilla::SCN_AUTOCCANCELLED,
+             this, &file_editor::handle_autoc_cancelled);
+
+    // signals from the qscintilla edit area
+    connect (this, &file_editor::enter_debug_mode_signal,
+             f->qsci_edit_area (), &octave_qscintilla::handle_enter_debug_mode);
+
+    connect (this, &file_editor::exit_debug_mode_signal,
+             f->qsci_edit_area (), &octave_qscintilla::handle_exit_debug_mode);
 
     // Signals from the file editor_tab
-    connect (f, SIGNAL (autoc_closed (void)),
-             this, SLOT (reset_focus (void)));
-
-    connect (f, SIGNAL (file_name_changed (const QString&, const QString&, bool)),
-             this, SLOT (handle_file_name_changed (const QString&,
-                                                   const QString&, bool)));
-
-    connect (f, SIGNAL (editor_state_changed (bool, bool)),
-             this, SLOT (handle_editor_state_changed (bool, bool)));
-
-    connect (f, SIGNAL (tab_remove_request ()),
-             this, SLOT (handle_tab_remove_request ()));
-
-    connect (f, SIGNAL (editor_check_conflict_save (const QString&, bool)),
-             this, SLOT (check_conflict_save (const QString&, bool)));
-
-    connect (f, SIGNAL (mru_add_file (const QString&, const QString&)),
-             this, SLOT (handle_mru_add_file (const QString&, const QString&)));
-
-    connect (f, SIGNAL (run_file_signal (const QFileInfo&)),
-             main_win (), SLOT (run_file_in_terminal (const QFileInfo&)));
-
-    connect (f, SIGNAL (request_open_file (const QString&, const QString&)),
-             this, SLOT (request_open_file (const QString&, const QString&)));
-
-    connect (f, SIGNAL (edit_mfile_request (const QString&, const QString&,
-                                            const QString&, int)),
-             main_win (), SLOT (handle_edit_mfile_request (const QString&,
-                                                           const QString&,
-                                                           const QString&, int)));
-
-    connect (f, SIGNAL (edit_area_changed (octave_qscintilla*)),
-             this, SIGNAL (edit_area_changed (octave_qscintilla*)));
-
-    connect (f, SIGNAL (set_focus_editor_signal (QWidget*)),
-             this, SLOT (set_focus (QWidget*)));
-
-    // Signals from the file_editor non-trivial operations
-    connect (this, SIGNAL (fetab_settings_changed (const gui_settings *)),
-             f, SLOT (notice_settings (const gui_settings *)));
-
-    connect (this, SIGNAL (fetab_change_request (const QWidget*)),
-             f, SLOT (change_editor_state (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_save_file (const QWidget*, const QString&,
-                                            bool)),
-             f, SLOT (save_file (const QWidget*, const QString&, bool)));
+    connect (f, &file_editor_tab::autoc_closed,
+             this, &file_editor::reset_focus);
+
+    connect (f, &file_editor_tab::file_name_changed,
+             this, &file_editor::handle_file_name_changed);
+
+    connect (f, &file_editor_tab::editor_state_changed,
+             this, &file_editor::handle_editor_state_changed);
+
+    connect (f, &file_editor_tab::tab_remove_request,
+             this, &file_editor::handle_tab_remove_request);
+
+    connect (f, &file_editor_tab::editor_check_conflict_save,
+             this, &file_editor::check_conflict_save);
+
+    connect (f, &file_editor_tab::mru_add_file,
+             this, &file_editor::handle_mru_add_file);
+
+    connect (f, &file_editor_tab::request_open_file,
+             this, [=] (const QString& fname, const QString& encoding) { request_open_file (fname, encoding); });
+
+    connect (f, &file_editor_tab::edit_area_changed,
+             this, &file_editor::edit_area_changed);
+
+    connect (f, &file_editor_tab::set_focus_editor_signal,
+             this, &file_editor::set_focus);
+
+    // Signals from the file_editor or main-win non-trivial operations
+    connect (this, &file_editor::fetab_settings_changed,
+             f, [=] (const gui_settings *settings) { f->notice_settings (settings); });
+
+    connect (this, &file_editor::fetab_change_request,
+             f, &file_editor_tab::change_editor_state);
+
+    connect (this, QOverload<const QWidget*, const QString&, bool>::of (&file_editor::fetab_save_file),
+             f, QOverload<const QWidget*, const QString&, bool>::of (&file_editor_tab::save_file));
 
     // Signals from the file_editor trivial operations
-    connect (this, SIGNAL (fetab_recover_from_exit (void)),
-             f, SLOT (recover_from_exit (void)));
-
-    connect (this, SIGNAL (fetab_set_directory (const QString&)),
-             f, SLOT (set_current_directory (const QString&)));
-
-    connect (this, SIGNAL (fetab_zoom_in (const QWidget*)),
-             f, SLOT (zoom_in (const QWidget*)));
-    connect (this, SIGNAL (fetab_zoom_out (const QWidget*)),
-             f, SLOT (zoom_out (const QWidget*)));
-    connect (this, SIGNAL (fetab_zoom_normal (const QWidget*)),
-             f, SLOT (zoom_normal (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_context_help (const QWidget*, bool)),
-             f, SLOT (context_help (const QWidget*, bool)));
-
-    connect (this, SIGNAL (fetab_context_edit (const QWidget*)),
-             f, SLOT (context_edit (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_save_file (const QWidget*)),
-             f, SLOT (save_file (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_save_file_as (const QWidget*)),
-             f, SLOT (save_file_as (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_print_file (const QWidget*)),
-             f, SLOT (print_file (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_run_file (const QWidget*, bool)),
-             f, SLOT (run_file (const QWidget*, bool)));
-
-    connect (this, SIGNAL (fetab_context_run (const QWidget*)),
-             f, SLOT (context_run (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_toggle_bookmark (const QWidget*)),
-             f, SLOT (toggle_bookmark (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_next_bookmark (const QWidget*)),
-             f, SLOT (next_bookmark (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_previous_bookmark (const QWidget*)),
-             f, SLOT (previous_bookmark (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_remove_bookmark (const QWidget*)),
-             f, SLOT (remove_bookmark (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_toggle_breakpoint (const QWidget*)),
-             f, SLOT (toggle_breakpoint (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_next_breakpoint (const QWidget*)),
-             f, SLOT (next_breakpoint (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_previous_breakpoint (const QWidget*)),
-             f, SLOT (previous_breakpoint (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_remove_all_breakpoints (const QWidget*)),
-             f, SLOT (remove_all_breakpoints (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_scintilla_command (const QWidget *,
-                                                    unsigned int)),
-             f, SLOT (scintilla_command (const QWidget *, unsigned int)));
-
-    connect (this, SIGNAL (fetab_comment_selected_text (const QWidget*, bool)),
-             f, SLOT (comment_selected_text (const QWidget*, bool)));
-
-    connect (this, SIGNAL (fetab_uncomment_selected_text (const QWidget*)),
-             f, SLOT (uncomment_selected_text (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_indent_selected_text (const QWidget*)),
-             f, SLOT (indent_selected_text (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_unindent_selected_text (const QWidget*)),
-             f, SLOT (unindent_selected_text (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_smart_indent_line_or_selected_text (const QWidget*)),
-             f, SLOT (smart_indent_line_or_selected_text (const QWidget*)));
-
-    connect (this,
-             SIGNAL (fetab_convert_eol (const QWidget*, QsciScintilla::EolMode)),
-             f, SLOT (convert_eol (const QWidget*, QsciScintilla::EolMode)));
-
-    connect (this, SIGNAL (fetab_goto_line (const QWidget*, int)),
-             f, SLOT (goto_line (const QWidget*, int)));
-
-    connect (this, SIGNAL (fetab_move_match_brace (const QWidget*, bool)),
-             f, SLOT (move_match_brace (const QWidget*, bool)));
-
-    connect (this, SIGNAL (fetab_completion (const QWidget*)),
-             f, SLOT (show_auto_completion (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_set_focus (const QWidget*)),
-             f, SLOT (set_focus (const QWidget*)));
-
-    connect (this, SIGNAL (fetab_insert_debugger_pointer (const QWidget*, int)),
-             f, SLOT (insert_debugger_pointer (const QWidget*, int)));
-
-    connect (this, SIGNAL (fetab_delete_debugger_pointer (const QWidget*, int)),
-             f, SLOT (delete_debugger_pointer (const QWidget*, int)));
-
-    connect (f, SIGNAL (debug_quit_signal (void)),
-             main_win (), SLOT (debug_quit (void)));
-
-    connect (this, SIGNAL (fetab_do_breakpoint_marker (bool, const QWidget*,
-                                                       int, const QString&)),
-             f, SLOT (do_breakpoint_marker (bool, const QWidget*, int,
-                                            const QString&)));
+    connect (this, &file_editor::fetab_recover_from_exit,
+             f, &file_editor_tab::recover_from_exit);
+
+    connect (this, &file_editor::fetab_set_directory,
+             f, &file_editor_tab::set_current_directory);
+
+    connect (this, &file_editor::fetab_zoom_in,
+             f, &file_editor_tab::zoom_in);
+    connect (this, &file_editor::fetab_zoom_out,
+             f, &file_editor_tab::zoom_out);
+    connect (this, &file_editor::fetab_zoom_normal,
+             f, &file_editor_tab::zoom_normal);
+
+    connect (this, &file_editor::fetab_context_help,
+             f, &file_editor_tab::context_help);
+
+    connect (this, &file_editor::fetab_context_edit,
+             f, &file_editor_tab::context_edit);
+
+    connect (this, QOverload<const QWidget*>::of (&file_editor::fetab_save_file),
+             f, QOverload<const QWidget*>::of (&file_editor_tab::save_file));
+
+    connect (this, &file_editor::fetab_save_file_as,
+             f, QOverload<const QWidget *>::of (&file_editor_tab::save_file_as));
+
+    connect (this, &file_editor::fetab_print_file,
+             f, &file_editor_tab::print_file);
+
+    connect (this, &file_editor::fetab_run_file,
+             f, &file_editor_tab::run_file);
+
+    connect (this, &file_editor::fetab_context_run,
+             f, &file_editor_tab::context_run);
+
+    connect (this, &file_editor::fetab_toggle_bookmark,
+             f, &file_editor_tab::toggle_bookmark);
+
+    connect (this, &file_editor::fetab_next_bookmark,
+             f, &file_editor_tab::next_bookmark);
+
+    connect (this, &file_editor::fetab_previous_bookmark,
+             f, &file_editor_tab::previous_bookmark);
+
+    connect (this, &file_editor::fetab_remove_bookmark,
+             f, &file_editor_tab::remove_bookmark);
+
+    connect (this, &file_editor::fetab_toggle_breakpoint,
+             f, &file_editor_tab::toggle_breakpoint);
+
+    connect (this, &file_editor::fetab_next_breakpoint,
+             f, &file_editor_tab::next_breakpoint);
+
+    connect (this, &file_editor::fetab_previous_breakpoint,
+             f, &file_editor_tab::previous_breakpoint);
+
+    connect (this, &file_editor::fetab_remove_all_breakpoints,
+             f, &file_editor_tab::remove_all_breakpoints);
+
+    connect (this, &file_editor::fetab_scintilla_command,
+             f, &file_editor_tab::scintilla_command);
+
+    connect (this, &file_editor::fetab_comment_selected_text,
+             f, &file_editor_tab::comment_selected_text);
+
+    connect (this, &file_editor::fetab_uncomment_selected_text,
+             f, &file_editor_tab::uncomment_selected_text);
+
+    connect (this, &file_editor::fetab_indent_selected_text,
+             f, &file_editor_tab::indent_selected_text);
+
+    connect (this, &file_editor::fetab_unindent_selected_text,
+             f, &file_editor_tab::unindent_selected_text);
+
+    connect (this, &file_editor::fetab_smart_indent_line_or_selected_text,
+             f, &file_editor_tab::smart_indent_line_or_selected_text);
+
+    connect (this, &file_editor::fetab_convert_eol,
+             f, &file_editor_tab::convert_eol);
+
+    connect (this, &file_editor::fetab_goto_line,
+             f, &file_editor_tab::goto_line);
+
+    connect (this, &file_editor::fetab_move_match_brace,
+             f, &file_editor_tab::move_match_brace);
+
+    connect (this, &file_editor::fetab_completion,
+             f, &file_editor_tab::show_auto_completion);
+
+    connect (this, &file_editor::fetab_set_focus,
+             f, &file_editor_tab::set_focus);
+
+    connect (this, &file_editor::fetab_insert_debugger_pointer,
+             f, &file_editor_tab::insert_debugger_pointer);
+
+    connect (this, &file_editor::fetab_delete_debugger_pointer,
+             f, &file_editor_tab::delete_debugger_pointer);
+
+    connect (this, &file_editor::fetab_do_breakpoint_marker,
+             f, &file_editor_tab::do_breakpoint_marker);
+
+    connect (this, &file_editor::update_gui_lexer_signal,
+             f, &file_editor_tab::update_lexer_settings);
+
+    // FIXME: What was the intent here?  The
+    // main_window::handle_show_doc slot no longer exists.
+    //
+    // connect (f->qsci_edit_area (), SIGNAL (show_doc_signal (const QString&)),
+    //          main_win (), SLOT (handle_show_doc (const QString&)));
+
+    // Convert other signals from the edit area and tab to editor signals.
+
+    connect (f->qsci_edit_area (), &octave_qscintilla::execute_command_in_terminal_signal,
+             this, &file_editor::execute_command_in_terminal_signal);
+
+    connect (f->qsci_edit_area (), &octave_qscintilla::focus_console_after_command_signal,
+             this, &file_editor::focus_console_after_command_signal);
+
+    connect (f, &file_editor_tab::run_file_signal,
+             this, &file_editor::run_file_signal);
+
+    connect (f, &file_editor_tab::edit_mfile_request,
+             this, &file_editor::edit_mfile_request);
+
+    connect (f, &file_editor_tab::debug_quit_signal,
+             this, &file_editor::debug_quit_signal);
 
     // Any interpreter_event signal from a file_editor_tab_widget is
     // handled the same as for the parent main_window object.
 
-    connect (f, SIGNAL (interpreter_event (const fcn_callback&)),
-             this, SIGNAL (interpreter_event (const fcn_callback&)));
-
-    connect (f, SIGNAL (interpreter_event (const meth_callback&)),
-             this, SIGNAL (interpreter_event (const meth_callback&)));
+    connect (f, QOverload<const fcn_callback&>::of (&file_editor_tab::interpreter_event),
+             this, QOverload<const fcn_callback&>::of (&file_editor::interpreter_event));
+
+    connect (f, QOverload<const meth_callback&>::of (&file_editor_tab::interpreter_event),
+             this, QOverload<const meth_callback&>::of (&file_editor::interpreter_event));
 
     return f;
   }
--- a/libgui/src/m-editor/file-editor.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/m-editor/file-editor.h	Sun May 16 09:44:35 2021 +0200
@@ -90,7 +90,7 @@
 
     file_editor (QWidget *p, base_qobject& oct_qobj);
 
-    ~file_editor (void);
+    ~file_editor (void) = default;
 
     QMenu * get_mru_menu (void) { return m_mru_file_menu; }
 
@@ -98,6 +98,8 @@
 
     QToolBar * toolbar (void) { return m_tool_bar; }
 
+    QMenuBar * menubar (void) { return m_menu_bar; }
+
     void insert_global_actions (QList<QAction*>);
 
     enum shared_actions_idx
@@ -112,9 +114,6 @@
       SELECTALL_ACTION
     };
 
-    void handle_enter_debug_mode (void);
-    void handle_exit_debug_mode (void);
-
     void check_actions (void);
     void empty_script (bool startup, bool visible);
     void restore_session (gui_settings *settings);
@@ -172,9 +171,19 @@
     void request_open_file_external (const QString& file_name, int line);
     void file_loaded_signal (void);
 
-    void editor_tabs_changed_signal (bool);
+    void editor_tabs_changed_signal (bool, bool);
     void request_dbcont_signal (void);
 
+    void enter_debug_mode_signal (void);
+    void exit_debug_mode_signal (void);
+
+    void update_gui_lexer_signal (bool);
+    void execute_command_in_terminal_signal (const QString&);
+    void focus_console_after_command_signal (void);
+    void run_file_signal (const QFileInfo&);
+    void edit_mfile_request (const QString&, const QString&, const QString&, int);
+    void debug_quit_signal (void);
+
   public slots:
 
     void activate (void);
@@ -184,10 +193,14 @@
     bool check_closing (void);
     void handle_tab_ready_to_close (void);
 
+    void handle_enter_debug_mode (void);
+    void handle_exit_debug_mode (void);
+
     void request_new_file (const QString& commands);
     void request_close_file (bool);
     void request_close_all_files (bool);
     void request_close_other_files (bool);
+    void copy_full_file_path (bool);
     void request_mru_open_file (QAction *action);
     void request_print_file (bool);
 
@@ -444,6 +457,7 @@
 
     bool m_copy_action_enabled;
     bool m_undo_action_enabled;
+    bool m_is_octave_file;
 
     QMenu *m_edit_menu;
     QMenu *m_edit_cmd_menu;
--- a/libgui/src/m-editor/find-dialog.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/m-editor/find-dialog.cc	Sun May 16 09:44:35 2021 +0200
@@ -144,23 +144,23 @@
     _search_selection_check_box = new QCheckBox (tr ("Search se&lection"));
     _search_selection_check_box->setCheckable (true);
 
-    connect (_find_next_button,   SIGNAL (clicked ()),
-             this,                SLOT (find_next ()));
-    connect (_find_prev_button,   SIGNAL (clicked ()),
-             this,                SLOT (find_prev ()));
-    connect (_more_button,        SIGNAL (toggled (bool)),
-             _extension,          SLOT (setVisible (bool)));
-    connect (_replace_button,     SIGNAL (clicked ()),
-             this,                SLOT (replace ()));
-    connect (_replace_all_button, SIGNAL (clicked ()),
-             this,                SLOT (replace_all ()));
-    connect (_backward_check_box, SIGNAL (stateChanged (int)),
-             this,                SLOT (handle_backward_search_changed (int)));
-    connect (_button_box,         SIGNAL (rejected ()),
-             this,                SLOT (close ()));
+    connect (_find_next_button, &QPushButton::clicked,
+             this, &find_dialog::find_next);
+    connect (_find_prev_button, &QPushButton::clicked,
+             this, &find_dialog::find_prev);
+    connect (_more_button, &QPushButton::toggled,
+             _extension, &QWidget::setVisible);
+    connect (_replace_button, &QPushButton::clicked,
+             this, &find_dialog::replace);
+    connect (_replace_all_button, &QPushButton::clicked,
+             this, &find_dialog::replace_all);
+    connect (_backward_check_box, &QCheckBox::stateChanged,
+             this, &find_dialog::handle_backward_search_changed);
+    connect (_button_box, &QDialogButtonBox::rejected,
+             this, &find_dialog::close);
 
-    connect (_search_selection_check_box, SIGNAL (stateChanged (int)),
-             this,                        SLOT (handle_sel_search_changed (int)));
+    connect (_search_selection_check_box, &QCheckBox::stateChanged,
+             this, &find_dialog::handle_sel_search_changed);
 
     QVBoxLayout *extension_layout = new QVBoxLayout ();
     extension_layout->setMargin (0);
@@ -212,8 +212,8 @@
     _edit_area = edit_area;
     _search_selection_check_box->setEnabled (edit_area->hasSelectedText ());
 
-    connect (_edit_area, SIGNAL (copyAvailable (bool)),
-             this,       SLOT (handle_selection_changed (bool)),
+    connect (_edit_area, &octave_qscintilla::copyAvailable,
+             this, &find_dialog::handle_selection_changed,
              Qt::UniqueConnection);
   }
 
@@ -398,21 +398,7 @@
         int lbeg, lend, cbeg, cend;
         _edit_area->getSelection (&lbeg,&cbeg,&lend,&cend);
         if (lbeg == lend)
-#if defined (HAVE_QCOMBOBOX_SETCURRENTTEXT)
           _search_line_edit->setCurrentText (_edit_area->selectedText ());
-#else
-          if (_search_line_edit->isEditable ())
-            {
-              _search_line_edit->setEditText (_edit_area->selectedText ());
-            }
-          else
-            {
-              int i = _search_line_edit->findText (_edit_area->selectedText ());
-
-              if (i > -1)
-                _search_line_edit->setCurrentIndex (i);
-            }
-#endif
       }
 
     // set focus to "Find what" and select all text
--- a/libgui/src/m-editor/octave-qscintilla.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/m-editor/octave-qscintilla.cc	Sun May 16 09:44:35 2021 +0200
@@ -59,6 +59,7 @@
 #include "octave-qobject.h"
 #include "octave-qscintilla.h"
 #include "shortcut-manager.h"
+#include "workspace-model.h"
 
 #include "builtin-defun-decls.h"
 #include "cmd-edit.h"
@@ -110,20 +111,19 @@
   }
 
   octave_qscintilla::octave_qscintilla (QWidget *p, base_qobject& oct_qobj)
-    : QsciScintilla (p), m_octave_qobj (oct_qobj), m_word_at_cursor (),
-      m_selection (), m_selection_replacement (), m_selection_line (-1),
-      m_selection_col (-1), m_indicator_id (1)
+    : QsciScintilla (p), m_octave_qobj (oct_qobj), m_debug_mode (false),
+      m_word_at_cursor (), m_selection (), m_selection_replacement (),
+      m_selection_line (-1), m_selection_col (-1), m_indicator_id (1),
+      m_tooltip_font (QToolTip::font ())
   {
-    connect (this, SIGNAL (textChanged (void)),
-             this, SLOT (text_changed (void)));
+    connect (this, &octave_qscintilla::textChanged,
+             this, &octave_qscintilla::text_changed);
 
-    connect (this, SIGNAL (cursorPositionChanged (int, int)),
-             this, SLOT (cursor_position_changed (int, int)));
+    connect (this, &octave_qscintilla::cursorPositionChanged,
+             this, &octave_qscintilla::cursor_position_changed);
 
-    connect (this, SIGNAL (ctx_menu_run_finished_signal (bool, int, QTemporaryFile*,
-                                                         QTemporaryFile*, bool, bool)),
-             this, SLOT (ctx_menu_run_finished (bool, int, QTemporaryFile*,
-                                                QTemporaryFile*, bool, bool)),
+    connect (this, &octave_qscintilla::ctx_menu_run_finished_signal,
+             this, &octave_qscintilla::ctx_menu_run_finished,
              Qt::QueuedConnection);
 
     // clear scintilla edit shortcuts that are handled by the editor
@@ -234,7 +234,7 @@
   void octave_qscintilla::set_selection_marker_color (const QColor& c)
   {
     QColor ic = c;
-    ic.setAlphaF (0.25);
+    ic.setAlphaF (0.45);
     setIndicatorForegroundColor (ic, m_indicator_id);
     setIndicatorOutlineColor (ic, m_indicator_id);
 
@@ -290,12 +290,12 @@
             if (! m_word_at_cursor.isEmpty ())
               {
                 context_menu->addAction (tr ("Help on") + ' ' + m_word_at_cursor,
-                                         this, SLOT (contextmenu_help (bool)));
+                                         this, &octave_qscintilla::contextmenu_help);
                 context_menu->addAction (tr ("Documentation on")
                                          + ' ' + m_word_at_cursor,
-                                         this, SLOT (contextmenu_doc (bool)));
+                                         this, &octave_qscintilla::contextmenu_doc);
                 context_menu->addAction (tr ("Edit") + ' ' + m_word_at_cursor,
-                                         this, SLOT (contextmenu_edit (bool)));
+                                         this, &octave_qscintilla::contextmenu_edit);
               }
           }
       }
@@ -310,7 +310,7 @@
 
         QAction *act
           = context_menu->addAction (tr ("dbstop if ..."), this,
-                                     SLOT (contextmenu_break_condition (bool)));
+                                     &octave_qscintilla::contextmenu_break_condition);
         act->setData (local_pos);
       }
 #endif
@@ -381,6 +381,22 @@
     markerDeleteAll (marker::selection);
   }
 
+  QString octave_qscintilla::eol_string (void)
+  {
+    switch (eolMode ())
+      {
+      case QsciScintilla::EolWindows:
+        return ("\r\n");
+      case QsciScintilla::EolMac:
+        return ("\r");
+      case QsciScintilla::EolUnix:
+        return ("\n");
+      }
+
+    // Last resort, if the above goes wrong (should never happen)
+    return ("\r\n");
+  }
+
   // Function returning the true cursor position where the tab length
   // is taken into account.
   void octave_qscintilla::get_current_position (int *pos, int *line, int *col)
@@ -860,7 +876,7 @@
 
     // Add commands to the history
     emit interpreter_event
-      ([tmp_hist] (interpreter& interp)
+      ([=] (interpreter& interp)
         {
           // INTERPRETER THREAD
 
@@ -877,7 +893,7 @@
 
     // Let the interpreter execute the tmp file
     emit interpreter_event
-      ([this, tmp_file, tmp_hist, show_dbg_file] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -900,14 +916,14 @@
              // Do the job
              interp.source_file (file);
            }
-         catch (const execution_exception& e)
+         catch (const execution_exception& ee)
            {
              // Catch errors otherwise the rest of the interpreter
              // will not be executed (cleaning up).
 
              // New error message and error stack
-             QString new_msg = QString::fromStdString (e.message ());
-             std::list<frame_info> stack = e.stack_info ();
+             QString new_msg = QString::fromStdString (ee.message ());
+             std::list<frame_info> stack = ee.stack_info ();
 
              // Remove line and column from first line of error message only
              // if it is related to the tmp itself, i.e. only if the
@@ -957,11 +973,11 @@
                                                 dbg, auto_repeat);
 
              // New exception with updated message and stack
-             octave::execution_exception ee (e.err_type (),e.identifier (),
-                                             new_msg.toStdString (), stack);
+             execution_exception nee (ee.err_type (), ee.identifier (),
+                                      new_msg.toStdString (), stack);
 
              // Throw
-             throw (ee);
+             throw (nee);
            }
 
          // Clean up
@@ -1085,6 +1101,75 @@
     QToolTip::showText (global_pos, msg);
   }
 
+  void octave_qscintilla::replace_all (const QString& o_str, const QString& n_str,
+                                       bool re, bool cs, bool wo)
+  {
+    // get the resulting cursor position
+    int pos, line, col, nline, ncol;
+    get_current_position (&pos, &line, &col);
+
+    // remember first visible line for restoring the view afterwards
+    int first_line = firstVisibleLine ();
+
+    // search for first occurrence of the detected word
+    bool find_result_available = findFirst (o_str, re, cs, wo,
+                                            false, true, 0, 0);
+    // replace and find more occurrences in a loop
+    beginUndoAction ();
+    while (find_result_available)
+      {
+        // findNext doesn't work properly if the length of the replacement
+        // text is different from the original
+        replace (n_str);
+        get_current_position (&pos, &nline, &ncol);
+
+        find_result_available = findFirst (o_str, re, cs, wo,
+                                           false, true, nline, ncol);
+      }
+    endUndoAction ();
+
+      // restore the visible area
+      setFirstVisibleLine (first_line);
+
+      // fix cursor column if outside of new line length
+      int eol_len = eol_string ().length ();
+      if (line == lines () - 1)
+        eol_len = 0;
+      const int col_max = text (line).length () - eol_len;
+      if (col_max < col)
+        col = col_max;
+
+      setCursorPosition (line, col);
+  }
+
+  bool octave_qscintilla::event (QEvent *e)
+  {
+    if (m_debug_mode && e->type() == QEvent::ToolTip)
+      {
+        QHelpEvent *help_e = static_cast<QHelpEvent *>(e);
+        QString variable = wordAtPoint (help_e->pos());
+        QStringList symbol_names
+            = m_octave_qobj.get_workspace_model ()->get_symbol_names ();
+        int symbol_idx = symbol_names.indexOf (variable);
+        if (symbol_idx > -1)
+          {
+            QStringList symbol_values
+                = m_octave_qobj.get_workspace_model ()->get_symbol_values ();
+            QToolTip::showText (help_e->globalPos(), variable
+                                + " = " + symbol_values.at (symbol_idx));
+          }
+        else
+          {
+            QToolTip::hideText();
+            e->ignore();
+          }
+
+        return true;
+      }
+
+    return QsciScintilla::event(e);
+  }
+
   void octave_qscintilla::keyPressEvent (QKeyEvent *key_event)
   {
     if (m_selection.isEmpty ())
@@ -1096,59 +1181,8 @@
 
         if (key == Qt::Key_Return && modifiers == Qt::ShiftModifier)
           {
-            // get the resulting cursor position
-            // (required if click was beyond a line ending)
-            int pos, line, col;
-            get_current_position (&pos, &line, &col);
-
-            // remember first visible line for restoring the view afterwards
-            int first_line = firstVisibleLine ();
-
-            // search for first occurrence of the detected word
-            bool find_result_available
-              = findFirst (m_selection,
-                           false,   // no regexp
-                           true,    // case sensitive
-                           true,    // whole words only
-                           false,   // do not wrap
-                           true,    // forward
-                           0, 0,    // from the beginning
-                           false
-#if defined (HAVE_QSCI_VERSION_2_6_0)
-                           , true
-#endif
-                          );
-
-            while (find_result_available)
-              {
-                replace (m_selection_replacement);
-
-                // FIXME: is this the right thing to do?  findNext doesn't
-                // work properly if the length of the replacement text is
-                // different from the original.
-
-                int new_line, new_col;
-                get_current_position (&pos, &new_line, &new_col);
-
-                find_result_available
-                  = findFirst (m_selection,
-                               false,   // no regexp
-                               true,    // case sensitive
-                               true,    // whole words only
-                               false,   // do not wrap
-                               true,    // forward
-                               new_line, new_col,    // from new pos
-                               false
-#if defined (HAVE_QSCI_VERSION_2_6_0)
-                               , true
-#endif
-                              );
-              }
-
-            // restore the visible area of the file, the cursor position,
-            // and the selection
-            setFirstVisibleLine (first_line);
-            setCursorPosition (line, col);
+            replace_all (m_selection, m_selection_replacement,
+                         false, true, true);
 
             // Clear the selection.
             set_word_selection ();
@@ -1291,6 +1325,24 @@
         e->ignore();
       }
   }
+
+  void octave_qscintilla::handle_enter_debug_mode (void)
+  {
+    // Set tool tip font to the lexers default font
+    m_tooltip_font = QToolTip::font ();   // Save current font
+    QToolTip::setFont (lexer ()->defaultFont ());
+
+    m_debug_mode = true;
+  }
+
+  void octave_qscintilla::handle_exit_debug_mode (void)
+  {
+    m_debug_mode = false;
+
+    // Reset tool tip font
+    QToolTip::setFont (m_tooltip_font);
+  }
+
 }
 
 #endif
--- a/libgui/src/m-editor/octave-qscintilla.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/m-editor/octave-qscintilla.h	Sun May 16 09:44:35 2021 +0200
@@ -65,6 +65,7 @@
     void get_global_textcursor_pos (QPoint *global_pos, QPoint *local_pos);
     bool get_actual_word (void);
     void clear_selection_markers (void);
+    QString eol_string (void);
     void get_current_position (int *pos, int *line, int *col);
     QStringList comment_string (bool comment = true);
     int get_style (int pos = -1);
@@ -80,6 +81,9 @@
 
     void set_selection_marker_color (const QColor& c);
 
+    void replace_all (const QString& o_str, const QString& n_str,
+                      bool re, bool cs, bool wo);
+
   signals:
 
     void execute_command_in_terminal_signal (const QString&);
@@ -90,11 +94,18 @@
     void show_doc_signal (const QString&);
     void context_menu_break_condition_signal (int);
     void context_menu_break_once (int);
-    void interpreter_event (const meth_callback& meth);
     void ctx_menu_run_finished_signal (bool, int, QTemporaryFile*,
                                        QTemporaryFile*, bool, bool);
     void focus_console_after_command_signal (void);
 
+    void interpreter_event (const fcn_callback& fcn);
+    void interpreter_event (const meth_callback& meth);
+
+  public slots:
+
+    void handle_enter_debug_mode (void);
+    void handle_exit_debug_mode (void);
+
   private slots:
 
     void ctx_menu_run_finished (bool, int, QTemporaryFile*, QTemporaryFile*,
@@ -119,6 +130,8 @@
 
     void show_replace_action_tooltip (void);
 
+    bool event (QEvent *e);
+
     void keyPressEvent (QKeyEvent *e);
 
     void dragEnterEvent (QDragEnterEvent *e);
@@ -130,6 +143,8 @@
 
     base_qobject& m_octave_qobj;
 
+    bool m_debug_mode;
+
     QString m_word_at_cursor;
 
     QString m_selection;
@@ -137,6 +152,8 @@
     int m_selection_line;
     int m_selection_col;
     int m_indicator_id;
+
+    QFont m_tooltip_font;
   };
 }
 
--- a/libgui/src/main-window.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/main-window.cc	Sun May 16 09:44:35 2021 +0200
@@ -69,6 +69,7 @@
 #include "main-window.h"
 #include "news-reader.h"
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 #include "settings-dialog.h"
 #include "shortcut-manager.h"
 #include "welcome-wizard.h"
@@ -94,32 +95,22 @@
 
 namespace octave
 {
-  static file_editor_interface *
-  create_default_editor (QWidget *p, base_qobject& oct_qobj)
-  {
-#if defined (HAVE_QSCINTILLA)
-    return new file_editor (p, oct_qobj);
-#else
-    octave_unused_parameter (p);
-    octave_unused_parameter (oct_qobj);
-
-    return 0;
-#endif
-  }
-
   main_window::main_window (base_qobject& oct_qobj)
     : QMainWindow (), m_octave_qobj (oct_qobj),
-      m_workspace_model (nullptr),
-      m_status_bar (nullptr), m_command_window (nullptr),
-      m_history_window (nullptr), m_file_browser_window (nullptr),
-      m_doc_browser_window (nullptr), m_editor_window (nullptr),
-      m_workspace_window (nullptr), m_variable_editor_window (nullptr),
+      m_status_bar (nullptr),
+      m_command_window (nullptr),
+      m_history_window (nullptr),
+      m_file_browser_window (nullptr),
+      m_editor_window (nullptr),
+      m_workspace_window (nullptr),
       m_external_editor (new external_editor_interface (this, m_octave_qobj)),
       m_active_editor (m_external_editor), m_settings_dlg (nullptr),
       m_find_files_dlg (nullptr), m_set_path_dlg (nullptr),
       m_release_notes_window (nullptr), m_community_news_window (nullptr),
       m_clipboard (QApplication::clipboard ()),
-      m_prevent_readline_conflicts (true), m_suppress_dbg_location (true),
+      m_prevent_readline_conflicts (true),
+      m_prevent_readline_conflicts_menu (false),
+      m_suppress_dbg_location (true),
       m_closing (false), m_file_encoding (QString ())
   {
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
@@ -166,24 +157,115 @@
 
     construct_central_widget ();
 
-    m_workspace_model = new workspace_model (m_octave_qobj);
-    m_status_bar = new QStatusBar ();
+    m_status_bar = new QStatusBar (this);
+    m_profiler_status_indicator = new led_indicator ();
+    QLabel *text = new QLabel (tr ("Profiler"));
+    m_status_bar->addPermanentWidget (text);
+    m_status_bar->addPermanentWidget (m_profiler_status_indicator);
+
     m_command_window = new terminal_dock_widget (this, m_octave_qobj);
-    m_history_window = new history_dock_widget (this, m_octave_qobj);
-    m_file_browser_window = new files_dock_widget (this, m_octave_qobj);
-    m_doc_browser_window = new documentation_dock_widget (this, m_octave_qobj);
-    m_editor_window = create_default_editor (this, m_octave_qobj);
-    m_variable_editor_window = new variable_editor (this, m_octave_qobj);
-    m_workspace_window = new workspace_view (this, m_octave_qobj);
+
+    make_dock_widget_connections (m_command_window);
+
+    connect (this, &main_window::settings_changed,
+             m_command_window, &terminal_dock_widget::notice_settings);
+
+    m_doc_browser_window = m_octave_qobj.documentation_widget (this);
+
+    make_dock_widget_connections (m_doc_browser_window);
+
+    m_file_browser_window = m_octave_qobj.file_browser_widget (this);
+
+    make_dock_widget_connections (m_file_browser_window);
+
+    connect (m_file_browser_window, &files_dock_widget::open_file,
+             this, QOverload<const QString&>::of (&main_window::open_file_signal));
+    connect (m_file_browser_window,
+             &files_dock_widget::displayed_directory_changed,
+             this, &main_window::set_current_working_directory);
+    connect (m_file_browser_window, &files_dock_widget::modify_path_signal,
+             this, &main_window::modify_path);
+    connect (m_file_browser_window, &files_dock_widget::run_file_signal,
+             this, &main_window::run_file_in_terminal);
+
+    m_history_window = m_octave_qobj.history_widget (this);
+
+    make_dock_widget_connections (m_history_window);
+
+    connect (m_history_window, &history_dock_widget::command_create_script,
+             this, &main_window::new_file_signal);
+
+    connect (m_history_window, &history_dock_widget::information,
+             this, &main_window::report_status_message);
+
+    connect (m_history_window, &history_dock_widget::command_double_clicked,
+             this, &main_window::execute_command_in_terminal);
+
+    m_workspace_window = m_octave_qobj.workspace_widget (this);
+
+    make_dock_widget_connections (m_workspace_window);
+
+    connect (m_workspace_window, &workspace_view::command_requested,
+             this, &main_window::execute_command_in_terminal);
+
+    connect (m_workspace_window, &workspace_view::edit_variable_signal,
+             this, &main_window::edit_variable);
+
+#if defined (HAVE_QSCINTILLA)
+    file_editor *editor = new file_editor (this, m_octave_qobj);
+
+    make_dock_widget_connections (editor);
+
+    connect (editor, &file_editor::request_settings_dialog,
+             this, QOverload<const QString&>::of (&main_window::process_settings_dialog_request));
+
+    connect (editor, &file_editor::request_dbcont_signal,
+             this, &main_window::debug_continue);
+
+    connect (this, &main_window::update_gui_lexer_signal,
+             editor, &file_editor::update_gui_lexer_signal);
+
+    connect (editor, &file_editor::execute_command_in_terminal_signal,
+             this, &main_window::execute_command_in_terminal);
+
+    connect (editor, &file_editor::focus_console_after_command_signal,
+             this, &main_window::focus_console_after_command);
+
+    connect (editor, &file_editor::run_file_signal,
+             this, &main_window::run_file_in_terminal);
+
+    connect (editor, &file_editor::edit_mfile_request,
+             this, &main_window::handle_edit_mfile_request);
+
+    connect (editor, &file_editor::debug_quit_signal,
+             this, &main_window::debug_quit);
+
+    m_editor_window = editor;
+#else
+    m_editor_window = nullptr;
+#endif
+
+    m_variable_editor_window = m_octave_qobj.variable_editor_widget (this);
+
+    make_dock_widget_connections (m_variable_editor_window);
+
+    connect (m_variable_editor_window, &variable_editor::command_signal,
+             this, &main_window::execute_command_in_terminal);
 
     m_previous_dock = m_command_window;
 
     // Set active editor depending on editor window.  If the latter is
     // not initialized (qscintilla not present), use the external editor.
     if (m_editor_window)
-      m_active_editor = m_editor_window;
+      {
+        m_editor_menubar = m_editor_window->menubar ();
+        m_active_editor = m_editor_window;
+      }
     else
-      m_active_editor = m_external_editor;
+      {
+        m_editor_menubar = nullptr;
+        m_active_editor = m_external_editor;
+      }
 
 #if defined (HAVE_QGUIAPPLICATION_SETDESKTOPFILENAME)
     QGuiApplication::setDesktopFileName ("org.octave.Octave.desktop");
@@ -230,33 +312,50 @@
 
     init_terminal_size ();
 
-    // Connect signals for changes in visibility now before window is
-    // shown.
-
-    connect_visibility_changed ();
+    emit init_window_menu ();
+
+#if defined (HAVE_QSCINTILLA)
+    m_editor_window->enable_menu_shortcuts (false);
+#endif
 
     focus_command_window ();
   }
 
   main_window::~main_window (void)
   {
-    // Destroy the terminal first so that STDERR stream is redirected back
-    // to its original pipe to capture error messages at exit.
-
-    delete m_editor_window;     // first one for dialogs of modified editor-tabs
-    delete m_external_editor;
-    delete m_command_window;
-    delete m_workspace_window;
-    delete m_doc_browser_window;
-    delete m_file_browser_window;
-    delete m_history_window;
-    delete m_status_bar;
-    delete m_workspace_model;
-    delete m_variable_editor_window;
-
-    delete m_find_files_dlg;
-    delete m_release_notes_window;
-    delete m_community_news_window;
+    // Prevent floating dock widgets from being deleted.
+
+    if (m_history_window->isFloating ())
+      m_history_window.clear ();
+
+    if (m_file_browser_window->isFloating ())
+      m_file_browser_window.clear ();
+
+    if (m_doc_browser_window->isFloating ())
+      m_doc_browser_window.clear ();
+
+#if 0
+    if (m_editor_window->isFloating ())
+      m_editor_window.clear ();
+#endif
+
+    if (m_workspace_window->isFloating ())
+      m_workspace_window.clear ();
+
+    if (m_variable_editor_window->isFloating ())
+      m_variable_editor_window.clear ();
+  }
+
+  void main_window::make_dock_widget_connections (octave_dock_widget *dw)
+  {
+    connect (this, &main_window::init_window_menu,
+             dw, &octave_dock_widget::init_window_menu_entry);
+
+    connect (this, &main_window::settings_changed,
+             dw, &octave_dock_widget::handle_settings);
+
+    connect (this, &main_window::active_dock_changed,
+             dw, &octave_dock_widget::handle_active_dock_changed);
   }
 
   bool main_window::command_window_has_focus (void) const
@@ -312,10 +411,18 @@
   // catch focus changes and determine the active dock widget
   void main_window::focus_changed (QWidget *, QWidget *new_widget)
   {
-    // If there is no new widget (e.g., when pressing <alt> and the global
-    // menu gets active), we can return immediately
-    if (! new_widget)
-      return;
+    // If there is no new widget or the new widget is a menu bar
+    // (when pressing <alt>), we can return immediately and reset the
+    // focus to the previous widget
+    if (! new_widget
+          || (new_widget == menuBar ())
+          || (new_widget == m_editor_menubar))
+      {
+        if (m_active_dock)
+          m_active_dock->setFocus ();
+
+        return;
+      }
 
     octave_dock_widget *dock = nullptr;
     QWidget *w_new = new_widget;  // get a copy of new focus widget
@@ -347,9 +454,12 @@
         count++;  // Limited number of trials
       }
 
-    // editor needs extra handling
+    // editor and terminal needs extra handling
     octave_dock_widget *edit_dock_widget
       = static_cast<octave_dock_widget *> (m_editor_window);
+    octave_dock_widget *cmd_dock_widget
+      = static_cast<octave_dock_widget *> (m_command_window);
+
     // if new dock has focus, emit signal and store active focus
     // except editor changes to a dialog (dock=0)
     if ((dock || m_active_dock != edit_dock_widget) && (dock != m_active_dock))
@@ -364,14 +474,51 @@
               dock->set_predecessor_widget (m_active_dock);
           }
 
+        // Check whether editor loses or gains focus
+        int editor = 0;
         if (edit_dock_widget == dock)
-          emit editor_focus_changed (true);
+          {
+            emit editor_focus_changed (true);
+            editor = 1;
+          }
         else if (edit_dock_widget == m_active_dock)
-          emit editor_focus_changed (false);
+          {
+            emit editor_focus_changed (false);
+            editor = -1;
+          }
+
+        // Check whether terminal loses or gains focus
+        int cmd_involved = 0;
+        if (cmd_dock_widget == dock)
+          cmd_involved = 1;
+        else if (cmd_dock_widget == m_active_dock)
+          cmd_involved = -1;
+
+        // If we have to take care of Alt+? accelerators of the main
+        // window, take result of test for terminal widget above
+        int command = 0;
+        if (m_prevent_readline_conflicts_menu)
+          command = cmd_involved;
+
+        // If editor or command gets/looses focus, disable/enable
+        // main menu accelerators (Alt + ?)
+        if (editor || command)
+          {
+            int sum = editor + command;
+            if (sum > 0)
+              disable_menu_shortcuts (true);
+            else if (sum < 0)
+              disable_menu_shortcuts (false);
+          }
 
         if (m_active_dock)
           m_previous_dock = m_active_dock;
         m_active_dock = dock;
+
+        // En-/disable global shortcuts (preventing conflicts with
+        // readline. Do it here because it relies on m_active_dock
+        if (cmd_involved)
+          configure_shortcuts ();
       }
   }
 
@@ -405,7 +552,7 @@
     if (! file.isEmpty ())
       {
         emit interpreter_event
-          ([file] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -432,7 +579,7 @@
     if (! file.isEmpty ())
       {
         emit interpreter_event
-          ([file] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -454,7 +601,7 @@
         std::string file = file_arg.toStdString ();
 
         emit interpreter_event
-          ([file] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -532,7 +679,7 @@
     std::string new_name = new_name_arg.toStdString ();
 
     emit interpreter_event
-      ([old_name, new_name] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -558,7 +705,7 @@
                                  bool rm, bool subdirs)
   {
     emit interpreter_event
-      ([dir_list, rm, subdirs, this] (interpreter& interp)
+      ([=] (interpreter& interp)
       {
         // INTERPRETER THREAD
 
@@ -580,19 +727,6 @@
       });
   }
 
-  void main_window::new_file (const QString& commands)
-  {
-    emit new_file_signal (commands);
-  }
-
-  void main_window::open_file (const QString& file_name, int line)
-  {
-    if (line < 0)
-      emit open_file_signal (file_name);
-    else
-      emit open_file_signal (file_name, QString (), line);
-  }
-
   void main_window::edit_mfile (const QString& name, int line)
   {
     handle_edit_mfile_request (name, QString (), QString (), line);
@@ -656,7 +790,11 @@
           news = (tr ("The release notes file '%1' cannot be read.")
                   . arg (QString::fromStdString (news_file)));
 
-        m_release_notes_window = new QWidget;
+        // We want the window manager to give the release notes window
+        // a title bar, so don't its parent to main_window.  Do remember
+        // to delete in the main_window destructor.
+
+        m_release_notes_window = new QWidget (this);
 
         QTextBrowser *browser = new QTextBrowser (m_release_notes_window);
         browser->setText (news);
@@ -707,18 +845,18 @@
 
     reader->moveToThread (worker_thread);
 
-    connect (reader, SIGNAL (display_news_signal (const QString&)),
-             this, SLOT (display_community_news (const QString&)));
-
-    connect (worker_thread, SIGNAL (started (void)),
-             reader, SLOT (process (void)));
-
-    connect (reader, SIGNAL (finished (void)), worker_thread, SLOT (quit (void)));
-
-    connect (reader, SIGNAL (finished (void)), reader, SLOT (deleteLater (void)));
-
-    connect (worker_thread, SIGNAL (finished (void)),
-             worker_thread, SLOT (deleteLater (void)));
+    connect (reader, &news_reader::display_news_signal,
+             this, &main_window::display_community_news);
+
+    connect (worker_thread, &QThread::started,
+             reader, &news_reader::process);
+
+    connect (reader, &news_reader::finished, worker_thread, &QThread::quit);
+
+    connect (reader, &news_reader::finished, reader, &news_reader::deleteLater);
+
+    connect (worker_thread, &QThread::finished,
+             worker_thread, &QThread::deleteLater);
 
     worker_thread->start ();
   }
@@ -727,7 +865,11 @@
   {
     if (! m_community_news_window)
       {
-        m_community_news_window = new QWidget;
+        // We want the window manager to give the community news window
+        // a title bar, so don't its parent to main_window.  Do remember
+        // to delete in the main_window destructor.
+
+        m_community_news_window = new QWidget (this);
 
         QTextBrowser *browser = new QTextBrowser (m_community_news_window);
 
@@ -755,9 +897,7 @@
         QTextBrowser *browser
 
           = m_community_news_window->findChild<QTextBrowser *>("OctaveNews"
-#if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
                                                                , Qt::FindDirectChildrenOnly
-#endif
                                                               );
         if (browser)
           browser->setHtml (news);
@@ -807,8 +947,8 @@
 
     m_settings_dlg = new settings_dialog (this, m_octave_qobj, desired_tab);
 
-    connect (m_settings_dlg, SIGNAL (apply_new_settings (void)),
-             this, SLOT (request_reload_settings (void)));
+    connect (m_settings_dlg, &settings_dialog::apply_new_settings,
+             this, &main_window::request_reload_settings);
 
     m_settings_dlg->setModal (false);
     m_settings_dlg->setAttribute (Qt::WA_DeleteOnClose);
@@ -890,14 +1030,16 @@
     int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
     m_main_tool_bar->setIconSize (QSize (icon_size,icon_size));
 
-    if (settings->value (global_status_bar.key, global_status_bar.def).toBool ())
+    if (settings->value (global_status_bar).toBool ())
       m_status_bar->show ();
     else
       m_status_bar->hide ();
 
     m_prevent_readline_conflicts
-      = settings->value (sc_prevent_rl_conflicts.key,
-                         sc_prevent_rl_conflicts.def).toBool ();
+      = settings->value (sc_prevent_rl_conflicts).toBool ();
+
+    m_prevent_readline_conflicts_menu
+      = settings->value (sc_prevent_rl_conflicts_menu).toBool ();
 
     m_suppress_dbg_location
       = ! settings->value (cs_dbg_location).toBool ();
@@ -908,8 +1050,13 @@
     emit active_dock_changed (nullptr, m_active_dock); // update dock widget styles
 
     configure_shortcuts ();
-    set_global_shortcuts (m_active_dock == m_command_window);
-    disable_menu_shortcuts (m_active_dock == m_editor_window);
+
+    bool do_disable_main_menu_shortcuts
+      = (m_active_dock == m_editor_window)
+        || (m_prevent_readline_conflicts_menu
+            && (m_active_dock == m_command_window));
+
+    disable_menu_shortcuts (do_disable_main_menu_shortcuts);
 
     // Check whether some octave internal preferences have to be updated
     QString new_default_encoding
@@ -949,6 +1096,10 @@
       m_set_path_dlg->save_settings ();
 
     write_settings ();
+
+    // No more active dock, otherwise, focus_changed would try to set
+    // the focus to a dock widget that might not exist anymore
+    m_active_dock = nullptr;
   }
 
   void main_window::go_to_previous_widget (void)
@@ -1003,7 +1154,7 @@
     if (fileInfo.exists () && fileInfo.isDir ())
       {
         emit interpreter_event
-          ([xdir] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -1038,7 +1189,7 @@
   void main_window::execute_command_in_terminal (const QString& command)
   {
     emit interpreter_event
-      ([command] (void)
+      ([=] (void)
        {
          // INTERPRETER THREAD
 
@@ -1057,7 +1208,7 @@
   void main_window::run_file_in_terminal (const QFileInfo& info)
   {
     emit interpreter_event
-      ([info] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1119,10 +1270,6 @@
     m_debug_step_over->setEnabled (true);
     m_debug_step_out->setEnabled (true);
     m_debug_quit->setEnabled (true);
-
-#if defined (HAVE_QSCINTILLA)
-    m_editor_window->handle_enter_debug_mode ();
-#endif
   }
 
   void main_window::handle_exit_debugger (void)
@@ -1131,19 +1278,15 @@
 
     m_debug_continue->setEnabled (false);
     m_debug_step_into->setEnabled (false);
-    m_debug_step_over->setEnabled (m_editor_has_tabs);
+    m_debug_step_over->setEnabled (m_editor_has_tabs && m_editor_is_octave_file);
     m_debug_step_out->setEnabled (false);
     m_debug_quit->setEnabled (false);
-
-#if defined (HAVE_QSCINTILLA)
-    m_editor_window->handle_exit_debug_mode ();
-#endif
   }
 
   void main_window::debug_continue (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1157,7 +1300,7 @@
   void main_window::debug_step_into (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1175,7 +1318,7 @@
         // We are in debug mode, just call dbstep.
 
         emit interpreter_event
-          ([this] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -1196,7 +1339,7 @@
   void main_window::debug_step_out (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1253,8 +1396,8 @@
     if (! settings->value (global_use_native_dialogs).toBool ())
       fileDialog->setOption(QFileDialog::DontUseNativeDialog);
 
-    connect (fileDialog, SIGNAL (filesSelected (const QStringList&)),
-             this, SLOT (request_open_files (const QStringList&)));
+    connect (fileDialog, &QFileDialog::filesSelected,
+             this, &main_window::request_open_files);
 
     fileDialog->setWindowModality (Qt::NonModal);
     fileDialog->setAttribute (Qt::WA_DeleteOnClose);
@@ -1307,7 +1450,7 @@
                                                int line)
   {
     emit interpreter_event
-      ([this, fname, ffile, curr_dir, line] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1555,18 +1698,6 @@
     settings->sync ();
   }
 
-  // Connecting the signals emitted when the visibility of a widget changes.
-  // This has to be done after the window is shown (see octave-gui.cc)
-  void main_window::connect_visibility_changed (void)
-  {
-    for (auto *widget : dock_widget_list ())
-      widget->connect_visibility_changed ();
-
-#if defined (HAVE_QSCINTILLA)
-    m_editor_window->enable_menu_shortcuts (false);
-#endif
-  }
-
   void main_window::copyClipboard (void)
   {
     if (m_current_directory_combo_box->hasFocus ())
@@ -1612,20 +1743,19 @@
       emit selectAll_signal ();
   }
 
-  void main_window::handle_show_doc (const QString& file)
+  void main_window::handle_gui_status_update (const QString& feature,
+                                              const QString& status)
   {
-    m_doc_browser_window->setVisible (true);
-    emit show_doc_signal (file);
-  }
-
-  void main_window::handle_register_doc (const QString& file)
-  {
-    emit register_doc_signal (file);
-  }
-
-  void main_window::handle_unregister_doc (const QString& file)
-  {
-    emit unregister_doc_signal (file);
+    // Put actions that are required for updating a gui features here
+
+    // Profiler on/off
+    if (! feature.compare ("profiler"))
+      {
+        if (! status.compare ("on", Qt::CaseInsensitive))
+          handle_profiler_status_update (true);
+        else if (! status.compare ("off", Qt::CaseInsensitive))
+          handle_profiler_status_update (false);
+      }
   }
 
   void main_window::handle_octave_ready (void)
@@ -1675,6 +1805,25 @@
 #endif
       }
 
+    if (m_octave_qobj.experimental_terminal_widget ())
+      {
+        // Set initial prompt.
+
+        emit interpreter_event
+          ([] (interpreter& interp)
+          {
+            // INTERPRETER_THREAD
+
+            event_manager& evmgr = interp.get_event_manager ();
+            input_system& input_sys = interp.get_input_system ();
+
+            input_sys.PS1 (">> ");
+            std::string prompt = input_sys.PS1 ();
+
+            evmgr.update_prompt (command_editor::decode_prompt_string (prompt));
+          });
+      }
+
     focus_command_window ();  // make sure that the command window has focus
   }
 
@@ -1692,22 +1841,21 @@
     // Any interpreter_event signal from a set_path_dialog object is
     // handled the same as for the main_window object.
 
-    connect (m_set_path_dlg, SIGNAL (interpreter_event (const fcn_callback&)),
-             this, SIGNAL (interpreter_event (const fcn_callback&)));
-
-    connect (m_set_path_dlg, SIGNAL (interpreter_event (const meth_callback&)),
-             this, SIGNAL (interpreter_event (const meth_callback&)));
-
-    connect (m_set_path_dlg,
-             SIGNAL (modify_path_signal (const octave_value_list&, bool, bool)),
-             this, SLOT (modify_path (const octave_value_list&, bool, bool)));
+    connect (m_set_path_dlg, QOverload<const fcn_callback&>::of (&set_path_dialog::interpreter_event),
+             this, QOverload<const fcn_callback&>::of (&main_window::interpreter_event));
+
+    connect (m_set_path_dlg, QOverload<const meth_callback&>::of (&set_path_dialog::interpreter_event),
+             this, QOverload<const meth_callback&>::of (&main_window::interpreter_event));
+
+    connect (m_set_path_dlg, &set_path_dialog::modify_path_signal,
+             this, &main_window::modify_path);
 
     interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj ();
 
     qt_interpreter_events *qt_link = interp_qobj->qt_link ();
 
-    connect (qt_link, SIGNAL (update_path_dialog_signal (void)),
-             m_set_path_dlg, SLOT (update_model (void)));
+    connect (qt_link, &qt_interpreter_events::update_path_dialog_signal,
+             m_set_path_dlg, &set_path_dialog::update_model);
 
     // Now that all the signal connections are in place for the dialog
     // we can set the initial value of the path in the model.
@@ -1722,15 +1870,14 @@
       {
         m_find_files_dlg = new find_files_dialog (this, m_octave_qobj);
 
-        connect (m_find_files_dlg, SIGNAL (finished (int)),
-                 this, SLOT (find_files_finished (int)));
-
-        connect (m_find_files_dlg, SIGNAL (dir_selected (const QString &)),
-                 m_file_browser_window,
-                 SLOT (set_current_directory (const QString&)));
-
-        connect (m_find_files_dlg, SIGNAL (file_selected (const QString &)),
-                 this, SLOT (open_file (const QString &)));
+        connect (m_find_files_dlg, &find_files_dialog::finished,
+                 this, &main_window::find_files_finished);
+
+        connect (m_find_files_dlg, &find_files_dialog::dir_selected,
+                 m_file_browser_window, &files_dock_widget::set_current_directory);
+
+        connect (m_find_files_dlg, &find_files_dialog::file_selected,
+                 this, QOverload<const QString&>::of (&main_window::open_file_signal));
 
         m_find_files_dlg->setWindowModality (Qt::NonModal);
       }
@@ -1746,65 +1893,10 @@
 
   }
 
-  void main_window::set_global_shortcuts (bool set_shortcuts)
-  {
-    // this slot is called when the terminal gets/loses focus
-
-    // return if the user doesn't want to use readline shortcuts
-    if (! m_prevent_readline_conflicts)
-      return;
-
-    if (set_shortcuts)
-      {
-        // terminal loses focus: set the global shortcuts
-        configure_shortcuts ();
-      }
-    else
-      {
-        // terminal gets focus: disable some shortcuts
-        QKeySequence no_key = QKeySequence ();
-
-        // file menu
-        m_open_action->setShortcut (no_key);
-        m_new_script_action->setShortcut (no_key);
-        m_new_function_action->setShortcut (no_key);
-        m_new_figure_action->setShortcut (no_key);
-        m_load_workspace_action->setShortcut (no_key);
-        m_save_workspace_action->setShortcut (no_key);
-        m_preferences_action->setShortcut (no_key);
-        m_set_path_action->setShortcut (no_key);
-        m_exit_action->setShortcut (no_key);
-
-        // edit menu
-        m_select_all_action->setShortcut (no_key);
-        m_clear_clipboard_action->setShortcut (no_key);
-        m_find_files_action->setShortcut (no_key);
-        m_clear_command_history_action->setShortcut (no_key);
-        m_clear_command_window_action->setShortcut (no_key);
-        m_clear_workspace_action->setShortcut (no_key);
-
-        // window menu
-        m_reset_windows_action->setShortcut (no_key);
-
-        // help menu
-        m_ondisk_doc_action->setShortcut (no_key);
-        m_online_doc_action->setShortcut (no_key);
-        m_report_bug_action->setShortcut (no_key);
-        m_octave_packages_action->setShortcut (no_key);
-        m_contribute_action->setShortcut (no_key);
-        m_developer_action->setShortcut (no_key);
-        m_about_octave_action->setShortcut (no_key);
-
-        // news menu
-        m_release_notes_action->setShortcut (no_key);
-        m_current_news_action->setShortcut (no_key);
-      }
-  }
-
   void main_window::set_screen_size (int ht, int wd)
   {
     emit interpreter_event
-      ([ht, wd] (void)
+      ([=] (void)
        {
          // INTERPRETER THREAD
 
@@ -1875,7 +1967,6 @@
         m_variable_editor_window->show ();
         m_variable_editor_window->raise ();
       }
-
   }
 
   void main_window::refresh_variable_editor (void)
@@ -1903,6 +1994,60 @@
        });
   }
 
+  void main_window::profiler_session (void)
+  {
+    emit interpreter_event
+      ([=] (interpreter& interp)
+        {
+          // INTERPRETER THREAD
+
+          Ffeval (interp, ovl ("profile","on"));
+        });
+  }
+
+  void main_window::profiler_session_resume (void)
+  {
+    emit interpreter_event
+      ([=] (interpreter& interp)
+        {
+          // INTERPRETER THREAD
+
+          Ffeval (interp, ovl ("profile","resume"));
+        });
+  }
+
+  void main_window::profiler_stop (void)
+  {
+    emit interpreter_event
+      ([=] (interpreter& interp)
+        {
+          // INTERPRETER THREAD
+
+          Ffeval (interp, ovl ("profile","off"));
+        });
+  }
+
+  void main_window::handle_profiler_status_update (bool active)
+  {
+    m_profiler_start->setEnabled (! active);
+    m_profiler_resume->setEnabled (! active);
+    m_profiler_stop->setEnabled (active);
+
+    led_indicator::led_state state = led_indicator::LED_STATE_INACTIVE;
+    if (active)
+      state = led_indicator::LED_STATE_ACTIVE;
+    m_profiler_status_indicator->set_state (state);
+  }
+
+  void main_window::profiler_show (void)
+  {
+    // Do not use a separate interpreter event as in the other
+    // profiler slots since the output of the command "profshow"
+    // would obscure the prompt and we do not need to emimt a signal
+    // for action that is required in the gui after rhe command
+    execute_command_in_terminal ("profshow");
+  }
+
   void main_window::closeEvent (QCloseEvent *e)
   {
     if (confirm_shutdown ())
@@ -1916,13 +2061,18 @@
 
         e->ignore ();
 
-        emit interpreter_event
-          ([] (interpreter& interp)
-           {
-             // INTERPRETER THREAD
-
-             interp.quit (0, false, false);
-           });
+        if (m_octave_qobj.experimental_terminal_widget ())
+          emit close_gui_signal ();
+        else
+          {
+            emit interpreter_event
+              ([] (interpreter& interp)
+               {
+                 // INTERPRETER THREAD
+
+                 interp.quit (0, false, false);
+               });
+          }
       }
     else
       e->ignore ();
@@ -1948,70 +2098,56 @@
   {
     setWindowIcon (QIcon (":/actions/icons/logo.png"));
 
-    m_workspace_window->setModel (m_workspace_model);
-
-    connect (m_workspace_model, SIGNAL (model_changed (void)),
-             m_workspace_window, SLOT (handle_model_changed (void)));
-
     interpreter_qobject *interp_qobj = m_octave_qobj.interpreter_qobj ();
 
     qt_interpreter_events *qt_link = interp_qobj->qt_link ();
 
-    connect (qt_link,
-             SIGNAL (edit_variable_signal (const QString&,
-                                           const octave_value&)),
-             this,
-             SLOT (edit_variable (const QString&, const octave_value&)));
-
-    connect (qt_link, SIGNAL (refresh_variable_editor_signal (void)),
-             this, SLOT (refresh_variable_editor (void)));
-
-    connect (m_workspace_window,
-             SIGNAL (rename_variable_signal (const QString&, const QString&)),
-             this,
-             SLOT (handle_rename_variable_request (const QString&,
-                                                   const QString&)));
-
-    connect (m_variable_editor_window, SIGNAL (updated (void)),
-             this, SLOT (handle_variable_editor_update (void)));
+    connect (qt_link, &qt_interpreter_events::edit_variable_signal,
+             this, &main_window::edit_variable);
+
+    connect (qt_link, &qt_interpreter_events::refresh_variable_editor_signal,
+             this, &main_window::refresh_variable_editor);
+
+    connect (m_workspace_window, &workspace_view::rename_variable_signal,
+             this, &main_window::handle_rename_variable_request);
+
+    connect (m_variable_editor_window, &variable_editor::updated,
+             this, &main_window::handle_variable_editor_update);
 
     construct_menu_bar ();
 
     construct_tool_bar ();
 
     // Order is important.  Deleting gui_settings must be last.
-    connect (qApp, SIGNAL (aboutToQuit (void)),
-             m_command_window, SLOT (save_settings (void)));
-
-    connect (qApp, SIGNAL (aboutToQuit (void)),
-             m_history_window, SLOT (save_settings (void)));
-
-    connect (qApp, SIGNAL (aboutToQuit (void)),
-             m_file_browser_window, SLOT (save_settings (void)));
-
-    connect (qApp, SIGNAL (aboutToQuit (void)),
-             m_doc_browser_window, SLOT (save_settings (void)));
-
-    connect (qApp, SIGNAL (aboutToQuit (void)),
-             m_workspace_window, SLOT (save_settings (void)));
-
-    connect (qApp, SIGNAL (aboutToQuit (void)),
-             m_editor_window, SLOT (save_settings (void)));
-
-    connect (qApp, SIGNAL (aboutToQuit (void)),
-             m_variable_editor_window, SLOT (save_settings (void)));
-
-    connect (qApp, SIGNAL (aboutToQuit (void)),
-             this, SLOT (prepare_to_exit (void)));
-
-    connect (qApp, SIGNAL (focusChanged (QWidget*, QWidget*)),
-             this, SLOT (focus_changed (QWidget*, QWidget*)));
-
-    connect (this, SIGNAL (settings_changed (const gui_settings *)),
-             this, SLOT (notice_settings (const gui_settings *)));
-
-    connect (this, SIGNAL (editor_focus_changed (bool)),
-             this, SLOT (disable_menu_shortcuts (bool)));
+    connect (qApp, &QApplication::aboutToQuit,
+             m_command_window, &terminal_dock_widget::save_settings);
+
+    connect (qApp, &QApplication::aboutToQuit,
+             m_history_window, &history_dock_widget::save_settings);
+
+    connect (qApp, &QApplication::aboutToQuit,
+             m_file_browser_window, &files_dock_widget::save_settings);
+
+    connect (qApp, &QApplication::aboutToQuit,
+             m_doc_browser_window, &documentation_dock_widget::save_settings);
+
+    connect (qApp, &QApplication::aboutToQuit,
+             m_workspace_window, &workspace_view::save_settings);
+
+    connect (qApp, &QApplication::aboutToQuit,
+             m_editor_window, &file_editor_interface::save_settings);
+
+    connect (qApp, &QApplication::aboutToQuit,
+             m_variable_editor_window, &variable_editor::save_settings);
+
+    connect (qApp, &QApplication::aboutToQuit,
+             this, &main_window::prepare_to_exit);
+
+    connect (qApp, &QApplication::focusChanged,
+             this, &main_window::focus_changed);
+
+    connect (this, &main_window::settings_changed,
+             this, [=] (const gui_settings *settings) { notice_settings (settings); });
 
     connect (this, SIGNAL (editor_focus_changed (bool)),
              m_editor_window, SLOT (enable_menu_shortcuts (bool)));
@@ -2019,8 +2155,8 @@
     connect (this, SIGNAL (step_into_file_signal (void)),
              m_editor_window, SLOT (request_step_into_file (void)));
 
-    connect (m_editor_window, SIGNAL (editor_tabs_changed_signal (bool)),
-             this, SLOT (editor_tabs_changed (bool)));
+    connect (m_editor_window, SIGNAL (editor_tabs_changed_signal (bool, bool)),
+             this, SLOT (editor_tabs_changed (bool, bool)));
 
     connect (m_editor_window,
              SIGNAL (request_open_file_external (const QString&, int)),
@@ -2031,20 +2167,20 @@
              SIGNAL (request_settings_dialog (const QString&)),
              this, SLOT (process_settings_dialog_request (const QString&)));
 
-    connect (m_file_browser_window, SIGNAL (load_file_signal (const QString&)),
-             this, SLOT (handle_load_workspace_request (const QString&)));
-
-    connect (m_file_browser_window, SIGNAL (open_any_signal (const QString&)),
-             this, SLOT (handle_open_any_request (const QString&)));
-
-    connect (m_file_browser_window, SIGNAL (find_files_signal (const QString&)),
-             this, SLOT (find_files (const QString&)));
+    connect (m_file_browser_window, &files_dock_widget::load_file_signal,
+             this, &main_window::handle_load_workspace_request);
+
+    connect (m_file_browser_window, &files_dock_widget::open_any_signal,
+             this, &main_window::handle_open_any_request);
+
+    connect (m_file_browser_window, &files_dock_widget::find_files_signal,
+             this, &main_window::find_files);
 
     // Connections for signals from the interpreter thread where the slot
     // should be executed by the gui thread
 
-    connect (this, SIGNAL (warning_function_not_found_signal (const QString&)),
-             this, SLOT (warning_function_not_found (const QString&)));
+    connect (this, &main_window::warning_function_not_found_signal,
+             this, &main_window::warning_function_not_found);
 
     setWindowTitle ("Octave");
 
@@ -2084,18 +2220,24 @@
     // Signals for removing/renaming files/dirs in the terminal window
     connect (qt_link, SIGNAL (file_renamed_signal (bool)),
              m_editor_window, SLOT (handle_file_renamed (bool)));
+
+    // Signals for entering/exiting debug mode
+    connect (qt_link, SIGNAL (enter_debugger_signal (void)),
+             m_editor_window, SLOT (handle_enter_debug_mode (void)));
+
+    connect (qt_link, SIGNAL (exit_debugger_signal (void)),
+             m_editor_window, SLOT (handle_exit_debug_mode (void)));
 #endif
 
     // Signals for removing/renaming files/dirs in the temrinal window
-    connect (qt_link,
-             SIGNAL (file_remove_signal (const QString&, const QString&)),
-             this, SLOT (file_remove_proxy (const QString&, const QString&)));
-
-    connect (this, SIGNAL (interpreter_event (const fcn_callback&)),
-             &m_octave_qobj, SLOT (interpreter_event (const fcn_callback&)));
-
-    connect (this, SIGNAL (interpreter_event (const meth_callback&)),
-             &m_octave_qobj, SLOT (interpreter_event (const meth_callback&)));
+    connect (qt_link, &qt_interpreter_events::file_remove_signal,
+             this, &main_window::file_remove_proxy);
+
+    connect (this, QOverload<const fcn_callback&>::of (&main_window::interpreter_event),
+             &m_octave_qobj, QOverload<const fcn_callback&>::of (&base_qobject::interpreter_event));
+
+    connect (this, QOverload<const meth_callback&>::of (&main_window::interpreter_event),
+             &m_octave_qobj, QOverload<const meth_callback&>::of (&base_qobject::interpreter_event));
 
     configure_shortcuts ();
   }
@@ -2106,90 +2248,61 @@
 
     qt_interpreter_events *qt_link = interp_qobj->qt_link ();
 
-    connect (qt_link, SIGNAL (settings_changed (const gui_settings *, bool)),
-             this, SLOT (notice_settings (const gui_settings *, bool)));
-
-    connect (qt_link, SIGNAL (apply_new_settings (void)),
-             this, SLOT (request_reload_settings (void)));
-
-    connect (qt_link,
-             SIGNAL (set_workspace_signal (bool, bool, const symbol_info_list&)),
-             m_workspace_model,
-             SLOT (set_workspace (bool, bool, const symbol_info_list&)));
-
-    connect (qt_link, SIGNAL (clear_workspace_signal (void)),
-             m_workspace_model, SLOT (clear_workspace (void)));
-
-    connect (qt_link, SIGNAL (directory_changed_signal (QString)),
-             this, SLOT (update_octave_directory (QString)));
-
-    connect (qt_link, SIGNAL (directory_changed_signal (QString)),
-             m_file_browser_window, SLOT (update_octave_directory (QString)));
+    connect (qt_link, &qt_interpreter_events::settings_changed,
+             this, &main_window::notice_settings);
+
+    connect (qt_link, &qt_interpreter_events::apply_new_settings,
+             this, &main_window::request_reload_settings);
+
+    if (m_octave_qobj.experimental_terminal_widget ())
+      {
+        connect (qt_link, &qt_interpreter_events::interpreter_output_signal,
+                 m_command_window, &terminal_dock_widget::interpreter_output);
+
+        connect (qt_link, &qt_interpreter_events::update_prompt_signal,
+                 m_command_window, &terminal_dock_widget::update_prompt);
+      }
+
+    connect (qt_link, &qt_interpreter_events::directory_changed_signal,
+             this, &main_window::update_octave_directory);
+
+    connect (qt_link, &qt_interpreter_events::directory_changed_signal,
+             m_file_browser_window, &files_dock_widget::update_octave_directory);
 
     connect (qt_link, SIGNAL (directory_changed_signal (QString)),
              m_editor_window, SLOT (update_octave_directory (QString)));
 
-    connect (qt_link,
-             SIGNAL (execute_command_in_terminal_signal (QString)),
-             this, SLOT (execute_command_in_terminal (QString)));
-
-    connect (qt_link,
-             SIGNAL (set_history_signal (const QStringList&)),
-             m_history_window, SLOT (set_history (const QStringList&)));
-
-    connect (qt_link,
-             SIGNAL (append_history_signal (const QString&)),
-             m_history_window, SLOT (append_history (const QString&)));
-
-    connect (qt_link,
-             SIGNAL (clear_history_signal (void)),
-             m_history_window, SLOT (clear_history (void)));
-
-    connect (qt_link, SIGNAL (enter_debugger_signal (void)),
-             this, SLOT (handle_enter_debugger (void)));
-
-    connect (qt_link, SIGNAL (exit_debugger_signal (void)),
-             this, SLOT (handle_exit_debugger (void)));
-
-    connect (qt_link,
-             SIGNAL (show_preferences_signal (void)),
-             this, SLOT (process_settings_dialog_request (void)));
+    connect (qt_link, &qt_interpreter_events::execute_command_in_terminal_signal,
+             this, &main_window::execute_command_in_terminal);
+
+    connect (qt_link, &qt_interpreter_events::enter_debugger_signal,
+             this, &main_window::handle_enter_debugger);
+
+    connect (qt_link, &qt_interpreter_events::exit_debugger_signal,
+             this, &main_window::handle_exit_debugger);
+
+    connect (qt_link, &qt_interpreter_events::show_preferences_signal,
+             this, [=] () { process_settings_dialog_request (); });
 
     connect (qt_link,
              SIGNAL (edit_file_signal (const QString&)),
              m_active_editor,
              SLOT (handle_edit_file_request (const QString&)));
 
-    connect (qt_link,
-             SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
-             this,
-             SLOT (handle_insert_debugger_pointer_request (const QString&,
-                                                           int)));
-
-    connect (qt_link,
-             SIGNAL (delete_debugger_pointer_signal (const QString&, int)),
-             this,
-             SLOT (handle_delete_debugger_pointer_request (const QString&,
-                                                           int)));
-
-    connect (qt_link,
-             SIGNAL (update_breakpoint_marker_signal (bool, const QString&,
-                                                      int, const QString&)),
-             this,
-             SLOT (handle_update_breakpoint_marker_request (bool, const QString&,
-                                                            int, const QString&)));
-
-    connect (qt_link,
-             SIGNAL (show_doc_signal (const QString &)),
-             this, SLOT (handle_show_doc (const QString &)));
-
-    connect (qt_link,
-             SIGNAL (register_doc_signal (const QString &)),
-             this, SLOT (handle_register_doc (const QString &)));
-
-    connect (qt_link,
-             SIGNAL (unregister_doc_signal (const QString &)),
-             this, SLOT (handle_unregister_doc (const QString &)));
+    connect (qt_link, &qt_interpreter_events::insert_debugger_pointer_signal,
+             this, &main_window::handle_insert_debugger_pointer_request);
+
+    connect (qt_link, &qt_interpreter_events::delete_debugger_pointer_signal,
+             this, &main_window::handle_delete_debugger_pointer_request);
+
+    connect (qt_link, &qt_interpreter_events::update_breakpoint_marker_signal,
+             this, &main_window::handle_update_breakpoint_marker_request);
+
+    connect (qt_link, &qt_interpreter_events::gui_status_update_signal,
+             this, &main_window::handle_gui_status_update);
+
+    connect (qt_link, &qt_interpreter_events::update_gui_lexer_signal,
+             this, &main_window::update_gui_lexer_signal);
   }
 
   QAction* main_window::add_action (QMenu *menu, const QIcon& icon,
@@ -2236,6 +2349,8 @@
 
     construct_debug_menu (menu_bar);
 
+    construct_tools_menu (menu_bar);
+
     construct_window_menu (menu_bar);
 
     construct_help_menu (menu_bar);
@@ -2253,7 +2368,7 @@
                    << m_undo_action
                    << m_copy_action
                    << m_paste_action
-                   <<m_select_all_action;
+                   << m_select_all_action;
     m_editor_window->insert_global_actions (shared_actions);
 #endif
   }
@@ -2265,9 +2380,10 @@
     construct_new_menu (file_menu);
 
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
-    m_open_action
-      = file_menu->addAction (rmgr.icon ("document-open"), tr ("Open..."));
-    m_open_action->setShortcutContext (Qt::ApplicationShortcut);
+
+    m_open_action = add_action (
+                    file_menu, rmgr.icon ("document-open"), tr ("Open..."),
+                    SLOT (request_open_file (void)), this);
     m_open_action->setToolTip (tr ("Open an existing file in editor"));
 
 #if defined (HAVE_QSCINTILLA)
@@ -2276,53 +2392,22 @@
 
     file_menu->addSeparator ();
 
-    m_load_workspace_action
-      = file_menu->addAction (tr ("Load Workspace..."));
-
-    m_save_workspace_action
-      = file_menu->addAction (tr ("Save Workspace As..."));
+    m_load_workspace_action = add_action (
+              file_menu, QIcon (), tr ("Load Workspace..."),
+              SLOT (handle_load_workspace_request (void)), this);
+
+    m_save_workspace_action = add_action (
+              file_menu, QIcon (), tr ("Save Workspace As..."),
+              SLOT (handle_save_workspace_request (void)), this);
 
     file_menu->addSeparator ();
 
-    m_exit_action = file_menu->addAction (tr ("Exit"));
+    m_exit_action = add_action (
+              file_menu, QIcon (), tr ("Exit"),
+              SLOT (close (void)), this);
     m_exit_action->setMenuRole (QAction::QuitRole);
-    m_exit_action->setShortcutContext (Qt::ApplicationShortcut);
-
-    connect (m_open_action, SIGNAL (triggered (void)),
-             this, SLOT (request_open_file (void)));
-
-    connect (m_load_workspace_action, SIGNAL (triggered (void)),
-             this, SLOT (handle_load_workspace_request (void)));
-
-    connect (m_save_workspace_action, SIGNAL (triggered (void)),
-             this, SLOT (handle_save_workspace_request (void)));
-
-    connect (m_exit_action, SIGNAL (triggered (void)),
-             this, SLOT (close (void)));
-  }
-
-  void main_window::construct_new_menu (QMenu *p)
-  {
-    QMenu *new_menu = p->addMenu (tr ("New"));
-
-    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
-    m_new_script_action
-      = new_menu->addAction (rmgr.icon ("document-new"), tr ("New Script"));
-    m_new_script_action->setShortcutContext (Qt::ApplicationShortcut);
-
-    m_new_function_action = new_menu->addAction (tr ("New Function..."));
-    m_new_function_action->setEnabled (true);
-    m_new_function_action->setShortcutContext (Qt::ApplicationShortcut);
-
-    m_new_figure_action = new_menu->addAction (tr ("New Figure"));
-    m_new_figure_action->setEnabled (true);
-
-    connect (m_new_script_action, SIGNAL (triggered (void)),
-             this, SLOT (request_new_script (void)));
-
-    connect (m_new_function_action, SIGNAL (triggered (void)),
-             this, SLOT (request_new_function (void)));
-
+
+    // Connect signal related to opening or creating editor files
     connect (this, SIGNAL (new_file_signal (const QString&)),
              m_active_editor, SLOT (request_new_file (const QString&)));
 
@@ -2333,9 +2418,25 @@
              SIGNAL (open_file_signal (const QString&, const QString&, int)),
              m_active_editor,
              SLOT (request_open_file (const QString&, const QString&, int)));
-
-    connect (m_new_figure_action, SIGNAL (triggered (void)),
-             this, SLOT (handle_new_figure_request (void)));
+  }
+
+  void main_window::construct_new_menu (QMenu *p)
+  {
+    QMenu *new_menu = p->addMenu (tr ("New"));
+
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+
+    m_new_script_action = add_action (
+          new_menu, rmgr.icon ("document-new"), tr ("New Script"),
+          SLOT (request_new_script (void)), this);
+
+    m_new_function_action = add_action (
+          new_menu, QIcon (), tr ("New Function..."),
+          SLOT (request_new_function (void)), this);
+
+    m_new_figure_action = add_action (
+          new_menu, QIcon (), tr ("New Figure"),
+          SLOT (handle_new_figure_request (void)), this);
   }
 
   void main_window::construct_edit_menu (QMenuBar *p)
@@ -2353,21 +2454,22 @@
 
     m_copy_action
       = edit_menu->addAction (rmgr.icon ("edit-copy"), tr ("Copy"), this,
-                              SLOT (copyClipboard (void)));
+                              &main_window::copyClipboard);
     m_copy_action->setShortcutContext (Qt::ApplicationShortcut);
 
     m_paste_action
       = edit_menu->addAction (rmgr.icon ("edit-paste"), tr ("Paste"), this,
-                              SLOT (pasteClipboard (void)));
+                              &main_window::pasteClipboard);
     m_paste_action->setShortcutContext (Qt::ApplicationShortcut);
 
     m_select_all_action
-      = edit_menu->addAction (tr ("Select All"), this, SLOT (selectAll (void)));
+      = edit_menu->addAction (tr ("Select All"), this,
+                              &main_window::selectAll);
     m_select_all_action->setShortcutContext (Qt::ApplicationShortcut);
 
     m_clear_clipboard_action
       = edit_menu->addAction (tr ("Clear Clipboard"), this,
-                              SLOT (clear_clipboard (void)));
+                              &main_window::clear_clipboard);
 
     edit_menu->addSeparator ();
 
@@ -2394,20 +2496,20 @@
       = edit_menu->addAction (rmgr.icon ("preferences-system"),
                               tr ("Preferences..."));
 
-    connect (m_find_files_action, SIGNAL (triggered (void)),
-             this, SLOT (find_files (void)));
-
-    connect (m_clear_command_window_action, SIGNAL (triggered (void)),
-             this, SLOT (handle_clear_command_window_request (void)));
-
-    connect (m_clear_command_history_action, SIGNAL (triggered (void)),
-             this, SLOT (handle_clear_history_request (void)));
-
-    connect (m_clear_workspace_action, SIGNAL (triggered (void)),
-             this, SLOT (handle_clear_workspace_request (void)));
-
-    connect (m_clipboard, SIGNAL (dataChanged (void)),
-             this, SLOT (clipboard_has_changed (void)));
+    connect (m_find_files_action, &QAction::triggered,
+             this, [=] () { find_files (); });
+
+    connect (m_clear_command_window_action, &QAction::triggered,
+             this, &main_window::handle_clear_command_window_request);
+
+    connect (m_clear_command_history_action, &QAction::triggered,
+             this, &main_window::handle_clear_history_request);
+
+    connect (m_clear_workspace_action, &QAction::triggered,
+             this, &main_window::handle_clear_workspace_request);
+
+    connect (m_clipboard, &QClipboard::dataChanged,
+             this, &main_window::clipboard_has_changed);
     clipboard_has_changed ();
 #if defined (Q_OS_WIN32)
     // Always enable paste action (unreliable clipboard signals in windows)
@@ -2417,11 +2519,11 @@
     m_clear_clipboard_action->setEnabled (true);
 #endif
 
-    connect (m_preferences_action, SIGNAL (triggered (void)),
-             this, SLOT (process_settings_dialog_request (void)));
-
-    connect (m_set_path_action, SIGNAL (triggered (void)),
-             this, SLOT (handle_set_path_dialog_request (void)));
+    connect (m_preferences_action, &QAction::triggered,
+             this, [=] () { process_settings_dialog_request (); });
+
+    connect (m_set_path_action, &QAction::triggered,
+             this, &main_window::handle_set_path_dialog_request);
 
   }
 
@@ -2473,11 +2575,30 @@
                                    SLOT (debug_quit (void)));
   }
 
-  void main_window::editor_tabs_changed (bool have_tabs)
+  void main_window::construct_tools_menu (QMenuBar *p)
+  {
+    QMenu *tools_menu = m_add_menu (p, tr ("&Tools"));
+
+    m_profiler_start = add_action (tools_menu, QIcon (),
+          tr ("Start &Profiler Session"), SLOT (profiler_session ()));
+
+    m_profiler_resume = add_action (tools_menu, QIcon (),
+          tr ("&Resume Profiler Session"), SLOT (profiler_session_resume ()));
+
+    m_profiler_stop = add_action (tools_menu, QIcon (),
+          tr ("&Stop Profiler"), SLOT (profiler_stop ()));
+    m_profiler_stop->setEnabled (false);
+
+    m_profiler_show = add_action (tools_menu, QIcon (),
+          tr ("&Show Profile Data"), SLOT (profiler_show ()));
+  }
+
+  void main_window::editor_tabs_changed (bool have_tabs, bool is_octave)
   {
     // Set state of actions which depend on the existence of editor tabs
     m_editor_has_tabs = have_tabs;
-    m_debug_step_over->setEnabled (have_tabs);
+    m_editor_is_octave_file = is_octave;
+    m_debug_step_over->setEnabled (have_tabs && is_octave);
   }
 
   QAction * main_window::construct_window_menu_item (QMenu *p,
@@ -2505,7 +2626,8 @@
         else
           {
             // action for focus of dock widget
-            connect (action, SIGNAL (triggered (void)), widget, SLOT (activate (void)));
+            connect (action, SIGNAL (triggered (void)),
+                     widget, SLOT (activate (void)));
           }
       }
     else
@@ -2664,20 +2786,21 @@
       = m_main_tool_bar->addAction (rmgr.icon ("folder"),
                                     tr ("Browse directories"));
 
-    connect (m_current_directory_combo_box, SIGNAL (activated (QString)),
-             this, SLOT (set_current_working_directory (QString)));
-
-    connect (m_current_directory_combo_box->lineEdit (), SIGNAL (returnPressed (void)),
-             this, SLOT (accept_directory_line_edit (void)));
-
-    connect (current_dir_search, SIGNAL (triggered (void)),
-             this, SLOT (browse_for_directory (void)));
-
-    connect (current_dir_up, SIGNAL (triggered (void)),
-             this, SLOT (change_directory_up (void)));
-
-    connect (m_undo_action, SIGNAL (triggered (void)),
-             this, SLOT (handle_undo_request (void)));
+    connect (m_current_directory_combo_box, SIGNAL (activated (const QString&)),
+             this, SLOT (set_current_working_directory (const QString&)));
+
+    connect (m_current_directory_combo_box->lineEdit (),
+             &QLineEdit::returnPressed,
+             this, &main_window::accept_directory_line_edit);
+
+    connect (current_dir_search, &QAction::triggered,
+             this, &main_window::browse_for_directory);
+
+    connect (current_dir_up, &QAction::triggered,
+             this, &main_window::change_directory_up);
+
+    connect (m_undo_action, &QAction::triggered,
+             this, &main_window::handle_undo_request);
   }
 
   void main_window::focus_console_after_command (void)
@@ -2690,67 +2813,77 @@
 
   void main_window::configure_shortcuts (void)
   {
+    bool enable
+      = ! ((m_active_dock == m_command_window) && m_prevent_readline_conflicts);
+
     shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager ();
 
     // file menu
-    scmgr.set_shortcut (m_open_action, sc_main_file_open_file);
-    scmgr.set_shortcut (m_new_script_action, sc_main_file_new_file);
-    scmgr.set_shortcut (m_new_function_action, sc_main_file_new_function);
-    scmgr.set_shortcut (m_new_figure_action, sc_main_file_new_figure);
-    scmgr.set_shortcut (m_load_workspace_action, sc_main_file_load_workspace);
-    scmgr.set_shortcut (m_save_workspace_action, sc_main_file_save_workspace);
-    scmgr.set_shortcut (m_exit_action, sc_main_file_exit);
+    scmgr.set_shortcut (m_open_action, sc_main_file_open_file, enable);
+    scmgr.set_shortcut (m_new_script_action, sc_main_file_new_file, enable);
+    scmgr.set_shortcut (m_new_function_action, sc_main_file_new_function, enable);
+    scmgr.set_shortcut (m_new_figure_action, sc_main_file_new_figure, enable);
+    scmgr.set_shortcut (m_load_workspace_action, sc_main_file_load_workspace, enable);
+    scmgr.set_shortcut (m_save_workspace_action, sc_main_file_save_workspace, enable);
+    scmgr.set_shortcut (m_exit_action, sc_main_file_exit, enable);
 
     // edit menu
-    scmgr.set_shortcut (m_copy_action, sc_main_edit_copy);
-    scmgr.set_shortcut (m_paste_action, sc_main_edit_paste);
-    scmgr.set_shortcut (m_undo_action, sc_main_edit_undo);
-    scmgr.set_shortcut (m_select_all_action, sc_main_edit_select_all);
-    scmgr.set_shortcut (m_clear_clipboard_action, sc_main_edit_clear_clipboard);
-    scmgr.set_shortcut (m_find_files_action, sc_main_edit_find_in_files);
-    scmgr.set_shortcut (m_clear_command_history_action, sc_main_edit_clear_history);
-    scmgr.set_shortcut (m_clear_command_window_action, sc_main_edit_clear_command_window);
-    scmgr.set_shortcut (m_clear_workspace_action, sc_main_edit_clear_workspace);
-    scmgr.set_shortcut (m_set_path_action, sc_main_edit_set_path);
-    scmgr.set_shortcut (m_preferences_action, sc_main_edit_preferences);
+    scmgr.set_shortcut (m_copy_action, sc_main_edit_copy, enable);
+    scmgr.set_shortcut (m_paste_action, sc_main_edit_paste, enable);
+    scmgr.set_shortcut (m_undo_action, sc_main_edit_undo, enable);
+    scmgr.set_shortcut (m_select_all_action, sc_main_edit_select_all, enable);
+    scmgr.set_shortcut (m_clear_clipboard_action, sc_main_edit_clear_clipboard, enable);
+    scmgr.set_shortcut (m_find_files_action, sc_main_edit_find_in_files, enable);
+    scmgr.set_shortcut (m_clear_command_history_action, sc_main_edit_clear_history, enable);
+    scmgr.set_shortcut (m_clear_command_window_action, sc_main_edit_clear_command_window, enable);
+    scmgr.set_shortcut (m_clear_workspace_action, sc_main_edit_clear_workspace, enable);
+    scmgr.set_shortcut (m_set_path_action, sc_main_edit_set_path, enable);
+    scmgr.set_shortcut (m_preferences_action, sc_main_edit_preferences, enable);
 
     // debug menu
-    scmgr.set_shortcut (m_debug_step_over, sc_main_debug_step_over);
-    scmgr.set_shortcut (m_debug_step_into, sc_main_debug_step_into);
-    scmgr.set_shortcut (m_debug_step_out, sc_main_debug_step_out);
-    scmgr.set_shortcut (m_debug_continue, sc_main_debug_continue);
-    scmgr.set_shortcut (m_debug_quit, sc_main_debug_quit);
+    scmgr.set_shortcut (m_debug_step_over, sc_main_debug_step_over, enable);
+    scmgr.set_shortcut (m_debug_step_into, sc_main_debug_step_into, enable);
+    scmgr.set_shortcut (m_debug_step_out, sc_main_debug_step_out, enable);
+    scmgr.set_shortcut (m_debug_continue, sc_main_debug_continue, enable);
+    scmgr.set_shortcut (m_debug_quit, sc_main_debug_quit, enable);
+
+    // tools menu
+    scmgr.set_shortcut (m_profiler_start, sc_main_tools_start_profiler, enable);
+    scmgr.set_shortcut (m_profiler_resume, sc_main_tools_resume_profiler, enable);
+    scmgr.set_shortcut (m_profiler_stop, sc_main_tools_start_profiler, enable); // same, toggling
+    scmgr.set_shortcut (m_profiler_show, sc_main_tools_show_profiler, enable);
 
     // window menu
-    scmgr.set_shortcut (m_show_command_window_action, sc_main_window_show_command);
-    scmgr.set_shortcut (m_show_history_action, sc_main_window_show_history);
-    scmgr.set_shortcut (m_show_workspace_action, sc_main_window_show_workspace);
-    scmgr.set_shortcut (m_show_file_browser_action, sc_main_window_show_file_browser);
-    scmgr.set_shortcut (m_show_editor_action, sc_main_window_show_editor);
-    scmgr.set_shortcut (m_show_documentation_action, sc_main_window_show_doc);
-    scmgr.set_shortcut (m_show_variable_editor_action, sc_main_window_show_variable_editor);
-    scmgr.set_shortcut (m_command_window_action, sc_main_window_command);
-    scmgr.set_shortcut (m_history_action, sc_main_window_history);
-    scmgr.set_shortcut (m_workspace_action, sc_main_window_workspace);
-    scmgr.set_shortcut (m_file_browser_action, sc_main_window_file_browser);
-    scmgr.set_shortcut (m_editor_action, sc_main_window_editor);
-    scmgr.set_shortcut (m_documentation_action, sc_main_window_doc);
-    scmgr.set_shortcut (m_variable_editor_action, sc_main_window_variable_editor);
-    scmgr.set_shortcut (m_previous_dock_action, sc_main_window_previous_dock);
-    scmgr.set_shortcut (m_reset_windows_action, sc_main_window_reset);
+    scmgr.set_shortcut (m_show_command_window_action, sc_main_window_show_command, enable);
+    scmgr.set_shortcut (m_show_history_action, sc_main_window_show_history, enable);
+    scmgr.set_shortcut (m_show_workspace_action, sc_main_window_show_workspace, enable);
+    scmgr.set_shortcut (m_show_file_browser_action, sc_main_window_show_file_browser, enable);
+    scmgr.set_shortcut (m_show_editor_action, sc_main_window_show_editor, enable);
+    scmgr.set_shortcut (m_show_documentation_action, sc_main_window_show_doc, enable);
+    scmgr.set_shortcut (m_show_variable_editor_action, sc_main_window_show_variable_editor, enable);
+    scmgr.set_shortcut (m_reset_windows_action, sc_main_window_reset, enable);
+    scmgr.set_shortcut (m_command_window_action, sc_main_window_command, enable);
+    // Switching to the other widgets (including the previous one) is always enabled
+    scmgr.set_shortcut (m_history_action, sc_main_window_history, true);
+    scmgr.set_shortcut (m_workspace_action, sc_main_window_workspace, true);
+    scmgr.set_shortcut (m_file_browser_action, sc_main_window_file_browser, true);
+    scmgr.set_shortcut (m_editor_action, sc_main_window_editor, true);
+    scmgr.set_shortcut (m_documentation_action, sc_main_window_doc, true);
+    scmgr.set_shortcut (m_variable_editor_action, sc_main_window_variable_editor, true);
+    scmgr.set_shortcut (m_previous_dock_action, sc_main_window_previous_dock, true);
 
     // help menu
-    scmgr.set_shortcut (m_ondisk_doc_action, sc_main_help_ondisk_doc);
-    scmgr.set_shortcut (m_online_doc_action, sc_main_help_online_doc);
-    scmgr.set_shortcut (m_report_bug_action, sc_main_help_report_bug);
-    scmgr.set_shortcut (m_octave_packages_action, sc_main_help_packages);
-    scmgr.set_shortcut (m_contribute_action, sc_main_help_contribute);
-    scmgr.set_shortcut (m_developer_action, sc_main_help_developer);
-    scmgr.set_shortcut (m_about_octave_action, sc_main_help_about);
+    scmgr.set_shortcut (m_ondisk_doc_action, sc_main_help_ondisk_doc, enable);
+    scmgr.set_shortcut (m_online_doc_action, sc_main_help_online_doc, enable);
+    scmgr.set_shortcut (m_report_bug_action, sc_main_help_report_bug, enable);
+    scmgr.set_shortcut (m_octave_packages_action, sc_main_help_packages, enable);
+    scmgr.set_shortcut (m_contribute_action, sc_main_help_contribute, enable);
+    scmgr.set_shortcut (m_developer_action, sc_main_help_developer, enable);
+    scmgr.set_shortcut (m_about_octave_action, sc_main_help_about, enable);
 
     // news menu
-    scmgr.set_shortcut (m_release_notes_action, sc_main_news_release_notes);
-    scmgr.set_shortcut (m_current_news_action, sc_main_news_community_news);
+    scmgr.set_shortcut (m_release_notes_action, sc_main_news_release_notes, enable);
+    scmgr.set_shortcut (m_current_news_action, sc_main_news_community_news, enable);
   }
 
   QList<octave_dock_widget *> main_window::dock_widget_list (void)
@@ -2776,7 +2909,7 @@
       mfile_encoding = "SYSTEM";
 
     emit interpreter_event
-      ([mfile_encoding] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -2833,7 +2966,7 @@
     do_reset_windows (false);   // Add all widgets
     // Re-add after giving time: This seems to be a reliable way to
     // reset the main window's layout
-    QTimer::singleShot (250, this, SLOT (do_reset_windows (void)));
+    QTimer::singleShot (250, this, [=] () { do_reset_windows (); });
   }
 
   // Create the default layout of the main window. Do not use
@@ -2846,8 +2979,10 @@
     set_default_geometry ();
     int win_x = geometry ().width ();
 
-    // Resize command window, the important one in the default layout
-    resize_dock (m_command_window, 7*win_x/8, -1);
+    // Resize command window (if docked),
+    //the important one in the default layout
+    if (dockWidgetArea (m_command_window) != Qt::NoDockWidgetArea)
+      resize_dock (m_command_window, 7*win_x/8, -1);
 
     // See Octave bug #53409 and https://bugreports.qt.io/browse/QTBUG-55357
 #if (QT_VERSION < 0x050601) || (QT_VERSION >= 0x050701)
--- a/libgui/src/main-window.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/main-window.h	Sun May 16 09:44:35 2021 +0200
@@ -53,13 +53,13 @@
 #include "find-files-dialog.h"
 #include "history-dock-widget.h"
 #include "interpreter-qobject.h"
+#include "led-indicator.h"
 #include "octave-dock-widget.h"
 #include "octave-qobject.h"
 #include "qt-interpreter-events.h"
 #include "set-path-dialog.h"
 #include "terminal-dock-widget.h"
 #include "variable-editor.h"
-#include "workspace-model.h"
 #include "workspace-view.h"
 
 class octave_value;
@@ -85,6 +85,8 @@
 
     ~main_window (void);
 
+    void make_dock_widget_connections (octave_dock_widget *dw);
+
     bool command_window_has_focus (void) const;
 
     void focus_command_window (void);
@@ -93,19 +95,22 @@
 
   signals:
 
+    // Note: CLOSE_GUI_SIGNAL is currently only used by the new
+    // experimental terminal widget.
+    void close_gui_signal (void);
+
     void active_dock_changed (octave_dock_widget *, octave_dock_widget *);
     void editor_focus_changed (bool);
 
     void settings_changed (const gui_settings *);
     void init_terminal_size_signal (void);
+    void init_window_menu (void);
     void new_file_signal (const QString&);
     void open_file_signal (const QString&);
     void open_file_signal (const QString& file, const QString& enc, int line);
     void step_into_file_signal (void);
 
-    void show_doc_signal (const QString&);
-    void register_doc_signal (const QString&);
-    void unregister_doc_signal (const QString&);
+    void update_gui_lexer_signal (bool);
 
     void insert_debugger_pointer_signal (const QString& file, int line);
     void delete_debugger_pointer_signal (const QString& file, int line);
@@ -141,8 +146,6 @@
     void handle_rename_variable_request (const QString& old_name,
                                          const QString& new_name);
     void modify_path (const octave_value_list& dir_list, bool rm, bool subdirs);
-    void new_file (const QString& commands = QString ());
-    void open_file (const QString& file_name = QString (), int line = -1);
     void edit_mfile (const QString&, int);
     void file_remove_proxy (const QString& o, const QString& n);
     void open_online_documentation_page (void);
@@ -182,7 +185,7 @@
     void debug_step_over (void);
     void debug_step_out (void);
     void debug_quit (void);
-    void editor_tabs_changed (bool);
+    void editor_tabs_changed (bool, bool);
 
     void request_open_file (void);
     void request_new_script (const QString& commands = QString ());
@@ -200,16 +203,20 @@
     void init_terminal_size (void);
     void set_window_layout (gui_settings *settings);
     void write_settings (void);
-    void connect_visibility_changed (void);
 
     void copyClipboard (void);
     void pasteClipboard (void);
     void selectAll (void);
 
+    void handle_gui_status_update (const QString& feature, const QString& status);
+
     void focus_console_after_command (void);
-    void handle_show_doc (const QString& file);
-    void handle_register_doc (const QString& file);
-    void handle_unregister_doc (const QString& file);
+
+    void profiler_session (void);
+    void profiler_session_resume (void);
+    void profiler_stop (void);
+    void handle_profiler_status_update (bool);
+    void profiler_show (void);
 
     void handle_octave_ready ();
 
@@ -221,10 +228,6 @@
     void find_files_finished (int) { }
     //!@}
 
-    //! Setting global shortcuts.
-
-    void set_global_shortcuts (bool enable);
-
     void set_screen_size (int ht, int wd);
 
     //! Handling the clipboard.
@@ -283,6 +286,7 @@
     void construct_debug_menu (QMenuBar *p);
     QAction * construct_window_menu_item (QMenu *p, const QString& item,
                                           bool checkable, QWidget*);
+    void construct_tools_menu (QMenuBar *p);
     void construct_window_menu (QMenuBar *p);
     void construct_help_menu (QMenuBar *p);
     void construct_documentation_menu (QMenu *p);
@@ -303,8 +307,6 @@
 
     base_qobject& m_octave_qobj;
 
-    workspace_model *m_workspace_model;
-
     QHash<QMenu*, QStringList> m_hash_menu_text;
 
     QString m_default_encoding;
@@ -314,16 +316,18 @@
     //! Toolbar.
 
     QStatusBar *m_status_bar;
+    led_indicator *m_profiler_status_indicator;
 
     //! Dock widgets.
     //!@{
-    terminal_dock_widget *m_command_window;
-    history_dock_widget *m_history_window;
-    files_dock_widget *m_file_browser_window;
-    documentation_dock_widget *m_doc_browser_window;
-    file_editor_interface *m_editor_window;
-    workspace_view *m_workspace_window;
-    variable_editor *m_variable_editor_window;
+    QPointer<terminal_dock_widget> m_command_window;
+
+    QPointer<history_dock_widget> m_history_window;
+    QPointer<files_dock_widget> m_file_browser_window;
+    QPointer<documentation_dock_widget> m_doc_browser_window;
+    QPointer<file_editor_interface> m_editor_window;
+    QPointer<workspace_view> m_workspace_window;
+    QPointer<variable_editor> m_variable_editor_window;
     //!@}
 
     external_editor_interface *m_external_editor;
@@ -338,6 +342,8 @@
 
     QMenu *m_debug_menu;
 
+    QMenuBar *m_editor_menubar;
+
     QAction *m_debug_continue;
     QAction *m_debug_step_into;
     QAction *m_debug_step_over;
@@ -364,6 +370,11 @@
     QAction *m_find_files_action;
     QAction *m_select_all_action;
 
+    QAction *m_profiler_start;
+    QAction *m_profiler_resume;
+    QAction *m_profiler_stop;
+    QAction *m_profiler_show;
+
     QAction *m_show_command_window_action;
     QAction *m_show_history_action;
     QAction *m_show_workspace_action;
@@ -422,8 +433,10 @@
     //! Some class global flags.
     //!@{
     bool m_prevent_readline_conflicts;
+    bool m_prevent_readline_conflicts_menu;
     bool m_suppress_dbg_location;
     bool m_editor_has_tabs;
+    bool m_editor_is_octave_file;
 
     //! Flag for closing the whole application.
 
--- a/libgui/src/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,6 @@
 octave_gui_ICONS = \
   %reldir%/icons/applications-system.png \
+  %reldir%/icons/bookmark-new.png \
   %reldir%/icons/bottom_left_corner.png \
   %reldir%/icons/bottom_right_corner.png \
   %reldir%/icons/bottom_side.png \
@@ -49,6 +50,7 @@
   %reldir%/icons/go-previous.png \
   %reldir%/icons/go-up.png \
   %reldir%/icons/graphic_logo_DocumentationDockWidget.png \
+  %reldir%/icons/graphic_logo_Figure.png \
   %reldir%/icons/graphic_logo_FileEditor.png \
   %reldir%/icons/graphic_logo_FilesDockWidget.png \
   %reldir%/icons/graphic_logo_HistoryDockWidget.png \
@@ -132,14 +134,17 @@
 
 OCTAVE_GUI_SRC_MOC = \
   %reldir%/moc-external-editor-interface.cc \
+  %reldir%/moc-command-widget.cc \
   %reldir%/moc-dialog.cc \
   %reldir%/moc-documentation-dock-widget.cc \
   %reldir%/moc-documentation.cc \
+  %reldir%/moc-documentation-bookmarks.cc \
   %reldir%/moc-dw-main-window.cc \
   %reldir%/moc-files-dock-widget.cc \
   %reldir%/moc-gui-settings.cc \
   %reldir%/moc-history-dock-widget.cc \
   %reldir%/moc-interpreter-qobject.cc \
+  %reldir%/moc-led-indicator.cc \
   %reldir%/moc-main-window.cc \
   %reldir%/moc-news-reader.cc \
   %reldir%/moc-octave-qobject.cc \
@@ -182,13 +187,16 @@
 BUILT_SOURCES += $(octave_gui_UI_H)
 
 noinst_HEADERS += \
+  %reldir%/command-widget.h \
   %reldir%/dialog.h \
   %reldir%/octave-dock-widget.h \
   %reldir%/documentation-dock-widget.h \
   %reldir%/documentation.h \
+  %reldir%/documentation-bookmarks.h \
   %reldir%/dw-main-window.h \
   %reldir%/gui-preferences-all.h \
   %reldir%/gui-preferences-cs.h \
+  %reldir%/gui-preferences-dc.h \
   %reldir%/gui-preferences-dw.h \
   %reldir%/gui-preferences-ed.h \
   %reldir%/gui-preferences-fb.h \
@@ -210,6 +218,7 @@
   %reldir%/graphics-init.h \
   %reldir%/history-dock-widget.h \
   %reldir%/interpreter-qobject.h \
+  %reldir%/led-indicator.h \
   %reldir%/m-editor/file-editor-interface.h \
   %reldir%/m-editor/file-editor-tab.h \
   %reldir%/m-editor/file-editor.h \
@@ -220,6 +229,7 @@
   %reldir%/main-window.h \
   %reldir%/news-reader.h \
   %reldir%/octave-qobject.h \
+  %reldir%/octave-qtutils.h \
   %reldir%/qt-application.h \
   %reldir%/qt-interpreter-events.h \
   %reldir%/qt-utils.h \
@@ -237,13 +247,16 @@
   %reldir%/variable-editor.h \
   %reldir%/variable-editor-model.h \
   %reldir%/set-path-dialog.h \
-  %reldir%/set-path-model.h
+  %reldir%/set-path-model.h \
+  %reldir%/gui-utils.h
 
 
 %canon_reldir%_%canon_reldir%_la_SOURCES = \
+  %reldir%/command-widget.cc \
   %reldir%/dialog.cc \
   %reldir%/documentation-dock-widget.cc \
   %reldir%/documentation.cc \
+  %reldir%/documentation-bookmarks.cc \
   %reldir%/dw-main-window.cc \
   %reldir%/external-editor-interface.cc \
   %reldir%/files-dock-widget.cc \
@@ -251,6 +264,7 @@
   %reldir%/gui-settings.cc \
   %reldir%/history-dock-widget.cc \
   %reldir%/interpreter-qobject.cc \
+  %reldir%/led-indicator.cc \
   %reldir%/m-editor/file-editor-tab.cc \
   %reldir%/m-editor/file-editor.cc \
   %reldir%/m-editor/find-dialog.cc \
@@ -277,7 +291,8 @@
   %reldir%/variable-editor.cc \
   %reldir%/variable-editor-model.cc \
   %reldir%/set-path-dialog.cc \
-  %reldir%/set-path-model.cc
+  %reldir%/set-path-model.cc \
+  %reldir%/gui-utils.cc
 
 nodist_%canon_reldir%_%canon_reldir%_la_SOURCES = \
   $(octave_gui_MOC) \
--- a/libgui/src/octave-dock-widget.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/octave-dock-widget.cc	Sun May 16 09:44:35 2021 +0200
@@ -41,6 +41,7 @@
 #include "gui-preferences-mw.h"
 #include "gui-preferences-sc.h"
 #include "gui-settings.h"
+#include "main-window.h"
 #include "octave-dock-widget.h"
 #include "octave-qobject.h"
 
@@ -183,59 +184,51 @@
 
   octave_dock_widget::octave_dock_widget (const QString& obj_name, QWidget *p,
                                           base_qobject& oct_qobj)
-    : label_dock_widget (p, oct_qobj), m_recent_float_geom (),
-      m_recent_dock_geom (), m_waiting_for_mouse_button_release (false)
+    : label_dock_widget (p, oct_qobj), m_focus_follows_mouse (false),
+      m_recent_float_geom (), m_recent_dock_geom (),
+      m_waiting_for_mouse_button_release (false)
   {
     setObjectName (obj_name);
 
-    m_parent = static_cast<QMainWindow *> (p);     // store main window
+    // FIXME: Can we avoid the cast here?
+    m_main_window = dynamic_cast<main_window *> (p);
+
     m_predecessor_widget = nullptr;
 
-    connect (this, SIGNAL (topLevelChanged (bool)),
-             this, SLOT (toplevel_change (bool)));
-    connect (this, SIGNAL (visibilityChanged (bool)),
-             this, SLOT (handle_visibility_changed (bool)));
-
-    connect (p, SIGNAL (settings_changed (const gui_settings *)),
-             this, SLOT (handle_settings (const gui_settings *)));
-
-    connect (p, SIGNAL (active_dock_changed (octave_dock_widget*,
-                                             octave_dock_widget*)),
-             this, SLOT (handle_active_dock_changed (octave_dock_widget*,
-                                                     octave_dock_widget*)));
+    connect (this, &octave_dock_widget::topLevelChanged,
+             this, &octave_dock_widget::toplevel_change);
+    connect (this, &octave_dock_widget::visibilityChanged,
+             this, &octave_dock_widget::handle_visibility);
 
     if (m_default_float_button != nullptr)
       {
         disconnect (m_default_float_button, 0, 0, 0);
-        connect (m_default_float_button, SIGNAL (clicked (bool)),
-                 this, SLOT (make_window (bool)));
+        connect (m_default_float_button, &QAbstractButton::clicked,
+                 this, &octave_dock_widget::make_window);
       }
-    connect (this, SIGNAL (queue_make_window (bool)),
-             this, SLOT (make_window (bool)), Qt::QueuedConnection);
-    connect (this, SIGNAL (queue_make_widget ()),
-             this, SLOT (make_widget ()), Qt::QueuedConnection);
+    connect (this, &octave_dock_widget::queue_make_window,
+             this, &octave_dock_widget::make_window, Qt::QueuedConnection);
+    connect (this, &octave_dock_widget::queue_make_widget,
+             this, [=] () { make_widget (); }, Qt::QueuedConnection);
 
     shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager ();
     scmgr.set_shortcut (m_dock_action, sc_dock_widget_dock);
     m_dock_action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
     addAction (m_dock_action);
-    connect (m_dock_action, SIGNAL (triggered (bool)),
-             this, SLOT (make_window (bool)));
+    connect (m_dock_action, &QAction::triggered,
+             this, &octave_dock_widget::make_window);
 
     scmgr.set_shortcut (m_close_action, sc_dock_widget_close);
     m_close_action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
     addAction (m_close_action);
-    connect (m_close_action, SIGNAL (triggered (bool)),
-             this, SLOT (change_visibility (bool)));
-
-    // Any interpreter_event signal from an octave_dock_widget object is
-    // handled the same as for the parent main_window object.
+    connect (m_close_action, &QAction::triggered,
+             this, &octave_dock_widget::change_visibility);
 
-    connect (this, SIGNAL (interpreter_event (const fcn_callback&)),
-             p, SIGNAL (interpreter_event (const fcn_callback&)));
+    connect (this, QOverload<const fcn_callback&>::of (&octave_dock_widget::interpreter_event),
+             &oct_qobj, QOverload<const fcn_callback&>::of (&base_qobject::interpreter_event));
 
-    connect (this, SIGNAL (interpreter_event (const meth_callback&)),
-             p, SIGNAL (interpreter_event (const meth_callback&)));
+    connect (this, QOverload<const meth_callback&>::of (&octave_dock_widget::interpreter_event),
+             &oct_qobj, QOverload<const meth_callback&>::of (&base_qobject::interpreter_event));
 
     m_close_action->setToolTip (tr ("Hide widget"));
 
@@ -262,12 +255,9 @@
     handle_settings (rmgr.get_settings ());
   }
 
-  // connect signal visibility changed to related slot (called from main-window)
   void
-  octave_dock_widget::connect_visibility_changed (void)
+  octave_dock_widget::init_window_menu_entry (void)
   {
-    connect (this, SIGNAL (visibilityChanged (bool)),
-             this, SLOT (handle_visibility (bool)));
     emit active_changed (isVisible ());  // emit once for init of window menu
   }
 
@@ -291,10 +281,14 @@
     if (isFloating ())
       setFloating (false);
 
-    // Before making it a separate (no more parent) floating widget, remove
-    // the dock widget from the main window. This ensures that tabbed widgets
-    // keep their focus when it is re-docked later
-    m_parent->removeDockWidget (this);
+    if (m_main_window)
+      {
+        // Before making it a separate (no more parent) floating widget,
+        // remove the dock widget from the main window. This ensures
+        // that tabbed widgets keep their focus when it is re-docked
+        // later
+        m_main_window->removeDockWidget (this);
+      }
 
     setParent (0, Qt::CustomizeWindowHint | Qt::WindowTitleHint |
                Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::Window);
@@ -308,8 +302,8 @@
 
     // adjust the (un)dock action
     disconnect (m_dock_action, 0, this, 0);
-    connect (m_dock_action, SIGNAL (triggered (bool)),
-             this, SLOT (make_widget (bool)));
+    connect (m_dock_action, &QAction::triggered,
+             this, &octave_dock_widget::make_widget);
 
     // adjust the (un)dock icon
     if (titleBarWidget ())
@@ -321,8 +315,8 @@
     else
       {
         disconnect (m_default_float_button, 0, this, 0);
-        connect (m_default_float_button, SIGNAL (clicked (bool)),
-                 this, SLOT (make_widget (bool)));
+        connect (m_default_float_button, &QAbstractButton::clicked,
+                 this, &octave_dock_widget::make_widget);
       }
 
     raise ();
@@ -348,22 +342,26 @@
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
     gui_settings *settings = rmgr.get_settings ();
 
-    settings->setValue (mw_state.key, m_parent->saveState ());
-    // Stay window, otherwise will bounce back to window by default because
-    // there is no layout information for this widget in the saved settings.
-    setParent (m_parent, Qt::Window);
-    m_parent->addDockWidget (Qt::BottomDockWidgetArea, this);
-    // recover old window states, hide and re-show new added widget
-    m_parent->restoreState (settings->value (mw_state.key).toByteArray ());
-    setFloating (false);
-    // restore size using setGeometry instead of restoreGeometry following
-    // this post:
-    // https://forum.qt.io/topic/79326/qdockwidget-restoregeometry-not-working-correctly-when-qmainwindow-is-maximized/5
-    setGeometry (m_recent_dock_geom);
+    if (m_main_window)
+      {
+        settings->setValue (mw_state.key, m_main_window->saveState ());
+        // Stay window, otherwise will bounce back to window by default
+        // because there is no layout information for this widget in the
+        // saved settings.
+        setParent (m_main_window, Qt::Window);
+        m_main_window->addDockWidget (Qt::BottomDockWidgetArea, this);
+        // recover old window states, hide and re-show new added widget
+        m_main_window->restoreState (settings->value (mw_state.key).toByteArray ());
+        setFloating (false);
+        // restore size using setGeometry instead of restoreGeometry
+        // following this post:
+        // https://forum.qt.io/topic/79326/qdockwidget-restoregeometry-not-working-correctly-when-qmainwindow-is-maximized/5
+        setGeometry (m_recent_dock_geom);
+      }
 
     // adjust the (un)dock icon
-    connect (m_dock_action, SIGNAL (triggered (bool)),
-             this, SLOT (make_window (bool)));
+    connect (m_dock_action, &QAction::triggered,
+             this, &octave_dock_widget::make_window);
     if (titleBarWidget ())
       {
         m_dock_action->setIcon (QIcon (":/actions/icons/widget-undock"
@@ -373,8 +371,8 @@
     else
       {
         disconnect (m_default_float_button, 0, this, 0);
-        connect (m_default_float_button, SIGNAL (clicked (bool)),
-                 this, SLOT (make_window (bool)));
+        connect (m_default_float_button, &QAbstractButton::clicked,
+                 this, &octave_dock_widget::make_window);
       }
 
     raise ();
@@ -402,6 +400,27 @@
     m_predecessor_widget = prev_widget;
   }
 
+  void
+  octave_dock_widget::set_main_window (main_window *mw)
+  {
+    m_main_window = mw;
+
+    if (m_main_window)
+      {
+        connect (m_main_window, &main_window::copyClipboard_signal,
+                 this, &octave_dock_widget::copyClipboard);
+
+        connect (m_main_window, &main_window::pasteClipboard_signal,
+                 this, &octave_dock_widget::pasteClipboard);
+
+        connect (m_main_window, &main_window::selectAll_signal,
+                 this, &octave_dock_widget::selectAll);
+
+        connect (m_main_window, &main_window::undo_signal,
+                 this, &octave_dock_widget::do_undo);
+      }
+  }
+
   // close event
   void
   octave_dock_widget::closeEvent (QCloseEvent *e)
@@ -446,6 +465,11 @@
   void
   octave_dock_widget::handle_settings (const gui_settings *settings)
   {
+    if (! settings)
+      return;
+
+    m_focus_follows_mouse = settings->value (dw_focus_follows_mouse).toBool ();
+
     m_custom_style
       = settings->value (dw_title_custom_style).toBool ();
 
@@ -484,38 +508,38 @@
     else
       m_icon_color_active = "";
 
-    QRect available_size = QApplication::desktop ()->availableGeometry (m_parent);
-    int x, y, w, h;
-    available_size.getRect (&x, &y, &w, &h);
-    QRect default_floating_size = QRect (x+16, y+32, w/3, h/2);
-    m_parent->geometry ().getRect (&x, &y, &w, &h);
-    QRect default_dock_size = QRect (x+16, y+32, w/3, h/3);
+    if (m_main_window)
+      {
+        QRect available_size
+          = QApplication::desktop ()->availableGeometry (m_main_window);
 
-    m_recent_float_geom
-      = settings->value (dw_float_geometry.key.arg (objectName ()),
-                         default_floating_size).toRect ();
+        int x, y, w, h;
+        available_size.getRect (&x, &y, &w, &h);
+        QRect default_floating_size = QRect (x+16, y+32, w/3, h/2);
+        m_main_window->geometry ().getRect (&x, &y, &w, &h);
+        QRect default_dock_size = QRect (x+16, y+32, w/3, h/3);
 
-    QWidget dummy;
-    dummy.setGeometry (m_recent_float_geom);
+        m_recent_float_geom
+          = settings->value (dw_float_geometry.key.arg (objectName ()),
+                             default_floating_size).toRect ();
 
-    if (QApplication::desktop ()->screenNumber (&dummy) == -1)
-      m_recent_float_geom = default_floating_size;
+        QWidget dummy;
+        dummy.setGeometry (m_recent_float_geom);
+
+        if (QApplication::desktop ()->screenNumber (&dummy) == -1)
+          m_recent_float_geom = default_floating_size;
 
-    // The following is required for ensure smooth transition from old
-    // saveGeomety to new QRect setting (see comment for restoring size
-    // of docked widgets)
-    QVariant dock_geom
-      = settings->value (dw_dock_geometry.key.arg (objectName ()),
-                         default_dock_size);
-#if defined (QVARIANT_CANCONVERT_ACCEPTS_QMETATYPE_TYPE)
-    QMetaType::Type rect_type = QMetaType::QRect;
-#else
-    QVariant::Type rect_type = QVariant::Rect;
-#endif
-    if (dock_geom.canConvert (rect_type))
-      m_recent_dock_geom = dock_geom.toRect ();
-    else
-      m_recent_dock_geom = dw_dock_geometry.def.toRect ();
+        // The following is required for ensure smooth transition from old
+        // saveGeomety to new QRect setting (see comment for restoring size
+        // of docked widgets)
+        QVariant dock_geom
+          = settings->value (dw_dock_geometry.key.arg (objectName ()),
+                             default_dock_size);
+        if (dock_geom.canConvert (QMetaType::QRect))
+          m_recent_dock_geom = dock_geom.toRect ();
+        else
+          m_recent_dock_geom = dw_dock_geometry.def.toRect ();
+      }
 
     notice_settings (settings);  // call individual handler
 
@@ -577,12 +601,19 @@
 
   bool octave_dock_widget::eventFilter (QObject *obj, QEvent *e)
   {
+    // Ignore double clicks into window decoration elements
     if (e->type () == QEvent::NonClientAreaMouseButtonDblClick)
       {
-        e->ignore (); // ignore double clicks into window decoration elements
+        e->ignore ();
         return true;
       }
 
+    // Detect mouse enter events if "focus follows mouse" is desired
+    // for widgets docked to the main window (non floating) and activate
+    // the widget currently under the mouse
+    if (m_focus_follows_mouse && ! isFloating () && (e->type () == QEvent::Enter))
+      activate ();
+
     return QDockWidget::eventFilter (obj,e);
   }
 
@@ -636,8 +667,12 @@
 
   void octave_dock_widget::handle_visibility (bool visible)
   {
-    if (visible && ! isFloating ())
-      setFocus ();
+    if (visible)
+      {
+        emit active_changed (true);
+        if (! isFloating ())
+          setFocus ();
+      }
   }
 
   void
--- a/libgui/src/octave-dock-widget.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/octave-dock-widget.h	Sun May 16 09:44:35 2021 +0200
@@ -28,7 +28,6 @@
 
 #include <QDockWidget>
 #include <QIcon>
-#include <QMainWindow>
 #include <QMouseEvent>
 #include <QToolButton>
 
@@ -38,6 +37,7 @@
 namespace octave
 {
   class base_qobject;
+  class main_window;
 
   // The few decoration items common to both main window and variable editor.
 
@@ -49,6 +49,8 @@
 
     label_dock_widget (QWidget *p, base_qobject& oct_qobj);
 
+    ~label_dock_widget (void) = default;
+
     // set_title() uses the custom title bar while setWindowTitle() uses
     // the default title bar (with style sheets)
     void set_title (const QString&);
@@ -90,12 +92,12 @@
     octave_dock_widget (const QString& obj_name, QWidget *p,
                         base_qobject& oct_qobj);
 
-    virtual ~octave_dock_widget (void) = default;
-
-    virtual void connect_visibility_changed (void);
+    ~octave_dock_widget (void) = default;
 
     void set_predecessor_widget (octave_dock_widget *prev_widget);
 
+    void set_main_window (main_window *mw);
+
   signals:
 
     //! Custom signal that tells whether a user has clicked away that dock
@@ -126,12 +128,12 @@
 
     virtual void notice_settings (const gui_settings *) { }
 
+    void init_window_menu_entry (void);
+
     void handle_settings (const gui_settings *);
 
     void handle_active_dock_changed (octave_dock_widget*, octave_dock_widget*);
 
-    QMainWindow * main_win (void) { return m_parent; }
-
     void save_settings (void);
 
     void moveEvent (QMoveEvent *event);
@@ -148,14 +150,6 @@
 
     virtual void toplevel_change (bool);
 
-    //! Slot to steer changing visibility from outside.
-
-    virtual void handle_visibility_changed (bool visible)
-    {
-      if (visible)
-        emit active_changed (true);
-    }
-
     //! Event filter for double clicks into the window decoration elements.
 
     bool eventFilter (QObject *obj, QEvent *e);
@@ -172,9 +166,10 @@
 
     //! Stores the parent, since we are reparenting to 0.
 
-    QMainWindow *m_parent;
+    main_window *m_main_window;
 
     bool m_custom_style;
+    bool m_focus_follows_mouse;
     int m_title_3d;
     QColor m_bg_color;
     QColor m_bg_color_active;
@@ -186,7 +181,6 @@
     QRect m_recent_float_geom;
     QRect m_recent_dock_geom;
     bool m_waiting_for_mouse_button_release;
-
   };
 }
 
--- a/libgui/src/octave-qobject.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/octave-qobject.cc	Sun May 16 09:44:35 2021 +0200
@@ -37,6 +37,9 @@
 #include <QTimer>
 #include <QTranslator>
 
+#include "documentation-dock-widget.h"
+#include "files-dock-widget.h"
+#include "history-dock-widget.h"
 #include "interpreter-qobject.h"
 #include "main-window.h"
 #include "octave-qobject.h"
@@ -44,6 +47,9 @@
 #include "qt-interpreter-events.h"
 #include "resource-manager.h"
 #include "shortcut-manager.h"
+#include "variable-editor.h"
+#include "workspace-model.h"
+#include "workspace-view.h"
 
 // Bug #55940 (Disable App Nap on Mac)
 #if defined (Q_OS_MAC)
@@ -51,6 +57,7 @@
 #  include <objc/message.h>
 #endif
 
+#include "interpreter.h"
 #include "oct-env.h"
 #include "version.h"
 
@@ -119,11 +126,7 @@
   // Disable all Qt messages by default.
 
   static void
-#if defined (QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT)
   message_handler (QtMsgType, const QMessageLogContext &, const QString &)
-#else
-  message_handler (QtMsgType, const char *)
-#endif
   { }
 
   //! Reimplement QApplication::notify.  Octave's own exceptions are
@@ -138,10 +141,9 @@
     catch (execution_exception& ee)
       {
         emit interpreter_event
-          ([ee] (void)
+          ([=] (void)
            {
              // INTERPRETER THREAD
-
              throw ee;
            });
       }
@@ -158,17 +160,31 @@
   // we can handle forward Octave interpreter exceptions from the GUI
   // thread to the interpreter thread.
 
-  base_qobject::base_qobject (qt_application& app_context)
-    : QObject (), m_app_context (app_context),
+  base_qobject::base_qobject (qt_application& app_context, bool gui_app)
+    : QObject (),
+      m_app_context (app_context),
       m_argc (m_app_context.sys_argc ()),
       m_argv (m_app_context.sys_argv ()),
       m_qapplication (new octave_qapplication (m_argc, m_argv)),
-      m_resource_manager (), m_shortcut_manager (*this),
-      m_qt_tr (new QTranslator ()), m_gui_tr (new QTranslator ()),
-      m_qsci_tr (new QTranslator ()), m_translators_installed (false),
+      m_resource_manager (),
+      m_shortcut_manager (*this),
+      m_qt_tr (new QTranslator ()),
+      m_gui_tr (new QTranslator ()),
+      m_qsci_tr (new QTranslator ()),
+      m_translators_installed (false),
       m_qt_interpreter_events (new qt_interpreter_events (*this)),
       m_interpreter_qobj (new interpreter_qobject (*this)),
-      m_main_thread (new QThread ())
+      m_main_thread (new QThread ()),
+      m_gui_app (gui_app),
+      m_interpreter_ready (false),
+      m_workspace_model (new workspace_model (*this)),
+      m_documentation_widget (),
+      m_file_browser_widget (),
+      m_history_widget (),
+      m_workspace_widget (),
+      m_editor_widget (),
+      m_variable_editor_widget (),
+      m_main_window (nullptr)
   {
     std::string show_gui_msgs =
       sys::env::getenv ("OCTAVE_SHOW_GUI_MESSAGES");
@@ -176,23 +192,13 @@
     // Installing our handler suppresses the messages.
 
     if (show_gui_msgs.empty ())
-      {
-#if defined (HAVE_QINSTALLMESSAGEHANDLER)
-        qInstallMessageHandler (message_handler);
-#else
-        qInstallMsgHandler (message_handler);
-#endif
-      }
+      qInstallMessageHandler (message_handler);
 
     // Set the codec for all strings (before wizard or any GUI object)
 #if ! defined (Q_OS_WIN32)
     QTextCodec::setCodecForLocale (QTextCodec::codecForName ("UTF-8"));
 #endif
 
-#if defined (HAVE_QT4)
-    QTextCodec::setCodecForCStrings (QTextCodec::codecForName ("UTF-8"));
-#endif
-
     // Initialize global Qt application metadata.
 
     QCoreApplication::setApplicationName ("GNU Octave");
@@ -202,7 +208,6 @@
 
     qRegisterMetaType<octave_value_list> ("octave_value_list");
 
-
 // Bug #55940 (Disable App Nap on Mac)
 #if defined (Q_OS_MAC)
     // Mac App Nap feature causes pause() and sleep() to misbehave.
@@ -213,30 +218,86 @@
     // Force left-to-right alignment (see bug #46204)
     m_qapplication->setLayoutDirection (Qt::LeftToRight);
 
-    connect (m_interpreter_qobj, SIGNAL (execution_finished (int)),
-             this, SLOT (handle_interpreter_execution_finished (int)));
-
-    connect (this, SIGNAL (request_interpreter_shutdown (int)),
-             m_interpreter_qobj, SLOT (shutdown (int)));
+    // Qt docs recommend using Qt::QueuedConnection when connecting to
+    // the QCoreApplication::exit slot.
+    connect (m_interpreter_qobj, &interpreter_qobject::shutdown_finished,
+             m_qapplication, &octave_qapplication::exit,
+             Qt::QueuedConnection);
 
-    connect (m_interpreter_qobj, SIGNAL (shutdown_finished (int)),
-             this, SLOT (handle_interpreter_shutdown_finished (int)));
-
-    connect (m_main_thread, SIGNAL (finished (void)),
-             m_main_thread, SLOT (deleteLater (void)));
+    connect (m_main_thread, &QThread::finished,
+             m_main_thread, &QThread::deleteLater);
 
     // Handle any interpreter_event signal from the octave_qapplication
     // object here.
 
-    connect (m_qapplication, SIGNAL (interpreter_event (const fcn_callback&)),
-             this, SLOT (interpreter_event (const fcn_callback&)));
+    connect (m_qapplication, QOverload<const fcn_callback&>::of (&octave_qapplication::interpreter_event),
+             this, QOverload<const fcn_callback&>::of (&base_qobject::interpreter_event));
+
+    connect (m_qapplication, QOverload<const meth_callback&>::of (&octave_qapplication::interpreter_event),
+             this, QOverload<const meth_callback&>::of (&base_qobject::interpreter_event));
+
+    if (m_app_context.experimental_terminal_widget ())
+      connect (qt_link (), &qt_interpreter_events::start_gui_signal,
+               this, &base_qobject::start_gui);
+
+    connect (qt_link (), &qt_interpreter_events::copy_image_to_clipboard_signal,
+             this, &base_qobject::copy_image_to_clipboard);
+
+    // Get settings file.
+    m_resource_manager.reload_settings ();
+
+    // After settings.
+    config_translators ();
+
+    connect (qt_link (), &qt_interpreter_events::show_documentation_signal,
+             this, &base_qobject::show_documentation_window);
+
+    connect (qt_link (), &qt_interpreter_events::show_file_browser_signal,
+             this, &base_qobject::show_file_browser_window);
+
+    connect (qt_link (), &qt_interpreter_events::show_command_history_signal,
+             this, &base_qobject::show_command_history_window);
+
+    connect (qt_link (), &qt_interpreter_events::show_workspace_signal,
+             this, &base_qobject::show_workspace_window);
+
+    connect (qt_link (), &qt_interpreter_events::edit_variable_signal,
+             this, &base_qobject::edit_variable);
 
-    connect (m_qapplication, SIGNAL (interpreter_event (const meth_callback&)),
-             this, SLOT (interpreter_event (const meth_callback&)));
+    if (m_app_context.experimental_terminal_widget ())
+      {
+        m_qapplication->setQuitOnLastWindowClosed (false);
+      }
+    else
+      {
+        if (gui_app)
+          {
+            m_main_window = new main_window (*this);
+
+            if (m_interpreter_ready)
+              m_main_window->handle_octave_ready ();
+            else
+              connect (m_interpreter_qobj, &interpreter_qobject::ready,
+                       m_main_window, &main_window::handle_octave_ready);
 
-    connect (qt_link (),
-             SIGNAL (copy_image_to_clipboard_signal (const QString&, bool)),
-             this, SLOT (copy_image_to_clipboard (const QString&, bool)));
+            connect (qt_link (), &qt_interpreter_events::focus_window_signal,
+                     m_main_window, &main_window::focus_window);
+
+            m_app_context.gui_running (true);
+          }
+        else
+          {
+            // Get settings file.
+            m_resource_manager.reload_settings ();
+
+            // After settings.
+            config_translators ();
+
+            m_qapplication->setQuitOnLastWindowClosed (false);
+          }
+      }
+
+    start_main_thread ();
   }
 
   base_qobject::~base_qobject (void)
@@ -245,11 +306,14 @@
     // deleteLater slot that is called when the m_main_thread issues a
     // finished signal.
 
+    delete m_main_window;
+
     delete m_interpreter_qobj;
     delete m_qsci_tr;
     delete m_gui_tr;
     delete m_qt_tr;
     delete m_qapplication;
+    delete m_workspace_model;
 
     string_vector::delete_c_str_vec (m_argv);
   }
@@ -270,8 +334,14 @@
 
   void base_qobject::start_main_thread (void)
   {
-    // Defer initializing and executing the interpreter until after the main
-    // window and QApplication are running to prevent race conditions
+    // Note: if using the new experimental terminal widget, we defer
+    // initializing and executing the interpreter until the main event
+    // loop begins executing.
+
+    // With the old terminal widget, we defer initializing and executing
+    // the interpreter until after the main window and QApplication are
+    // running to prevent race conditions.
+
     QTimer::singleShot (0, m_interpreter_qobj, SLOT (execute (void)));
 
     m_interpreter_qobj->moveToThread (m_main_thread);
@@ -281,21 +351,8 @@
 
   int base_qobject::exec (void)
   {
-    return m_qapplication->exec ();
-  }
-
-  bool base_qobject::confirm_shutdown (void)
-  {
-    return true;
-  }
+    int status = m_qapplication->exec ();
 
-  void base_qobject::handle_interpreter_execution_finished (int exit_status)
-  {
-    emit request_interpreter_shutdown (exit_status);
-  }
-
-  void base_qobject::handle_interpreter_shutdown_finished (int exit_status)
-  {
 #if defined (Q_OS_MAC)
     // fprintf to stderr is needed by macOS, for poorly-understood reasons.
     fprintf (stderr, "\n");
@@ -304,7 +361,296 @@
     m_main_thread->quit ();
     m_main_thread->wait ();
 
-    qApp->exit (exit_status);
+    return status;
+  }
+
+  // Provided for convenience.  Will be removed once we eliminate the
+  // old terminal widget.
+  bool base_qobject::experimental_terminal_widget (void) const
+  {
+    return m_app_context.experimental_terminal_widget ();
+  }
+
+  bool base_qobject::gui_running (void) const
+  {
+    return m_app_context.gui_running ();
+  }
+
+  QPointer<documentation_dock_widget>
+  base_qobject::documentation_widget (main_window *mw)
+  {
+    if (m_documentation_widget)
+      m_documentation_widget->set_main_window (mw);
+    else
+      m_documentation_widget
+        = QPointer<documentation_dock_widget> (new documentation_dock_widget (mw, *this));
+
+    connect (qt_link (), &qt_interpreter_events::register_documentation_signal,
+             m_documentation_widget, &documentation_dock_widget::registerDoc);
+
+    connect (qt_link (), &qt_interpreter_events::unregister_documentation_signal,
+             m_documentation_widget, &documentation_dock_widget::unregisterDoc);
+
+    return m_documentation_widget;
+  }
+
+  QPointer<files_dock_widget>
+  base_qobject::file_browser_widget (main_window *mw)
+  {
+    if (m_file_browser_widget)
+      m_file_browser_widget->set_main_window (mw);
+    else
+      m_file_browser_widget
+        = QPointer<files_dock_widget> (new files_dock_widget (mw, *this));
+
+    return m_file_browser_widget;
+  }
+
+  QPointer<history_dock_widget>
+  base_qobject::history_widget (main_window *mw)
+  {
+    if (m_history_widget)
+      m_history_widget->set_main_window (mw);
+    else
+      m_history_widget
+        = QPointer<history_dock_widget> (new history_dock_widget (mw, *this));
+
+    connect (qt_link (), &qt_interpreter_events::set_history_signal,
+             m_history_widget, &history_dock_widget::set_history);
+
+    connect (qt_link (), &qt_interpreter_events::append_history_signal,
+             m_history_widget, &history_dock_widget::append_history);
+
+    connect (qt_link (), &qt_interpreter_events::clear_history_signal,
+             m_history_widget, &history_dock_widget::clear_history);
+
+    qt_link()->set_history (octave::command_history::list ());
+
+    return m_history_widget;
+  }
+
+  QPointer<workspace_view>
+  base_qobject::workspace_widget (main_window *mw)
+  {
+    if (m_workspace_widget)
+      m_workspace_widget->set_main_window (mw);
+    else
+      m_workspace_widget
+        = QPointer<workspace_view> (new workspace_view (mw, *this));
+
+    m_workspace_widget->setModel (m_workspace_model);
+
+    connect (m_workspace_model, &workspace_model::model_changed,
+             m_workspace_widget, &workspace_view::handle_model_changed);
+
+    connect (qt_link (), &qt_interpreter_events::set_workspace_signal,
+             m_workspace_model, &workspace_model::set_workspace);
+
+    connect (qt_link (), &qt_interpreter_events::clear_workspace_signal,
+             m_workspace_model, &workspace_model::clear_workspace);
+
+    return m_workspace_widget;
+  }
+
+  QPointer<file_editor_interface>
+  base_qobject::editor_widget (main_window */*mw*/)
+  {
+#if 0
+    if (m_editor_widget)
+      m_editor_widget->set_main_window (mw);
+    else
+      m_editor_widget = new file_editor (mw, *this);
+#endif
+
+    return m_editor_widget;
+  }
+
+  QPointer<variable_editor>
+  base_qobject::variable_editor_widget (main_window *mw)
+  {
+    if (m_variable_editor_widget)
+      m_variable_editor_widget->set_main_window (mw);
+    else
+      m_variable_editor_widget
+        = QPointer<variable_editor> (new variable_editor (mw, *this));
+
+    return m_variable_editor_widget;
+  }
+
+  bool base_qobject::confirm_shutdown (void)
+  {
+    // Currently, we forward to main_window::confirm_shutdown instead of
+    // just displaying a dialog box here because the main_window also
+    // knows about and is responsible for notifying the editor.
+
+    return m_main_window ? m_main_window->confirm_shutdown () : true;
+  }
+
+  void base_qobject::start_gui (bool gui_app)
+  {
+    if (m_app_context.experimental_terminal_widget ())
+      {
+        if (m_main_window)
+          return;
+
+        m_gui_app = gui_app;
+
+        m_main_window = new main_window (*this);
+
+        connect (qt_link (), &qt_interpreter_events::focus_window_signal,
+                 m_main_window, &main_window::focus_window);
+
+        connect (qt_link (), &qt_interpreter_events::close_gui_signal,
+                 this, &base_qobject::close_gui);
+
+        connect (m_main_window, &main_window::close_gui_signal,
+                 this, &base_qobject::close_gui);
+
+        if (m_interpreter_ready)
+          m_main_window->handle_octave_ready ();
+        else
+          connect (m_interpreter_qobj, &interpreter_qobject::ready,
+                   m_main_window, &main_window::handle_octave_ready);
+
+        if (m_gui_app)
+          m_qapplication->setQuitOnLastWindowClosed (true);
+        else
+          {
+            // FIXME: Save current values of PS1 and PS2 so they can be
+            // restored when we return to the command line?
+          }
+
+        m_app_context.gui_running (true);
+      }
+  }
+
+  void base_qobject::show_documentation_window (const QString& file)
+  {
+    documentation_dock_widget *widget = documentation_widget ();
+
+    widget->showDoc (file);
+
+    if (! widget->isVisible ())
+      {
+        widget->show ();
+        widget->raise ();
+      }
+  }
+
+  void base_qobject::show_file_browser_window (void)
+  {
+    files_dock_widget *widget = file_browser_widget ();
+
+    if (! widget->isVisible ())
+      {
+        widget->show ();
+        widget->raise ();
+      }
+  }
+
+  void base_qobject::show_command_history_window (void)
+  {
+    history_dock_widget *widget = history_widget ();
+
+    if (! widget->isVisible ())
+      {
+        widget->show ();
+        widget->raise ();
+      }
+  }
+
+  void base_qobject::show_workspace_window (void)
+  {
+    workspace_view *widget = workspace_widget ();
+
+    if (! widget->isVisible ())
+      {
+        widget->show ();
+        widget->raise ();
+      }
+  }
+
+  void base_qobject::edit_variable (const QString& expr,
+                                    const octave_value& val)
+  {
+    variable_editor *widget = variable_editor_widget ();
+
+#if 0
+    // FIXME: This connection needs to be made whether running with the
+    // GUI main window or not, but only needs to be made once.
+    // Currently we have handle_variable_editor_update methods here and
+    // in the main_window object.
+
+    connect (widget, &variable_editor::updated,
+             this, &base_qobject::handle_variable_editor_update);
+#endif
+
+    widget->edit_variable (expr, val);
+
+    if (! widget->isVisible ())
+      {
+        widget->show ();
+        widget->raise ();
+      }
+  }
+
+  void base_qobject::handle_variable_editor_update (void)
+  {
+    // Called when the variable editor emits the updated signal.  The size
+    // of a variable may have changed, so we refresh the workspace in the
+    // interpreter.  That will eventually cause the workspace view in the
+    // GUI to be updated.
+
+    interpreter_event
+      ([] (interpreter& interp)
+       {
+         // INTERPRETER THREAD
+
+         tree_evaluator& tw = interp.get_evaluator ();
+
+         event_manager& xevmgr = interp.get_event_manager ();
+
+         xevmgr.set_workspace (true, tw.get_symbol_info (), false);
+       });
+  }
+
+  void base_qobject::close_gui (void)
+  {
+    if (m_app_context.experimental_terminal_widget ())
+      {
+        if (! m_main_window)
+          return;
+
+        // FIXME: Restore previous values of PS1 and PS2 if we are
+        // returning to the command line?
+
+        interpreter_event
+          ([=] (interpreter& interp)
+          {
+            // INTERPRETER THREAD
+
+            application *app = interp.get_app_context ();
+
+            cmdline_options opts = app->options ();
+
+            if (opts.gui ())
+              interp.quit (0, false, false);
+          });
+
+        m_app_context.gui_running (false);
+
+        if (m_main_window)
+          {
+            m_main_window->deleteLater ();
+
+            m_main_window = nullptr;
+          }
+      }
+  }
+
+  void base_qobject::interpreter_ready (void)
+  {
+    m_interpreter_ready = true;
   }
 
   void base_qobject::interpreter_event (const fcn_callback& fcn)
@@ -331,6 +677,32 @@
     m_interpreter_qobj->interpreter_event (meth);
   }
 
+  void base_qobject::interpreter_interrupt (void)
+  {
+    m_interpreter_qobj->interrupt ();
+  }
+
+  // FIXME: Should we try to make the pause, stop, and resume actions
+  // work for both the old and new terminal widget?
+
+  void base_qobject::interpreter_pause (void)
+  {
+    if (m_app_context.experimental_terminal_widget ())
+      m_interpreter_qobj->pause ();
+  }
+
+  void base_qobject::interpreter_stop (void)
+  {
+    if (m_app_context.experimental_terminal_widget ())
+      m_interpreter_qobj->stop ();
+  }
+
+  void base_qobject::interpreter_resume (void)
+  {
+    if (m_app_context.experimental_terminal_widget ())
+      m_interpreter_qobj->resume ();
+  }
+
   void base_qobject::copy_image_to_clipboard (const QString& file,
                                               bool remove_file)
   {
@@ -349,47 +721,4 @@
     if (remove_file)
       QFile::remove (file);
   }
-
-  cli_qobject::cli_qobject (qt_application& app_context)
-    : base_qobject (app_context)
-  {
-    // Get settings file.
-    m_resource_manager.reload_settings ();
-
-    // After settings.
-    config_translators ();
-
-    m_qapplication->setQuitOnLastWindowClosed (false);
-
-    start_main_thread ();
-  }
-
-  gui_qobject::gui_qobject (qt_application& app_context)
-    : base_qobject (app_context), m_main_window (new main_window (*this))
-  {
-    connect (m_interpreter_qobj, SIGNAL (ready (void)),
-             m_main_window, SLOT (handle_octave_ready (void)));
-
-    connect (qt_link (),
-             SIGNAL (focus_window_signal (const QString&)),
-             m_main_window, SLOT (focus_window (const QString&)));
-
-    m_app_context.gui_running (true);
-
-    start_main_thread ();
-  }
-
-  gui_qobject::~gui_qobject (void)
-  {
-    delete m_main_window;
-  }
-
-  bool gui_qobject::confirm_shutdown (void)
-  {
-    // Currently, we forward to main_window::confirm_shutdown instead of
-    // just displaying a dialog box here because the main_window also
-    // knows about and is responsible for notifying the editor.
-
-    return m_main_window ? m_main_window->confirm_shutdown () : true;
-  }
 }
--- a/libgui/src/octave-qobject.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/octave-qobject.h	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
   //! reimplement QApplication::notify.  The octave_qapplication object
   //! should behave identically to a QApplication object except that it
   //! overrides the notify method so we can handle forward Octave
-  //! octave::execution_exception exceptions from the GUI thread to the
+  //! execution_exception exceptions from the GUI thread to the
   //! interpreter thread.
 
   class octave_qapplication : public QApplication
@@ -71,6 +71,22 @@
     void interpreter_event (const meth_callback& meth);
   };
 
+  //! Container for windows that may be created from the command line or
+  //! docked with the main GUI window.  Any of these windows that are
+  //! created in command line mode will be adopted by the main window if
+  //! it is opened from the command line.  Any that are undocked from
+  //! the main window will remain open if control returns to the command
+  //! line.
+
+  class base_qobject;
+  class documentation_dock_widget;
+  class file_editor_interface;
+  class files_dock_widget;
+  class history_dock_widget;
+  class variable_editor;
+  class workspace_model;
+  class workspace_view;
+
   //! Base class for Octave interfaces that use Qt.  There are two
   //! classes derived from this one.  One provides a command-line
   //! interface that may use Qt graphics and another provides the
@@ -82,7 +98,9 @@
 
   public:
 
-    base_qobject (qt_application& app_context);
+    // Note: the GUI_APP argument is not needed with the new
+    // experimental terminal widget.
+    base_qobject (qt_application& app_context, bool gui_app = false);
 
     ~base_qobject (void);
 
@@ -98,6 +116,13 @@
     // The Qt QApplication.
     QApplication * qapplication (void) { return m_qapplication; };
 
+    // Provided for convenience.  Will be removed once we eliminate the
+    // old terminal widget.
+    bool experimental_terminal_widget (void) const;
+
+    // Provided for convenience.
+    bool gui_running (void) const;
+
     resource_manager& get_resource_manager (void)
     {
       return m_resource_manager;
@@ -123,24 +148,72 @@
       return m_interpreter_qobj;
     }
 
+    workspace_model * get_workspace_model (void)
+    {
+      return m_workspace_model;
+    }
+
+    QPointer<documentation_dock_widget>
+    documentation_widget (main_window *mw = nullptr);
+
+    QPointer<files_dock_widget>
+    file_browser_widget (main_window *mw = nullptr);
+
+    QPointer<history_dock_widget>
+    history_widget (main_window *mw = nullptr);
+
+    QPointer<workspace_view>
+    workspace_widget (main_window *mw = nullptr);
+
+    // FIXME: The file_editor_interface needs to be a proper generic
+    // interface for all editors (internal and external) for this to
+    // work properly.
+    QPointer<file_editor_interface>
+    editor_widget (main_window *mw = nullptr);
+
+    QPointer<variable_editor>
+    variable_editor_widget (main_window *mw = nullptr);
+
     QThread *main_thread (void) { return m_main_thread; }
 
+    // Declared virtual so that a derived class may redefine this
+    // method.
+
     virtual bool confirm_shutdown (void);
 
-  signals:
-
-    void request_interpreter_shutdown (int);
-
   public slots:
 
-    void handle_interpreter_execution_finished (int);
+    // Note: START_GUI and CLOSE_GUI don't currently perform any work
+    // with the old terminal widget.
+    void start_gui (bool gui_app);
+    void close_gui (void);
+
+    void show_documentation_window (const QString& file);
+
+    void show_file_browser_window (void);
 
-    void handle_interpreter_shutdown_finished (int);
+    void show_command_history_window (void);
+
+    void show_workspace_window (void);
+
+    void edit_variable (const QString& expr, const octave_value& val);
+
+    void handle_variable_editor_update (void);
+
+    void interpreter_ready (void);
 
     void interpreter_event (const fcn_callback& fcn);
 
     void interpreter_event (const meth_callback& meth);
 
+    void interpreter_interrupt (void);
+
+    // Note: these currently only work with the new experimental
+    // terminal widget.
+    void interpreter_pause (void);
+    void interpreter_stop (void);
+    void interpreter_resume (void);
+
     void copy_image_to_clipboard (const QString& file, bool remove_file);
 
   protected:
@@ -170,38 +243,28 @@
     interpreter_qobject *m_interpreter_qobj;
 
     QThread *m_main_thread;
-  };
 
-  //! This object provides a command-line interface to Octave that may
-  //! use Qt graphics.
+    bool m_gui_app;
+
+    bool m_interpreter_ready;
 
-  class cli_qobject : public base_qobject
-  {
-    Q_OBJECT
+    workspace_model *m_workspace_model;
 
-  public:
-
-    cli_qobject (qt_application& app_context);
-
-    ~cli_qobject (void) = default;
-  };
+    // Dock widgets that may be used from the command line.  They are
+    // adopted by the desktop (main window) if it is also started from
+    // the command line.
 
-  //! This object provides a full GUI interface to Octave that is
-  //! implemented Qt.
+    QPointer<documentation_dock_widget> m_documentation_widget;
 
-  class gui_qobject : public base_qobject
-  {
-    Q_OBJECT
+    QPointer<files_dock_widget> m_file_browser_widget;
+
+    QPointer<history_dock_widget> m_history_widget;
 
-  public:
-
-    gui_qobject (qt_application& app_context);
+    QPointer<workspace_view> m_workspace_widget;
 
-    ~gui_qobject (void);
+    QPointer<file_editor_interface> m_editor_widget;
 
-    bool confirm_shutdown (void);
-
-  private:
+    QPointer<variable_editor> m_variable_editor_widget;
 
     main_window *m_main_window;
   };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/octave-qtutils.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,82 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2021 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_octave_qtutils_h)
+#define octave_octave_qtutils_h 1
+
+// This file should not be installed and should only be included in C++
+// source files after config.h is included, not in other header files.
+
+#if ! defined (HAVE_QOVERLOAD_TEMPLATE)
+
+// The following are copied directly from qglobal.h from Qt 5.15.2 with
+// Q_DECL_CONSTEXPR replaced by constexpr so that we don't have to
+// include any Qt headers or define any other special magic here.
+// Octave requires C++11 so using constexpr should be OK.
+
+template <typename... Args>
+struct QNonConstOverload
+{
+    template <typename R, typename T>
+    constexpr auto operator()(R (T::*ptr)(Args...)) const noexcept -> decltype(ptr)
+    { return ptr; }
+
+    template <typename R, typename T>
+    static constexpr auto of(R (T::*ptr)(Args...)) noexcept -> decltype(ptr)
+    { return ptr; }
+};
+
+template <typename... Args>
+struct QConstOverload
+{
+    template <typename R, typename T>
+    constexpr auto operator()(R (T::*ptr)(Args...) const) const noexcept -> decltype(ptr)
+    { return ptr; }
+
+    template <typename R, typename T>
+    static constexpr auto of(R (T::*ptr)(Args...) const) noexcept -> decltype(ptr)
+    { return ptr; }
+};
+
+template <typename... Args>
+struct QOverload : QConstOverload<Args...>, QNonConstOverload<Args...>
+{
+    using QConstOverload<Args...>::of;
+    using QConstOverload<Args...>::operator();
+    using QNonConstOverload<Args...>::of;
+    using QNonConstOverload<Args...>::operator();
+
+    template <typename R>
+    constexpr auto operator()(R (*ptr)(Args...)) const noexcept -> decltype(ptr)
+    { return ptr; }
+
+    template <typename R>
+    static constexpr auto of(R (*ptr)(Args...)) noexcept -> decltype(ptr)
+    { return ptr; }
+};
+
+#endif
+
+#endif
--- a/libgui/src/qt-application.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/qt-application.cc	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,10 @@
 
   bool qt_application::start_gui_p (void) const
   {
-    return m_options.gui ();
+    // Note: this function is not needed if using the experimental
+    // terminal widget, so return a dummy value of false in that case.
+
+    return experimental_terminal_widget () ? false : m_options.gui ();
   }
 
   int qt_application::execute (void)
@@ -62,15 +65,11 @@
 
     // Create and show main window.
 
-    if (start_gui_p ())
-      {
-        gui_qobject gui_interface (*this);
-        return gui_interface.exec ();
-      }
-    else
-      {
-        cli_qobject cli_interface (*this);
-        return cli_interface.exec ();
-      }
+    // Note: the second argument is ignored if using the new terminal
+    // widget.
+
+    base_qobject qt_interface (*this, start_gui_p ());
+
+    return qt_interface.exec ();
   }
 }
--- a/libgui/src/qt-application.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/qt-application.h	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
   // must be included only in the corresponding .cc file.
 
   //! This class inherits from the pure-virtual base class
-  //! octave::application and provides an implementation of the
+  //! application and provides an implementation of the
   //! application::execute method that starts an interface to Octave
   //! that is based on Qt.  It may start a command-line interface that
   //! allows Qt graphics to be used or it may start an interface that
--- a/libgui/src/qt-interpreter-events.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/qt-interpreter-events.cc	Sun May 16 09:44:35 2021 +0200
@@ -27,6 +27,9 @@
 #  include "config.h"
 #endif
 
+#include <iostream>
+#include <sstream>
+
 #include <QDialog>
 #include <QDir>
 #include <QIcon>
@@ -118,16 +121,26 @@
     qRegisterMetaType<fcn_callback> ("fcn_callback");
     qRegisterMetaType<meth_callback> ("meth_callback");
 
-    connect (this, SIGNAL (confirm_shutdown_signal (void)),
-             this, SLOT (confirm_shutdown_octave (void)));
+    connect (this, &qt_interpreter_events::confirm_shutdown_signal,
+             this, &qt_interpreter_events::confirm_shutdown_octave);
+
+    connect (this, &qt_interpreter_events::get_named_icon_signal,
+             this, &qt_interpreter_events::get_named_icon_slot);
+
+    connect (this, &qt_interpreter_events::gui_preference_signal,
+             this, &qt_interpreter_events::gui_preference_slot);
+  }
 
-    connect (this, SIGNAL (get_named_icon_signal (const QString&)),
-             this, SLOT (get_named_icon_slot (const QString&)));
+  void qt_interpreter_events::start_gui (bool gui_app)
+  {
+    if (m_octave_qobj.experimental_terminal_widget ())
+      emit start_gui_signal (gui_app);
+  }
 
-    connect (this,
-             SIGNAL (gui_preference_signal (const QString&, const QString&)),
-             this,
-             SLOT (gui_preference_slot (const QString&, const QString&)));
+  void qt_interpreter_events::close_gui (void)
+  {
+    if (m_octave_qobj.experimental_terminal_widget ())
+      emit close_gui_signal ();
   }
 
   std::list<std::string>
@@ -246,9 +259,26 @@
     emit apply_new_settings ();
   }
 
-  void qt_interpreter_events::show_doc (const std::string& file)
+  bool qt_interpreter_events::show_documentation (const std::string& file)
+  {
+    emit show_documentation_signal (QString::fromStdString (file));
+
+    return true;
+  }
+
+  void qt_interpreter_events::show_file_browser (void)
   {
-    emit show_doc_signal (QString::fromStdString (file));
+    emit show_file_browser_signal ();
+  }
+
+  void qt_interpreter_events::show_command_history (void)
+  {
+    emit show_command_history_signal ();
+  }
+
+  void qt_interpreter_events::show_workspace (void)
+  {
+    emit show_workspace_signal ();
   }
 
   bool qt_interpreter_events::edit_file (const std::string& file)
@@ -437,14 +467,57 @@
     emit execute_command_in_terminal_signal (QString::fromStdString (command));
   }
 
-  void qt_interpreter_events::register_doc (const std::string& file)
+  void qt_interpreter_events::register_documentation (const std::string& file)
+  {
+    emit register_documentation_signal (QString::fromStdString (file));
+  }
+
+  void qt_interpreter_events::unregister_documentation (const std::string& file)
   {
-    emit register_doc_signal (QString::fromStdString (file));
+    emit unregister_documentation_signal (QString::fromStdString (file));
+  }
+
+  void qt_interpreter_events::interpreter_output (const std::string& msg)
+  {
+    if (m_octave_qobj.experimental_terminal_widget ()
+        && m_octave_qobj.gui_running ())
+      emit interpreter_output_signal (QString::fromStdString (msg));
+    else
+      {
+        // FIXME: is this the correct thing to do?
+        std::cout << msg;
+      }
   }
 
-  void qt_interpreter_events::unregister_doc (const std::string& file)
+  void qt_interpreter_events::display_exception (const execution_exception& ee,
+                                                 bool beep)
   {
-    emit unregister_doc_signal (QString::fromStdString (file));
+    if (m_octave_qobj.experimental_terminal_widget ()
+        && m_octave_qobj.gui_running ())
+      {
+        std::ostringstream buf;
+        ee.display (buf);
+        emit interpreter_output_signal (QString::fromStdString (buf.str ()));
+      }
+    else
+      {
+        if (beep)
+          std::cerr << "\a";
+
+        ee.display (std::cerr);
+      }
+  }
+
+  void qt_interpreter_events::gui_status_update (const std::string& feature,
+                                                 const std::string& status)
+  {
+    emit gui_status_update_signal (QString::fromStdString (feature),
+                                   QString::fromStdString (status));
+  }
+
+  void qt_interpreter_events::update_gui_lexer (void)
+  {
+    emit update_gui_lexer_signal (true);
   }
 
   void qt_interpreter_events::directory_changed (const std::string& dir)
@@ -488,6 +561,11 @@
     emit clear_workspace_signal ();
   }
 
+  void qt_interpreter_events::update_prompt (const std::string& prompt)
+  {
+    emit update_prompt_signal (QString::fromStdString (prompt));
+  }
+
   void qt_interpreter_events::set_history (const string_vector& hist)
   {
     QStringList qt_hist;
--- a/libgui/src/qt-interpreter-events.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/qt-interpreter-events.h	Sun May 16 09:44:35 2021 +0200
@@ -81,6 +81,11 @@
 
     ~qt_interpreter_events (void) = default;
 
+    // Note: these functions currently do nothing with the old terminal
+    // widget.
+    void start_gui (bool gui_app = false);
+    void close_gui (void);
+
     std::list<std::string>
     file_dialog (const filter_list& filter, const std::string& title,
                  const std::string& filename, const std::string& pathname,
@@ -112,7 +117,13 @@
 
     void apply_preferences (void);
 
-    void show_doc (const std::string& file);
+    bool show_documentation (const std::string& file);
+
+    void show_file_browser (void);
+
+    void show_command_history (void);
+
+    void show_workspace (void);
 
     bool edit_file (const std::string& file);
 
@@ -137,9 +148,19 @@
 
     void execute_command_in_terminal (const std::string& command);
 
-    void register_doc (const std::string& file);
+    void register_documentation (const std::string& file);
+
+    void unregister_documentation (const std::string& file);
 
-    void unregister_doc (const std::string& file);
+    // Note: this function currently does nothing with the old terminal
+    // widget.
+    void interpreter_output (const std::string& msg);
+
+    void display_exception (const execution_exception& ee, bool beep);
+
+    void gui_status_update (const std::string& feature, const std::string& status);
+
+    void update_gui_lexer (void);
 
     void directory_changed (const std::string& dir);
 
@@ -154,6 +175,8 @@
 
     void clear_workspace (void);
 
+    void update_prompt (const std::string& prompt);
+
     void set_history (const string_vector& hist);
 
     void append_history (const std::string& hist_entry);
@@ -192,6 +215,10 @@
 
   signals:
 
+    // Note: these signals are not currently used by the old terminal widget.
+    void start_gui_signal (bool gui_app);
+    void close_gui_signal (void);
+
     void copy_image_to_clipboard_signal (const QString& file, bool remove_file);
 
     void focus_window_signal (const QString& win_name);
@@ -213,6 +240,8 @@
 
     void clear_workspace_signal (void);
 
+    void update_prompt_signal (const QString& prompt);
+
     void set_history_signal (const QStringList& hist);
 
     void append_history_signal (const QString& hist_entry);
@@ -234,11 +263,24 @@
 
     void gui_preference_signal (const QString& key, const QString& value);
 
-    void show_doc_signal (const QString& file);
+    void show_documentation_signal (const QString& file);
+
+    void register_documentation_signal (const QString& file);
+
+    void unregister_documentation_signal (const QString& file);
+
+    void show_file_browser_signal (void);
 
-    void register_doc_signal (const QString& file);
+    void show_command_history_signal (void);
+
+    void show_workspace_signal (void);
 
-    void unregister_doc_signal (const QString& file);
+    // Note: this signal currently not used by the old terminal widget.
+    void interpreter_output_signal (const QString& msg);
+
+    void gui_status_update_signal (const QString& feature, const QString& status);
+
+    void update_gui_lexer_signal (bool update_apis_only);
 
     void edit_variable_signal (const QString& name, const octave_value& val);
 
--- a/libgui/src/resource-manager.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/resource-manager.cc	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,7 @@
 #endif
 
 #include <algorithm>
+#include <array>
 #include <string>
 
 #include <QDir>
@@ -46,6 +47,7 @@
 #include <QTextCodec>
 
 #include "QTerminal.h"
+#include "gui-preferences-cs.h"
 #include "gui-preferences-ed.h"
 #include "gui-preferences-global.h"
 #include "octave-qobject.h"
@@ -63,19 +65,6 @@
 
 namespace octave
 {
-  static QString
-  default_qt_settings_file (void)
-  {
-    std::string dsf = sys::env::getenv ("OCTAVE_DEFAULT_QT_SETTINGS");
-
-    if (dsf.empty ())
-      dsf = (config::oct_etc_dir ()
-             + sys::file_ops::dir_sep_str ()
-             + "default-qt-settings");
-
-    return QString::fromStdString (dsf);
-  }
-
   resource_manager::resource_manager (void)
     : m_settings_directory (), m_settings_file (), m_settings (nullptr),
       m_default_settings (nullptr), m_temporary_files ()
@@ -220,39 +209,38 @@
   {
     QString default_family;
 
-#if defined (Q_OS_MAC)
-  // Use hard coded default on macOS, since selection of fixed width
-  // default font is unreliable (see bug #59128).
+    // Get all available fixed width fonts via a font combobox
+    QFontComboBox font_combo_box;
+    font_combo_box.setFontFilters (QFontComboBox::MonospacedFonts);
+    QStringList fonts;
 
-  // Get all available fixed width fonts via a font combobox
-  QFontComboBox font_combo_box;
-  font_combo_box.setFontFilters (QFontComboBox::MonospacedFonts);
-  QStringList fonts;
+    for (int index = 0; index < font_combo_box.count(); index++)
+      fonts << font_combo_box.itemText(index);
 
-  for (int index = 0; index < font_combo_box.count(); index++)
-    fonts << font_combo_box.itemText(index);
-
-  // Test for macOS default fixed width font
-  if (fonts.contains (global_mono_font.def.toString ()))
-    default_family = global_mono_font.def.toString ();
+#if defined (Q_OS_MAC)
+    // Use hard coded default on macOS, since selection of fixed width
+    // default font is unreliable (see bug #59128).
+    // Test for macOS default fixed width font
+    if (fonts.contains (global_mono_font.def.toString ()))
+      default_family = global_mono_font.def.toString ();
 #endif
 
-  // If default font is still empty (on all other platforms or
-  // if macOS default font is not available): use QFontDatabase
-  if (default_family.isEmpty ())
-    {
-#if defined (HAVE_QFONTDATABASE_SYSTEMFONT)
-      // Get the system's default monospaced font
-      QFont fixed_font = QFontDatabase::systemFont (QFontDatabase::FixedFont);
-      default_family = fixed_font.defaultFamily ();
-#elif defined (HAVE_QFONT_MONOSPACE)
-      QFont fixed_font;
-      fixed_font.setStyleHint (QFont::Monospace);
-      default_family = fixed_font.defaultFamily ();
-#else
-      default_family = global_font_family;
-#endif
-    }
+    // If default font is still empty (on all other platforms or
+    // if macOS default font is not available): use QFontDatabase
+    if (default_family.isEmpty ())
+      {
+        // Get the system's default monospaced font
+        QFont fixed_font = QFontDatabase::systemFont (QFontDatabase::FixedFont);
+        default_family = fixed_font.defaultFamily ();
+
+        // Since this might be unreliable, test all available fixed width fonts
+        if (! fonts.contains (default_family))
+          {
+            // Font returned by QFontDatabase is not in fixed fonts list.
+            // Fallback: take first from this list
+            default_family = fonts[0];
+          }
+      }
 
     // Test env variable which has preference
     std::string env_default_family = sys::env::getenv ("OCTAVE_DEFAULT_FONT");
@@ -262,76 +250,190 @@
     return default_family;
   }
 
-  void resource_manager::reload_settings (void)
+  QStringList resource_manager::get_default_font (void)
   {
     QString default_family = get_default_font_family ();
 
+    // determine the fefault font size of the system
+    // FIXME: QApplication::font () does not return the monospace font,
+    //        but the size should be probably near to the monospace font
+    QFont font = QApplication::font ();
+
+    int font_size = font.pointSize ();
+    if (font_size == -1)
+      font_size = static_cast <int> (std::floor(font.pointSizeF ()));
+
+    // check for valid font size, otherwise take default 10
+    QString default_font_size = "10";
+    if (font_size > 0)
+      default_font_size = QString::number (font_size);
+
+    std::string env_default_font_size
+      = sys::env::getenv ("OCTAVE_DEFAULT_FONT_SIZE");
+
+    if (! env_default_font_size.empty ())
+      default_font_size = QString::fromStdString (env_default_font_size);
+
+    QStringList result;
+    result << default_family;
+    result << default_font_size;
+    return result;
+  }
+
+  void resource_manager::reload_settings (void)
+  {
+    // Declare some empty options, which may be set at first startup for
+    // writing them into the newly created settings file
+    QString custom_editor;
+    QStringList def_font;
+
+    // Check whether the settings file does not yet exist
     if (! QFile::exists (m_settings_file))
       {
-        QDir ("/").mkpath (m_settings_directory);
-        QFile qt_settings (default_qt_settings_file ());
-
-        if (! qt_settings.open (QFile::ReadOnly))
-          return;
-
-        QTextStream in (&qt_settings);
-        QString settings_text = in.readAll ();
-        qt_settings.close ();
-
-        default_family = get_default_font_family ();
-
-        QString default_font_size = "10";
+        // Get the default font (for terminal)
+        def_font = get_default_font ();
 
-        std::string env_default_font_size
-          = sys::env::getenv ("OCTAVE_DEFAULT_FONT_SIZE");
-
-        if (! env_default_font_size.empty ())
-          default_font_size = QString::fromStdString (env_default_font_size);
-
-        // Get the default custom editor
-#if defined (Q_OS_WIN32)
-        QString custom_editor = "notepad++ -n%l %f";
-#else
-        QString custom_editor = "emacs +%l %f";
-#endif
-
+        // Get a custom editor defined as env variable
         std::string env_default_editor
           = sys::env::getenv ("OCTAVE_DEFAULT_EDITOR");
 
         if (! env_default_editor.empty ())
           custom_editor = QString::fromStdString (env_default_editor);
-
-        // Replace placeholders
-        settings_text.replace ("__default_custom_editor__", custom_editor);
-        settings_text.replace ("__default_font__", default_family);
-        settings_text.replace ("__default_font_size__", default_font_size);
-
-        QFile user_settings (m_settings_file);
-
-        if (! user_settings.open (QIODevice::WriteOnly))
-          return;
-
-        QTextStream out (&user_settings);
-
-        out << settings_text;
-
-        user_settings.close ();
       }
 
     set_settings (m_settings_file);
 
-    // Write the default monospace font into the settings for later use by
-    // console and editor as fallbacks of their font preferences.
+    // Write some settings that were dynamically determined at first startup
     if (m_settings)
-      m_settings->setValue (global_mono_font.key, default_family);
+      {
+        // Custom editor
+        if (! custom_editor.isEmpty ())
+          m_settings->setValue (global_custom_editor.key, custom_editor);
+
+        // Default monospace font for the terminal
+        if (def_font.count () > 1)
+          {
+            m_settings->setValue (cs_font.key, def_font[0]);
+            m_settings->setValue (cs_font_size.key, def_font[1].toInt ());
+          }
+
+        // Write the default monospace font into the settings for later use by
+        // console and editor as fallbacks of their font preferences.
+        m_settings->setValue (global_mono_font.key, get_default_font_family ());
+      }
+  }
+
+#if defined (HAVE_QSCINTILLA)
+  int resource_manager::get_valid_lexer_styles (QsciLexer *lexer, int *styles)
+  {
+    int max_style = 0;
+    int actual_style = 0;
+    while (actual_style < ed_max_style_number && max_style < ed_max_lexer_styles)
+      {
+        if ((lexer->description (actual_style)) != "")  // valid style
+          styles[max_style++] = actual_style;
+        actual_style++;
+      }
+    return max_style;
+  }
+#endif
+
+  QFont resource_manager::copy_font_attributes (const QFont& attr,
+                                                const QFont& base) const
+  {
+    QFont dest (base);
+
+    dest.setBold (attr.bold ());
+    dest.setItalic (attr.italic ());
+    dest.setUnderline (attr.underline ());
+
+    return dest;
+  }
 
+#if defined (HAVE_QSCINTILLA)
+  void resource_manager::read_lexer_settings (QsciLexer *lexer,
+                                              gui_settings *settings,
+                                              int mode, int def)
+  {
+    // Test whether the settings for lexer is already contained in the
+    // given gui settings file. If yes, load them, if not copy them from the
+    // default settings file.
+    // This is useful when a new language support is implemented and the
+    // existing settings file is used (which is of course the common case).
+    int m = mode;
+    if (m > 1)
+      m = 1;
+
+    QString group ("Scintilla" + settings_color_modes_ext[m]);
+
+    settings->beginGroup (group);
+    settings->beginGroup (lexer->language ());
+
+    QStringList lexer_keys = settings->allKeys ();
+
+    settings->endGroup ();
+    settings->endGroup ();
+
+    if (def == settings_reload_default_colors_flag || lexer_keys.count () == 0)
+      {
+        // We have to reload the default values or no Lexer keys found:
+        // If mode == 0, take all settings except font from default lexer
+        // If Mode == 1, take all settings except font from default lexer
+        //               and convert the color by inverting the lightness
+
+        // Get the default font
+        QStringList def_font = get_default_font ();
+        QFont df (def_font[0], def_font[1].toInt ());
+        QFont dfa = copy_font_attributes (lexer->defaultFont (), df);
+        lexer->setDefaultFont (dfa);
+
+        QColor c, p;
+
+        int styles[ed_max_lexer_styles];  // array for saving valid styles
+        int max_style = get_valid_lexer_styles (lexer, styles);
+
+        for (int i = 0; i < max_style; i++)
+          {
+            c = settings->get_color_value (QVariant (lexer->color (styles[i])), m);
+            lexer->setColor (c, styles[i]);
+            p = settings->get_color_value (QVariant (lexer->paper (styles[i])), m);
+            lexer->setPaper (p, styles[i]);
+            dfa = copy_font_attributes (lexer->font (styles[i]), df);
+            lexer->setFont (dfa, styles[i]);
+          }
+        // Set defaults last for not changing the defaults of the styles
+        lexer->setDefaultColor (lexer->color (styles[0]));
+        lexer->setDefaultPaper (lexer->paper (styles[0]));
+
+        // Write settings if not just reload the default values
+        if (def != settings_reload_default_colors_flag)
+          {
+            const std::string group_str = group.toStdString ();
+            lexer->writeSettings (*settings, group_str.c_str ());
+            settings->sync ();
+          }
+      }
+    else
+      {
+        // Found lexer keys, read the settings
+        const std::string group_str = group.toStdString ();
+        lexer->readSettings (*settings, group_str.c_str ());
+      }
   }
+#endif
 
   void resource_manager::set_settings (const QString& file)
   {
     delete m_settings;
     m_settings = new gui_settings (file, QSettings::IniFormat);
 
+    if (m_settings->status () == QSettings::NoError)
+      {
+        // Test usability (force file to be really created)
+        m_settings->setValue ("dummy", 0);
+        m_settings->sync ();
+      }
+
     if (! (QFile::exists (m_settings->fileName ())
            && m_settings->isWritable ()
            && m_settings->status () == QSettings::NoError))
@@ -348,6 +450,8 @@
 
         exit (1);
       }
+    else
+      m_settings->remove ("dummy"); // Remove test entry
   }
 
   bool resource_manager::update_settings_key (const QString& old_key,
@@ -371,39 +475,108 @@
 
   void resource_manager::update_network_settings (void)
   {
-    if (m_settings)
+    if (! m_settings)
+      return;
+
+    QNetworkProxy proxy;
+
+    // Assume no proxy and empty proxy data
+    QNetworkProxy::ProxyType proxy_type = QNetworkProxy::NoProxy;
+    QString scheme;
+    QString host;
+    int port = 0;
+    QString user;
+    QString pass;
+    QUrl proxy_url = QUrl ();
+
+    if (m_settings->value (global_use_proxy.key, global_use_proxy.def).toBool ())
       {
-        QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy;
+        // Use a proxy, collect all required information
+        QString proxy_type_string
+            = m_settings->value (global_proxy_type.key, global_proxy_type.def).toString ();
 
-        if (m_settings->value (global_use_proxy.key, global_use_proxy.def).toBool ())
+        // The proxy type for the Qt proxy settings
+        if (proxy_type_string == "Socks5Proxy")
+          proxy_type = QNetworkProxy::Socks5Proxy;
+        else if (proxy_type_string == "HttpProxy")
+          proxy_type = QNetworkProxy::HttpProxy;
+
+        // The proxy data from the settings
+        if (proxy_type_string == "HttpProxy"
+            || proxy_type_string == "Socks5Proxy")
           {
-            QString proxyTypeString
-              = m_settings->value (global_proxy_type.key, global_proxy_type.def).toString ();
+            host = m_settings->value (global_proxy_host.key,
+                                      global_proxy_host.def).toString ();
+            port = m_settings->value (global_proxy_port.key,
+                                      global_proxy_port.def).toInt ();
+            user = m_settings->value (global_proxy_user.key,
+                                      global_proxy_user.def).toString ();
+            pass = m_settings->value (global_proxy_pass.key,
+                                      global_proxy_pass.def).toString ();
+            if (proxy_type_string == "HttpProxy")
+              scheme = "http";
+            else if (proxy_type_string == "Socks5Proxy")
+              scheme = "socks5";
 
-            if (proxyTypeString == "Socks5Proxy")
-              proxyType = QNetworkProxy::Socks5Proxy;
-            else if (proxyTypeString == "HttpProxy")
-              proxyType = QNetworkProxy::HttpProxy;
+            QUrl env_var_url = QUrl ();
+            proxy_url.setScheme (scheme);
+            proxy_url.setHost (host);
+            proxy_url.setPort (port);
+            if (! user.isEmpty ())
+              proxy_url.setUserName (user);
+            if (! pass.isEmpty ())
+              proxy_url.setPassword (pass);
           }
 
-        QNetworkProxy proxy;
+        // The proxy data from environment variables
+        if (proxy_type_string == global_proxy_all_types.at (2))
+          {
+            const std::array<std::string, 6> env_vars =
+                { "ALL_PROXY", "all_proxy",
+                  "HTTP_PROXY", "http_proxy",
+                  "HTTPS_PROXY", "https_proxy" };
+
+            unsigned int count = 0;
+            while (! proxy_url.isValid () && count < env_vars.size ())
+              {
+                proxy_url = QUrl (QString::fromStdString
+                                    (sys::env::getenv (env_vars[count])));
+                count++;
+              }
+
+            if (proxy_url.isValid ())
+              {
+                // Found an entry, get the data from the string
+                scheme = proxy_url.scheme ();
 
-        proxy.setType (proxyType);
-        proxy.setHostName (m_settings->value (global_proxy_host.key,
-                                              global_proxy_host.def).toString ());
-        proxy.setPort (m_settings->value (global_proxy_port.key,
-                                          global_proxy_port.def).toInt ());
-        proxy.setUser (m_settings->value (global_proxy_user.key,
-                                          global_proxy_user.def).toString ());
-        proxy.setPassword (m_settings->value (global_proxy_pass.key,
-                                              global_proxy_pass.def).toString ());
+                if (scheme.contains ("socks", Qt::CaseInsensitive))
+                  proxy_type = QNetworkProxy::Socks5Proxy;
+                else
+                  proxy_type = QNetworkProxy::HttpProxy;
+
+                host = proxy_url.host ();
+                port = proxy_url.port ();
+                user = proxy_url.userName ();
+                pass = proxy_url.password ();
+              }
+          }
+      }
 
-        QNetworkProxy::setApplicationProxy (proxy);
-      }
-    else
-      {
-        // FIXME: Is this an error?  If so, what should we do?
-      }
+    // Set proxy for Qt framework
+    proxy.setType (proxy_type);
+    proxy.setHostName (host);
+    proxy.setPort (port);
+    proxy.setUser (user);
+    proxy.setPassword (pass);
+
+    QNetworkProxy::setApplicationProxy (proxy);
+
+    // Set proxy for curl library if not based on environment variables
+    std::string proxy_url_str = proxy_url.toString().toStdString ();
+    sys::env::putenv ("http_proxy", proxy_url_str);
+    sys::env::putenv ("HTTP_PROXY", proxy_url_str);
+    sys::env::putenv ("https_proxy", proxy_url_str);
+    sys::env::putenv ("HTTPS_PROXY", proxy_url_str);
   }
 
   QIcon resource_manager::icon (const QString& icon_name, bool fallback)
--- a/libgui/src/resource-manager.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/resource-manager.h	Sun May 16 09:44:35 2021 +0200
@@ -29,6 +29,7 @@
 #include <QComboBox>
 #include <QIcon>
 #include <QPointer>
+#include <Qsci/qscilexer.h>
 #include <QTranslator>
 #include <QTemporaryFile>
 
@@ -69,6 +70,8 @@
 
     QString get_default_font_family (void);
 
+    QStringList get_default_font (void);
+
     QPointer<QTemporaryFile>
     create_tmp_file (const QString& extension = QString (),
                      const QString& contents = QString ());
@@ -77,6 +80,12 @@
 
     void reload_settings (void);
 
+#if defined (HAVE_QSCINTILLA)
+    int get_valid_lexer_styles (QsciLexer *lexer, int *styles);
+    void read_lexer_settings (QsciLexer *lexer, gui_settings *settings,
+                              int mode = 0, int def = 0);
+#endif
+
     void set_settings (const QString& file);
 
     bool update_settings_key (const QString& new_key, const QString& old_key);
@@ -93,6 +102,15 @@
 
   private:
 
+    /*!
+     * Copys the attributes bold, italic and underline from QFont
+     * @p attr to the font @p base and returns the result without
+     * changing @p base,
+     * @param attr QFont with the desired attributes
+     * @param base QFont with desired family and size
+    */
+    QFont copy_font_attributes (const QFont& attr, const QFont& base) const;
+
     QString m_settings_directory;
 
     QString m_settings_file;
--- a/libgui/src/resource.qrc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/resource.qrc	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 <RCC>
     <qresource prefix="/actions">
         <file>icons/applications-system.png</file>
+        <file>icons/bookmark-new.png</file>
         <file>icons/bp-toggle.png</file>
         <file>icons/bp-rm-all.png</file>
         <file>icons/bp-prev.png</file>
@@ -49,6 +50,7 @@
         <file>icons/go-previous.png</file>
         <file>icons/go-up.png</file>
         <file>icons/graphic_logo_FilesDockWidget.png</file>
+        <file>icons/graphic_logo_Figure.png</file>
         <file>icons/graphic_logo_FileEditor.png</file>
         <file>icons/graphic_logo_NewsDockWidget.png</file>
         <file>icons/graphic_logo_TerminalDockWidget.png</file>
--- a/libgui/src/set-path-dialog.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/set-path-dialog.cc	Sun May 16 09:44:35 2021 +0200
@@ -51,6 +51,7 @@
 
 #include "gui-preferences-pd.h"
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 #include "set-path-dialog.h"
 #include "set-path-model.h"
 
@@ -72,9 +73,9 @@
     QMenu *add_dir_menu = new QMenu ();
     m_add_folder_button->setMenu (add_dir_menu);
     add_dir_menu->addAction (tr ("Single Folder"),
-                             this, SLOT (add_dir (void)));
+                             this, &set_path_dialog::add_dir);
     add_dir_menu->addAction (tr ("Folder with Subfolders"),
-                             this, SLOT (add_dir_subdirs (void)));
+                             this, &set_path_dialog::add_dir_subdirs);
 
     m_move_to_top_button = new QPushButton (tr ("Move to Top"));
     m_move_to_bottom_button = new QPushButton (tr ("Move to Bottom"));
@@ -90,41 +91,41 @@
     QMenu *revert_menu = new QMenu ();
     m_revert_button->setMenu (revert_menu);
     revert_menu->addAction (tr ("Revert Last Change"),
-                            model, SLOT (revert_last (void)));
+                            model, &set_path_model::revert_last);
     revert_menu->addAction (tr ("Revert All Changes"),
-                            model, SLOT (revert (void)));
+                            model, &set_path_model::revert);
 
     m_save_button->setFocus ();
 
-    connect (m_remove_button, SIGNAL (clicked (void)),
-             this, SLOT (rm_dir (void)));
+    connect (m_remove_button, &QPushButton::clicked,
+             this, &set_path_dialog::rm_dir);
 
-    connect (m_move_to_top_button, SIGNAL (clicked (void)),
-             this, SLOT (move_dir_top (void)));
+    connect (m_move_to_top_button, &QPushButton::clicked,
+             this, &set_path_dialog::move_dir_top);
 
-    connect (m_move_to_bottom_button, SIGNAL (clicked (void)),
-             this, SLOT (move_dir_bottom (void)));
+    connect (m_move_to_bottom_button, &QPushButton::clicked,
+             this, &set_path_dialog::move_dir_bottom);
 
-    connect (m_move_up_button, SIGNAL (clicked (void)),
-             this, SLOT (move_dir_up (void)));
+    connect (m_move_up_button, &QPushButton::clicked,
+             this, &set_path_dialog::move_dir_up);
 
-    connect (m_move_down_button, SIGNAL (clicked (void)),
-             this, SLOT (move_dir_down (void)));
+    connect (m_move_down_button, &QPushButton::clicked,
+             this, &set_path_dialog::move_dir_down);
 
-    connect (m_reload_button, SIGNAL (clicked (void)),
-             model, SLOT (path_to_model (void)));
+    connect (m_reload_button, &QPushButton::clicked,
+             model, &set_path_model::path_to_model);
 
-    connect (m_save_button, SIGNAL (clicked (void)),
-             model, SLOT (save (void)));
+    connect (m_save_button, &QPushButton::clicked,
+             model, &set_path_model::save);
 
     // Any interpreter_event signal from a set_path_model object is
     // handled the same as for the parent set_path_dialog object.
 
-    connect (model, SIGNAL (interpreter_event (const fcn_callback&)),
-             this, SIGNAL (interpreter_event (const fcn_callback&)));
+    connect (model, QOverload<const fcn_callback&>::of (&set_path_model::interpreter_event),
+             this, QOverload<const fcn_callback&>::of (&set_path_dialog::interpreter_event));
 
-    connect (model, SIGNAL (interpreter_event (const meth_callback&)),
-             this, SIGNAL (interpreter_event (const meth_callback&)));
+    connect (model, QOverload<const meth_callback&>::of (&set_path_model::interpreter_event),
+             this, QOverload<const meth_callback&>::of (&set_path_dialog::interpreter_event));
 
     m_path_list = new QListView (this);
     m_path_list->setWordWrap (false);
@@ -141,7 +142,8 @@
 
     // add dialog close button
     m_close_button = button_box->addButton (QDialogButtonBox::Close);
-    connect (button_box, SIGNAL (rejected (void)), this, SLOT (close (void)));
+    connect (button_box, &QDialogButtonBox::rejected,
+             this, &set_path_dialog::close);
 
     button_box->addButton (m_revert_button, QDialogButtonBox::ActionRole);
 
@@ -172,10 +174,6 @@
       settings->value(pd_geometry.key).toByteArray());
   }
 
-  set_path_dialog::~set_path_dialog (void)
-  {
-  }
-
   void set_path_dialog::update_model (void)
   {
     set_path_model *m = static_cast<set_path_model *> (m_path_list->model ());
--- a/libgui/src/set-path-dialog.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/set-path-dialog.h	Sun May 16 09:44:35 2021 +0200
@@ -55,7 +55,7 @@
 
     set_path_dialog (QWidget *parent, base_qobject& oct_qobj);
 
-    virtual ~set_path_dialog (void);
+    virtual ~set_path_dialog (void) = default;
 
     void save_settings (void);
 
--- a/libgui/src/set-path-model.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/set-path-model.cc	Sun May 16 09:44:35 2021 +0200
@@ -47,8 +47,8 @@
   set_path_model::set_path_model (QObject *p)
     : QAbstractListModel (p)
   {
-    connect (this, SIGNAL (update_data_signal (const QStringList&)),
-             this, SLOT (update_data (const QStringList&)));
+    connect (this, &set_path_model::update_data_signal,
+             this, &set_path_model::update_data);
 
     m_revertible = false;
   }
@@ -77,7 +77,7 @@
     std::string path_str = to_string ();
 
     emit interpreter_event
-      ([path_str] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -283,7 +283,7 @@
   void set_path_model::path_to_model (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
--- a/libgui/src/settings-dialog.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/settings-dialog.cc	Sun May 16 09:44:35 2021 +0200
@@ -56,6 +56,7 @@
 #  endif
 
 #  include <Qsci/qscilexercpp.h>
+#  include <Qsci/qscilexerjava.h>
 #  include <Qsci/qscilexerbash.h>
 #  include <Qsci/qscilexerperl.h>
 #  include <Qsci/qscilexerbatch.h>
@@ -64,31 +65,13 @@
 
 #include "gui-preferences-all.h"
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 #include "settings-dialog.h"
 #include "variable-editor.h"
 #include "workspace-model.h"
 
 namespace octave
 {
-#if defined (HAVE_QSCINTILLA)
-
-  static const int MaxLexerStyles = 64;
-  static const int MaxStyleNumber = 128;
-
-  static int get_valid_lexer_styles (QsciLexer *lexer, int *styles)
-  {
-    int max_style = 0;
-    int actual_style = 0;
-    while (actual_style < MaxStyleNumber && max_style < MaxLexerStyles)
-      {
-        if ((lexer->description (actual_style)) != "")  // valid style
-          styles[max_style++] = actual_style;
-        actual_style++;
-      }
-    return max_style;
-  }
-
-#endif
 
   settings_dialog::settings_dialog (QWidget *p, base_qobject& oct_qobj,
                                     const QString& desired_tab)
@@ -174,32 +157,32 @@
     m_widget_title_bg_color->setEnabled (false);
     layout_widget_bgtitle->addWidget (m_widget_title_bg_color, 0);
 
-    connect (cb_widget_custom_style, SIGNAL (toggled (bool)),
-             m_widget_title_bg_color, SLOT (setEnabled (bool)));
+    connect (cb_widget_custom_style, &QCheckBox::toggled,
+             m_widget_title_bg_color, &color_picker::setEnabled);
 
     QColor bg_color_active = settings->value (dw_title_bg_color_active).value<QColor> ();
     m_widget_title_bg_color_active = new color_picker (bg_color_active);
     m_widget_title_bg_color_active->setEnabled (false);
     layout_widget_bgtitle_active->addWidget (m_widget_title_bg_color_active, 0);
 
-    connect (cb_widget_custom_style, SIGNAL (toggled (bool)),
-             m_widget_title_bg_color_active, SLOT (setEnabled (bool)));
+    connect (cb_widget_custom_style, &QCheckBox::toggled,
+             m_widget_title_bg_color_active, &color_picker::setEnabled);
 
     QColor fg_color = settings->value (dw_title_fg_color).value<QColor> ();
     m_widget_title_fg_color = new color_picker (fg_color);
     m_widget_title_fg_color->setEnabled (false);
     layout_widget_fgtitle->addWidget (m_widget_title_fg_color, 0);
 
-    connect (cb_widget_custom_style, SIGNAL (toggled (bool)),
-             m_widget_title_fg_color, SLOT (setEnabled (bool)));
+    connect (cb_widget_custom_style, &QCheckBox::toggled,
+             m_widget_title_fg_color, &color_picker::setEnabled);
 
     QColor fg_color_active = settings->value (dw_title_fg_color_active).value<QColor> ();
     m_widget_title_fg_color_active = new color_picker (fg_color_active);
     m_widget_title_fg_color_active->setEnabled (false);
     layout_widget_fgtitle_active->addWidget (m_widget_title_fg_color_active, 0);
 
-    connect (cb_widget_custom_style, SIGNAL (toggled (bool)),
-             m_widget_title_fg_color_active, SLOT (setEnabled (bool)));
+    connect (cb_widget_custom_style, &QCheckBox::toggled,
+             m_widget_title_fg_color_active, &color_picker::setEnabled);
 
     sb_3d_title->setValue (settings->value (dw_title_3d.key,
                                             dw_title_3d.def).toInt ());
@@ -227,6 +210,10 @@
                     (cs_cursor_blinking.key, cs_cursor_blinking.def).toBool ());
       }
 
+    // focus follows mouse
+    cb_focus_follows_mouse->setChecked (
+        settings->value (dw_focus_follows_mouse).toBool ());
+
     // prompt on exit
     cb_prompt_to_exit->setChecked (
         settings->value (global_prompt_to_exit.key, global_prompt_to_exit.def).toBool ());
@@ -241,8 +228,8 @@
     le_octave_dir->setText (settings->value (global_ov_startup_dir.key,
                                              global_ov_startup_dir.def).toString ());
 
-    connect (pb_octave_dir, SIGNAL (pressed (void)),
-             this, SLOT (get_octave_dir (void)));
+    connect (pb_octave_dir, &QPushButton::pressed,
+             this, &settings_dialog::get_octave_dir);
 
     //
     // editor
@@ -256,15 +243,6 @@
 
     rmgr.combo_encoding (editor_combo_encoding);
 
-    QColor setting_color = settings->value (ed_highlight_current_line_color).value<QColor> ();
-    m_editor_current_line_color = new color_picker (setting_color);
-    editor_grid_current_line->addWidget (m_editor_current_line_color, 0, 3);
-    m_editor_current_line_color->setMinimumSize (20, 10);
-    m_editor_current_line_color->setEnabled (false);
-
-    connect (editor_highlightCurrentLine, SIGNAL (toggled (bool)),
-             m_editor_current_line_color, SLOT (setEnabled (bool)));
-
     editor_highlightCurrentLine->setChecked (settings->value (ed_highlight_current_line).toBool ());
     editor_long_line_marker->setChecked (settings->value (ed_long_line_marker).toBool ());
     bool long_line =
@@ -306,6 +284,9 @@
     editor_combox_tab_pos->setCurrentIndex
       (settings->value (ed_tab_position).toInt ());
 
+    editor_cb_tabs_rotated->setChecked (settings->value (ed_tabs_rotated).toBool ());
+    editor_sb_tabs_max_width->setValue (settings->value (ed_tabs_max_width).toInt ());
+
     int selected_comment_string, selected_uncomment_string;
 
     if (settings->contains (ed_comment_str.key))   // new version (radio buttons)
@@ -320,10 +301,10 @@
         m_rb_comment_strings[i] = new QRadioButton ();
         m_rb_uncomment_strings[i] = new QCheckBox ();
 
-        connect (m_rb_comment_strings[i], SIGNAL (clicked (bool)),
-                 m_rb_uncomment_strings[i], SLOT (setChecked (bool)));
-        connect (m_rb_comment_strings[i], SIGNAL (toggled (bool)),
-                 m_rb_uncomment_strings[i], SLOT (setDisabled (bool)));
+        connect (m_rb_comment_strings[i], &QRadioButton::clicked,
+                 m_rb_uncomment_strings[i], &QCheckBox::setChecked);
+        connect (m_rb_comment_strings[i], &QRadioButton::toggled,
+                 m_rb_uncomment_strings[i], &QCheckBox::setDisabled);
 
         m_rb_comment_strings[i]->setText (ed_comment_strings.at(i));
         m_rb_comment_strings[i]->setChecked (i == selected_comment_string);
@@ -344,12 +325,11 @@
     editor_ind_width_spinbox->setValue (settings->value (ed_indent_width).toInt ());
     editor_ind_uses_tabs_checkbox->setChecked (settings->value (ed_indent_uses_tabs).toBool ());
     editor_tab_width_spinbox->setValue (settings->value (ed_tab_width).toInt ());
-    editor_longWindowTitle->setChecked (settings->value (ed_long_window_title).toBool ());
-    editor_notebook_tab_width_min->setValue (settings->value (ed_notebook_tab_width_min).toInt ());
-    editor_notebook_tab_width_max->setValue (settings->value (ed_notebook_tab_width_max).toInt ());
     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 ());
 
@@ -381,42 +361,53 @@
           }
       }
 
+    read_terminal_colors (settings);
+
     // file browser
-    connect (sync_octave_directory, SIGNAL (toggled (bool)),
-             this, SLOT (set_disabled_pref_file_browser_dir (bool)));
+    connect (sync_octave_directory, &QCheckBox::toggled,
+             this, &settings_dialog::set_disabled_pref_file_browser_dir);
 
     sync_octave_directory->setChecked (settings->value (fb_sync_octdir).toBool ());
     cb_restore_file_browser_dir->setChecked (settings->value (fb_restore_last_dir).toBool ());
     le_file_browser_dir->setText (settings->value (fb_startup_dir.key).toString ());
 
-    connect (pb_file_browser_dir, SIGNAL (pressed (void)),
-             this, SLOT (get_file_browser_dir (void)));
+    connect (pb_file_browser_dir, &QPushButton::pressed,
+             this, &settings_dialog::get_file_browser_dir);
 
     le_file_browser_extensions->setText (settings->value (fb_txt_file_ext).toString ());
 
     checkbox_allow_web_connect->setChecked (settings->value (nr_allow_connection).toBool ());
-    useProxyServer->setChecked (
-        settings->value (global_use_proxy.key, global_use_proxy.def).toBool ());
-    proxyHostName->setText (settings->value (global_proxy_host.key, global_proxy_host.def).toString ());
 
-    int currentIndex = 0;
-    QString proxyTypeString = settings->value (global_proxy_type.key, global_proxy_type.def).toString ();
-    while ((currentIndex < proxyType->count ())
-           && (proxyType->currentText () != proxyTypeString))
+    // Proxy
+    bool use_proxy = settings->value (global_use_proxy.key, global_use_proxy.def).toBool ();
+    use_proxy_server->setChecked (use_proxy);
+    // Fill combo box and activate current one
+    QString proxy_type_string = settings->value (global_proxy_type.key, global_proxy_type.def).toString ();
+    proxy_type->addItems (global_proxy_all_types);
+    for (int i = 0; i < global_proxy_all_types.length (); i++)
       {
-        currentIndex++;
-        proxyType->setCurrentIndex (currentIndex);
+        if (proxy_type->itemText (i) == proxy_type_string)
+          {
+            proxy_type->setCurrentIndex (i);
+            break;
+          }
       }
-    proxyPort->setText (settings->value (global_proxy_port.key, global_proxy_port.def).toString ());
-    proxyUserName->setText (settings->value (global_proxy_user.key, global_proxy_user.def).toString ());
-    proxyPassword->setText (settings->value (global_proxy_pass.key, global_proxy_pass.def).toString ());
+    // Fill all line edits
+    proxy_host_name->setText (settings->value (global_proxy_host.key, global_proxy_host.def).toString ());
+    proxy_port->setText (settings->value (global_proxy_port.key, global_proxy_port.def).toString ());
+    proxy_username->setText (settings->value (global_proxy_user.key, global_proxy_user.def).toString ());
+    proxy_password->setText (settings->value (global_proxy_pass.key, global_proxy_pass.def).toString ());
+    // Connect relevant signals for dis-/enabling some elements
+    connect (proxy_type, QOverload<int>::of (&QComboBox::currentIndexChanged),
+             this, &settings_dialog::proxy_items_update);
+    connect (use_proxy_server, &QCheckBox::toggled,
+             this, &settings_dialog::proxy_items_update);
+    // Check whehter line edits have to be enabled
+    proxy_items_update ();
 
     // Workspace
     read_workspace_colors (settings);
 
-    // terminal colors
-    read_terminal_colors (settings);
-
     // variable editor
     varedit_columnWidth->setValue (settings->value (ve_column_width).toInt ());
     varedit_rowHeight->setValue (settings->value (ve_row_height).toInt ());
@@ -424,10 +415,10 @@
     varedit_font->setCurrentFont (QFont (settings->value (ve_font_name.key,
                                                           settings->value (cs_font.key, default_font)).toString ()));
     varedit_fontSize->setValue (settings->value (ve_font_size).toInt ());
-    connect (varedit_useTerminalFont, SIGNAL (toggled (bool)),
-             varedit_font, SLOT (setDisabled (bool)));
-    connect (varedit_useTerminalFont, SIGNAL (toggled (bool)),
-             varedit_fontSize, SLOT (setDisabled (bool)));
+    connect (varedit_useTerminalFont, &QCheckBox::toggled,
+             varedit_font, &QFontComboBox::setDisabled);
+    connect (varedit_useTerminalFont, &QCheckBox::toggled,
+             varedit_fontSize, &QSpinBox::setDisabled);
     varedit_useTerminalFont->setChecked (settings->value (ve_use_terminal_font).toBool ());
     varedit_font->setDisabled (varedit_useTerminalFont->isChecked ());
     varedit_fontSize->setDisabled (varedit_useTerminalFont->isChecked ());
@@ -444,62 +435,50 @@
     cb_prevent_readline_conflicts->setChecked (
           settings->value (sc_prevent_rl_conflicts.key,
                            sc_prevent_rl_conflicts.def).toBool ());
+    cb_prevent_readline_conflicts_menu->setChecked (
+          settings->value (sc_prevent_rl_conflicts_menu.key,
+                           sc_prevent_rl_conflicts_menu.def).toBool ());
 
     // initialize the tree view with all shortcut data
     scmgr.fill_treewidget (shortcuts_treewidget);
 
     // connect the buttons for import/export of the shortcut sets
-    connect (btn_import_shortcut_set, SIGNAL (clicked (void)),
-             this, SLOT (import_shortcut_set (void)));
+    connect (btn_import_shortcut_set, &QPushButton::clicked,
+             this, &settings_dialog::import_shortcut_set);
 
-    connect (btn_export_shortcut_set, SIGNAL (clicked (void)),
-             this, SLOT (export_shortcut_set (void)));
+    connect (btn_export_shortcut_set, &QPushButton::clicked,
+             this, &settings_dialog::export_shortcut_set);
 
-    connect (btn_default_shortcut_set, SIGNAL (clicked (void)),
-             this, SLOT (default_shortcut_set (void)));
+    connect (btn_default_shortcut_set, &QPushButton::clicked,
+             this, &settings_dialog::default_shortcut_set);
 
 #if defined (HAVE_QSCINTILLA)
 
-    // editor styles: create lexer, read settings, and create dialog elements
-    QsciLexer *lexer;
-
-#if defined (HAVE_LEXER_OCTAVE)
+    int ed_mode = settings->value (ed_color_mode).toInt ();
 
-    lexer = new QsciLexerOctave ();
-    read_lexer_settings (lexer, settings);
-    delete lexer;
-
-#elif defined (HAVE_LEXER_MATLAB)
+    QCheckBox *cb_color_mode = new QCheckBox (settings_color_modes,
+                                              group_box_editor_styles);
+    cb_color_mode->setToolTip (settings_color_modes_tooltip);
+    cb_color_mode->setChecked (ed_mode > 0);
+    cb_color_mode->setObjectName (ed_color_mode.key);
 
-    lexer = new QsciLexerMatlab ();
-    read_lexer_settings (lexer, settings);
-    delete lexer;
-
-#endif
+    QPushButton *pb_reload_default_colors = new QPushButton (settings_reload_styles);
+    pb_reload_default_colors->setToolTip (settings_reload_styles_tooltip);
 
-    lexer = new QsciLexerCPP ();
-    read_lexer_settings (lexer, settings);
-    delete lexer;
+    editor_style_grid->addWidget (cb_color_mode, 0, 0);
+    editor_style_grid->addWidget (pb_reload_default_colors, 0, 1);
+    editor_style_grid->addItem (new QSpacerItem (5,5,QSizePolicy::Expanding), 0, 2);
 
-    lexer = new QsciLexerPerl ();
-    read_lexer_settings (lexer, settings);
-    delete lexer;
 
-    lexer = new QsciLexerBatch ();
-    read_lexer_settings (lexer, settings);
-    delete lexer;
 
-    lexer = new QsciLexerDiff ();
-    read_lexer_settings (lexer, settings);
-    delete lexer;
+    // update colors depending on second theme selection
+    connect (cb_color_mode, &QCheckBox::stateChanged,
+             this, &settings_dialog::update_editor_lexers);
+    connect (pb_reload_default_colors, &QPushButton::clicked,
+             [=] () { update_editor_lexers (settings_reload_default_colors_flag); });
 
-    lexer = new QsciLexerBash ();
-    read_lexer_settings (lexer, settings);
-    delete lexer;
-
-    lexer = new octave_txt_lexer ();
-    read_lexer_settings (lexer, settings);
-    delete lexer;
+    // finally read the lexer colors using the update slot
+    update_editor_lexers ();
 
 #endif
 
@@ -507,8 +486,8 @@
     show_tab (desired_tab);
 
     // connect button box signal
-    connect (button_box, SIGNAL (clicked (QAbstractButton *)),
-             this, SLOT (button_clicked (QAbstractButton *)));
+    connect (button_box, &QDialogButtonBox::clicked,
+             this, &settings_dialog::button_clicked);
 
     // restore last geometry
     if (settings->contains (sd_geometry.key))
@@ -594,6 +573,32 @@
       }
   }
 
+  // slot for updating enabled state of proxy settings
+  void settings_dialog::proxy_items_update (void)
+  {
+    bool use_proxy = use_proxy_server->isChecked ();
+
+    bool manual = false;
+    for (int i = 0; i < global_proxy_manual_types.length (); i++)
+      {
+        if (proxy_type->currentIndex () == global_proxy_manual_types.at (i))
+          {
+            manual = true;
+            break;
+          }
+      }
+
+    proxy_type->setEnabled (use_proxy);
+    proxy_host_name_label->setEnabled (use_proxy && manual);
+    proxy_host_name->setEnabled (use_proxy && manual);
+    proxy_port_label->setEnabled (use_proxy && manual);
+    proxy_port->setEnabled (use_proxy && manual);
+    proxy_username_label->setEnabled (use_proxy && manual);
+    proxy_username->setEnabled (use_proxy && manual);
+    proxy_password_label->setEnabled (use_proxy && manual);
+    proxy_password->setEnabled (use_proxy && manual);
+  }
+
   // slots for import/export of shortcut sets
 
   void settings_dialog::import_shortcut_set (void)
@@ -617,15 +622,176 @@
     scmgr.import_export (shortcut_manager::OSC_DEFAULT);
   }
 
-  void settings_dialog::read_lexer_settings (QsciLexer *lexer,
-                                             gui_settings *settings)
+  void settings_dialog::update_editor_lexers (int def)
   {
 #if defined (HAVE_QSCINTILLA)
+    QCheckBox *cb_color_mode
+      = group_box_editor_styles->findChild <QCheckBox *> (ed_color_mode.key);
+
+    int m = 0;
+    if (cb_color_mode && cb_color_mode->isChecked ())
+      m = 1;
+
+    // editor styles: create lexer, read settings, and
+    // create or update dialog elements
+    QsciLexer *lexer;
+
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+#if defined (HAVE_LEXER_OCTAVE)
+    lexer = new QsciLexerOctave ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+#elif defined (HAVE_LEXER_MATLAB)
+    lexer = new QsciLexerMatlab ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+#endif
+
+    lexer = new QsciLexerCPP ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+
+    lexer = new QsciLexerJava ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+
+    lexer = new QsciLexerPerl ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+
+    lexer = new QsciLexerBatch ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+
+    lexer = new QsciLexerDiff ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+
+    lexer = new QsciLexerBash ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+
+    lexer = new octave_txt_lexer ();
+    update_lexer (lexer, settings, m, def);
+    delete lexer;
+#endif
+  }
+
+#if defined (HAVE_QSCINTILLA)
 
-    lexer->readSettings (*settings);
-    int styles[MaxLexerStyles];  // array for saving valid styles
+  void settings_dialog::update_lexer (QsciLexer *lexer, gui_settings *settings,
+                                      int mode, int def)
+  {
+    // Get lexer settings and copy from default settings if not yet
+    // available in normal settings file
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    rmgr.read_lexer_settings (lexer, settings, mode, def);
+
+    // When reloading default styles, the style tabs do already exists.
+    // Otherwise, check if they exist or not.
+    QString lexer_name = lexer->language ();
+
+    int index = -1;
+    for (int i = 0; i < tabs_editor_lexers->count (); i++)
+      {
+        if (tabs_editor_lexers->tabText (i) == lexer_name)
+          {
+            index = i;
+            break;
+          }
+      }
+
+    if (index == -1)
+      {
+        // This is not an update, call get_lexer_settings for building
+        // the settings tab
+        get_lexer_settings (lexer, settings);
+        return;
+      }
+
+    // Update the styles elements in all styles
+    int styles[ed_max_lexer_styles];  // array for saving valid styles
+    int max_style = rmgr.get_valid_lexer_styles (lexer, styles);
+    QWidget *tab = tabs_editor_lexers->widget (index);
+    int default_size = 0;
+    QString default_family;
+
+    for (int i = 0; i < max_style; i++)  // create dialog elements for all styles
+      {
+        QString actual_name = lexer->description (styles[i]);
+        color_picker *bg_color
+          = tab->findChild <color_picker *> (actual_name + "_bg_color");
+        if (bg_color)
+          {
+            // Update
+            if (styles[i] == 0)
+              bg_color->set_color (lexer->defaultPaper ());
+            else
+              {
+                if (lexer->paper (styles[i]) == lexer->defaultPaper ())
+                  bg_color->set_color (settings_color_no_change);
+                else
+                  bg_color->set_color (lexer->paper (styles[i]));
+              }
+          }
+
+        color_picker *color = tab->findChild <color_picker *> (actual_name + "_color");
+        if (color)
+          color->set_color (lexer->color (styles[i]));
+
+        QFont font = lexer->font (styles[i]);
+
+        QCheckBox *cb = tab->findChild <QCheckBox *> (actual_name + "_bold");
+        if (cb)
+          cb->setChecked (font.bold ());
+        cb = tab->findChild <QCheckBox *> (actual_name + "_italic");
+        if (cb)
+          cb->setChecked (font.italic ());
+        cb = tab->findChild <QCheckBox *> (actual_name + "_underline");
+        if (cb)
+          cb->setChecked (font.underline ());
+
+        QFontComboBox *fcb = tab->findChild <QFontComboBox *> (actual_name + "_font");
+        if (fcb)
+          {
+            if (styles[i] == 0)
+              {
+                default_family = font.family ();
+                fcb->setEditText (default_family);
+              }
+            else
+              {
+                if (font.family () == default_family)
+                  fcb->setEditText (lexer->description (0));
+                else
+                  fcb->setEditText (font.family ());
+              }
+          }
+        QSpinBox *fs = tab->findChild <QSpinBox *> (actual_name + "_size");
+        if (fs)
+          {
+            if (styles[i] == 0)
+              {
+                default_size = font.pointSize ();
+                fs->setValue (default_size);
+              }
+            else
+              fs->setValue (font.pointSize () - default_size);
+          }
+      }
+
+  }
+
+  void settings_dialog::get_lexer_settings (QsciLexer *lexer,
+                                             gui_settings *settings)
+  {
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+
+    int styles[ed_max_lexer_styles];  // array for saving valid styles
     // (enum is not continuous)
-    int max_style = get_valid_lexer_styles (lexer, styles);
+    int max_style = rmgr.get_valid_lexer_styles (lexer, styles);
     QGridLayout *style_grid = new QGridLayout ();
     QVector<QLabel*> description (max_style);
     QVector<QFontComboBox*> select_font (max_style);
@@ -637,7 +803,6 @@
     QFont default_font = QFont ();
     int label_width;
     QColor default_color = QColor ();
-    QColor dummy_color = QColor (255, 0, 255);
 
     for (int i = 0; i < max_style; i++)  // create dialog elements for all styles
       {
@@ -673,7 +838,7 @@
             font_size[i]->setValue (actual_font.pointSize ()-default_size);
             font_size[i]->setToolTip (QObject::tr ("Difference to the default size"));
             if (lexer->paper (styles[i]) == default_color)
-              bg_color[i] = new color_picker (dummy_color);
+              bg_color[i] = new color_picker (settings_color_no_change);
             else
               bg_color[i] = new color_picker (lexer->paper (styles[i]));
             bg_color[i]->setToolTip
@@ -701,6 +866,7 @@
         style_grid->addWidget (color[i], i, column++);
         style_grid->addWidget (bg_color[i], i, column++);
       }
+
     // place grid with elements into the tab
     QScrollArea *scroll_area = new QScrollArea ();
     QWidget *scroll_area_contents = new QWidget ();
@@ -710,25 +876,26 @@
     tabs_editor_lexers->addTab (scroll_area, lexer->language ());
 
     tabs_editor_lexers->setCurrentIndex (settings->value (sd_last_editor_styles_tab).toInt ());
-
-#else
-
-    octave_unused_parameter (lexer);
-    octave_unused_parameter (settings);
-
-#endif
   }
 
   void settings_dialog::write_lexer_settings (QsciLexer *lexer,
                                               gui_settings *settings)
   {
-#if defined (HAVE_QSCINTILLA)
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+
+    QCheckBox *cb_color_mode
+      = group_box_editor_styles->findChild <QCheckBox *> (ed_color_mode.key);
+    int mode = 0;
+    if (cb_color_mode && cb_color_mode->isChecked ())
+      mode = 1;
+
+    settings->setValue (ed_color_mode.key, mode);
 
     QWidget *tab = tabs_editor_lexers->
       findChild <QWidget *> (QString (lexer->language ()) + "_styles");
-    int styles[MaxLexerStyles];  // array for saving valid styles
+    int styles[ed_max_lexer_styles];  // array for saving valid styles
     // (enum is not continuous)
-    int max_style = get_valid_lexer_styles (lexer, styles);
+    int max_style = rmgr.get_valid_lexer_styles (lexer, styles);
     QFontComboBox *select_font;
     QSpinBox *font_size;
     QCheckBox *attrib_font[3];
@@ -740,7 +907,6 @@
       = settings->value (global_mono_font).toString ();
     QFont default_font = QFont (default_font_name, 10, -1, 0);
     QColor default_color = QColor ();
-    QColor dummy_color = QColor (255, 0, 255);
 
     for (int i = 0; i < max_style; i++)  // get dialog elements and their contents
       {
@@ -792,7 +958,7 @@
               }
             else
               {
-                if (bg_color->color () == dummy_color)
+                if (bg_color->color () == settings_color_no_change)
                   lexer->setPaper (default_color, styles[i]);
                 else
                   lexer->setPaper (bg_color->color (), styles[i]);
@@ -800,19 +966,17 @@
           }
       }
 
-    lexer->writeSettings (*settings);
+    const std::string group = 
+      QString ("Scintilla" + settings_color_modes_ext[mode]).toStdString ();
+
+    lexer->writeSettings (*settings, group.c_str ());
 
     settings->setValue (sd_last_editor_styles_tab.key,
                         tabs_editor_lexers->currentIndex ());
     settings->sync ();
-
-#else
-
-    octave_unused_parameter (lexer);
-    octave_unused_parameter (settings);
+  }
 
 #endif
-  }
 
   void settings_dialog::write_changed_settings (bool closing)
   {
@@ -858,6 +1022,9 @@
     // cursor blinking
     settings->setValue (global_cursor_blinking.key, cb_cursor_blinking->isChecked ());
 
+    // focus follows mouse
+    settings->setValue (dw_focus_follows_mouse.key, cb_focus_follows_mouse->isChecked ());
+
     // promp to exit
     settings->setValue (global_prompt_to_exit.key, cb_prompt_to_exit->isChecked ());
 
@@ -874,7 +1041,6 @@
     settings->setValue (ed_show_line_numbers.key, editor_showLineNumbers->isChecked ());
     settings->setValue (ed_line_numbers_size.key, editor_linenr_size->value ());
     settings->setValue (ed_highlight_current_line.key, editor_highlightCurrentLine->isChecked ());
-    settings->setValue (ed_highlight_current_line_color.key, m_editor_current_line_color->color ());
     settings->setValue (ed_long_line_marker.key, editor_long_line_marker->isChecked ());
     settings->setValue (ed_long_line_marker_line.key, editor_long_line_marker_line->isChecked ());
     settings->setValue (ed_long_line_marker_background.key, editor_long_line_marker_background->isChecked ());
@@ -902,6 +1068,8 @@
     settings->setValue (ed_default_eol_mode.key, combo_eol_mode->currentIndex ());
 
     settings->setValue (ed_tab_position.key, editor_combox_tab_pos->currentIndex ());
+    settings->setValue (ed_tabs_rotated.key, editor_cb_tabs_rotated->isChecked ());
+    settings->setValue (ed_tabs_max_width.key, editor_sb_tabs_max_width->value ());
 
     // Comment strings
     int rb_uncomment = 0;
@@ -928,35 +1096,37 @@
     settings->setValue (ed_indent_width.key, editor_ind_width_spinbox->value ());
     settings->setValue (ed_indent_uses_tabs.key, editor_ind_uses_tabs_checkbox->isChecked ());
     settings->setValue (ed_tab_width.key, editor_tab_width_spinbox->value ());
-    settings->setValue (ed_long_window_title.key, editor_longWindowTitle->isChecked ());
-    settings->setValue (ed_notebook_tab_width_min.key, editor_notebook_tab_width_min->value ());
-    settings->setValue (ed_notebook_tab_width_max.key, editor_notebook_tab_width_max->value ());
     settings->setValue (ed_restore_session.key, editor_restoreSession->isChecked ());
     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 ());
-    settings->setValue (cs_font.key, terminal_fontName->currentFont ().family ());
-
     // file browser
     settings->setValue (fb_sync_octdir.key, sync_octave_directory->isChecked ());
     settings->setValue (fb_restore_last_dir.key, cb_restore_file_browser_dir->isChecked ());
     settings->setValue (fb_startup_dir.key, le_file_browser_dir->text ());
     settings->setValue (fb_txt_file_ext.key, le_file_browser_extensions->text ());
 
+    // network
     settings->setValue (nr_allow_connection.key, checkbox_allow_web_connect->isChecked ());
-    settings->setValue (global_use_proxy.key, useProxyServer->isChecked ());
-    settings->setValue (global_proxy_type.key, proxyType->currentText ());
-    settings->setValue (global_proxy_host.key, proxyHostName->text ());
-    settings->setValue (global_proxy_port.key, proxyPort->text ());
-    settings->setValue (global_proxy_user.key, proxyUserName->text ());
-    settings->setValue (global_proxy_pass.key, proxyPassword->text ());
+    settings->setValue (global_use_proxy.key, use_proxy_server->isChecked ());
+    settings->setValue (global_proxy_type.key, proxy_type->currentText ());
+    settings->setValue (global_proxy_host.key, proxy_host_name->text ());
+    settings->setValue (global_proxy_port.key, proxy_port->text ());
+    settings->setValue (global_proxy_user.key, proxy_username->text ());
+    settings->setValue (global_proxy_pass.key, proxy_password->text ());
+
+    // command window
+    settings->setValue (cs_font_size.key, terminal_fontSize->value ());
+    settings->setValue (cs_font.key, terminal_fontName->currentFont ().family ());
     settings->setValue (cs_cursor_use_fgcol.key, terminal_cursorUseForegroundColor->isChecked ());
     settings->setValue (cs_focus_cmd.key, terminal_focus_command->isChecked ());
     settings->setValue (cs_dbg_location.key, terminal_print_dbg_location->isChecked ());
     settings->setValue (cs_hist_buffer.key, terminal_history_buffer->value ());
+    write_terminal_colors (settings);
 
     // the cursor
     QString cursor_type;
@@ -990,6 +1160,10 @@
     write_lexer_settings (lexer, settings);
     delete lexer;
 
+    lexer = new QsciLexerJava ();
+    write_lexer_settings (lexer, settings);
+    delete lexer;
+
     lexer = new QsciLexerPerl ();
     write_lexer_settings (lexer, settings);
     delete lexer;
@@ -1015,9 +1189,6 @@
     // Workspace
     write_workspace_colors (settings);
 
-    // Terminal
-    write_terminal_colors (settings);
-
     // Variable editor
     settings->setValue (ve_column_width.key, varedit_columnWidth->value ());
     settings->setValue (ve_row_height.key, varedit_rowHeight->value ());
@@ -1030,6 +1201,7 @@
     // shortcuts
 
     settings->setValue (sc_prevent_rl_conflicts.key, cb_prevent_readline_conflicts->isChecked ());
+    settings->setValue (sc_prevent_rl_conflicts_menu.key, cb_prevent_readline_conflicts_menu->isChecked ());
     shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager ();
     scmgr.write_shortcuts (settings, closing);
 
@@ -1048,52 +1220,111 @@
     QVector<color_picker*> color (ws_colors_count);
 
     int column = 0;
+    const int color_columns = 3;  // place colors in so many columns
     int row = 0;
+    int mode = settings->value (ws_color_mode).toInt ();
 
     m_ws_enable_colors = new QCheckBox (tr ("Enable attribute colors"));
     style_grid->addWidget (m_ws_enable_colors, row++, column, 1, 4);
 
     m_ws_hide_tool_tips = new QCheckBox (tr ("Hide tools tips"));
     style_grid->addWidget (m_ws_hide_tool_tips, row++, column, 1, 4);
-    connect (m_ws_enable_colors, SIGNAL (toggled (bool)),
-             m_ws_hide_tool_tips, SLOT(setEnabled (bool)));
+    connect (m_ws_enable_colors, &QCheckBox::toggled,
+             m_ws_hide_tool_tips, &QCheckBox::setEnabled);
     m_ws_hide_tool_tips->setChecked
       (settings->value (ws_hide_tool_tips).toBool ());
 
+    QCheckBox *cb_color_mode = new QCheckBox (settings_color_modes);
+    cb_color_mode->setToolTip (settings_color_modes_tooltip);
+    cb_color_mode->setChecked (mode == 1);
+    cb_color_mode->setObjectName (ws_color_mode.key);
+    connect (m_ws_enable_colors, &QCheckBox::toggled,
+             cb_color_mode, &QCheckBox::setEnabled);
+    style_grid->addWidget (cb_color_mode, row, column);
+
+    QPushButton *pb_reload_default_colors = new QPushButton (settings_reload_colors);
+    pb_reload_default_colors->setToolTip (settings_reload_colors_tooltip);
+    connect (m_ws_enable_colors, &QCheckBox::toggled,
+             pb_reload_default_colors, &QPushButton::setEnabled);
+    style_grid->addWidget (pb_reload_default_colors, row+1, column++);
+
+    bool colors_enabled = settings->value (ws_enable_colors).toBool ();
+
     for (int i = 0; i < ws_colors_count; i++)
       {
         description[i] = new QLabel ("    "
           + tr (ws_color_names.at (i).toStdString ().data ()));
         description[i]->setAlignment (Qt::AlignRight);
-        connect (m_ws_enable_colors, SIGNAL (toggled (bool)),
-                 description[i], SLOT(setEnabled (bool)));
+        description[i]->setEnabled (colors_enabled);
+        connect (m_ws_enable_colors, &QCheckBox::toggled,
+                 description[i], &QLabel::setEnabled);
 
-        QColor setting_color = settings->value (ws_colors[i].key,
-                                                ws_colors[i].def).value<QColor> ();
+        QColor setting_color = settings->color_value (ws_colors[i], mode);
         color[i] = new color_picker (setting_color);
         color[i]->setObjectName (ws_colors[i].key);
         color[i]->setMinimumSize (30, 10);
-        connect (m_ws_enable_colors, SIGNAL (toggled (bool)),
-                 color[i], SLOT(setEnabled (bool)));
+        color[i]->setEnabled (colors_enabled);
+        connect (m_ws_enable_colors, &QCheckBox::toggled,
+                 color[i], &color_picker::setEnabled);
 
         style_grid->addWidget (description[i], row, 3*column);
         style_grid->addWidget (color[i], row, 3*column+1);
-        if (++column == 3)
+        if (++column > color_columns)
           {
             style_grid->setColumnStretch (4*column, 10);
             row++;
-            column = 0;
+            column = 1;
           }
       }
 
     // Load enable settings at the end for having signals already connected
-    bool colors_enabled =
-      settings->value (ws_enable_colors).toBool ();
     m_ws_enable_colors->setChecked (colors_enabled);
     m_ws_hide_tool_tips->setEnabled (colors_enabled);
+    cb_color_mode->setEnabled (colors_enabled);
+    pb_reload_default_colors->setEnabled (colors_enabled);
 
     // place grid with elements into the tab
     workspace_colors_box->setLayout (style_grid);
+
+    // update colors depending on second theme selection or reloading
+    // the dfault values
+    connect (cb_color_mode, &QCheckBox::stateChanged,
+             this, &settings_dialog::update_workspace_colors);
+    connect (pb_reload_default_colors, &QPushButton::clicked,
+             [=] () { update_workspace_colors (settings_reload_default_colors_flag); });
+  }
+
+  void settings_dialog::update_workspace_colors (int def)
+  {
+    QCheckBox *cb_color_mode
+      = workspace_colors_box->findChild <QCheckBox *> (ws_color_mode.key);
+
+    int m = 0;
+    if (cb_color_mode && cb_color_mode->isChecked ())
+      m = 1;
+
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+    color_picker *c_picker;
+
+    for (unsigned int i = 0; i < ws_colors_count; i++)
+      {
+        c_picker = workspace_colors_box->findChild <color_picker *> (ws_colors[i].key);
+        if (c_picker)
+          {
+            if (def != settings_reload_default_colors_flag)
+              {
+                // Get current value from settings or the default
+                c_picker->set_color (settings->color_value (ws_colors[i], m));
+              }
+            else
+              {
+                // Get the default value
+                c_picker->set_color (settings->get_color_value (ws_colors[i].def, m));
+              }
+          }
+      }
   }
 
   void settings_dialog::write_workspace_colors (gui_settings *settings)
@@ -1101,14 +1332,24 @@
     settings->setValue (ws_enable_colors.key, m_ws_enable_colors->isChecked ());
     settings->setValue (ws_hide_tool_tips.key, m_ws_hide_tool_tips->isChecked ());
 
+    QCheckBox *cb_color_mode
+      = workspace_colors_box->findChild <QCheckBox *> (ws_color_mode.key);
+
+    int mode = 0;
+    if (cb_color_mode && cb_color_mode->isChecked ())
+      mode = 1;
+
     color_picker *color;
 
     for (int i = 0; i < ws_colors_count; i++)
       {
         color = workspace_colors_box->findChild <color_picker *> (ws_colors[i].key);
         if (color)
-          settings->setValue (ws_colors[i].key, color->color ());
+          settings->set_color_value (ws_colors[i], color->color (), mode);
       }
+
+    settings->setValue (ws_color_mode.key, mode);
+
     settings->sync ();
   }
 
@@ -1118,43 +1359,103 @@
     QVector<QLabel*> description (cs_colors_count);
     QVector<color_picker*> color (cs_colors_count);
 
-    int column = 0;
+    int mode = settings->value (cs_color_mode).toInt ();
+
+    QCheckBox *cb_color_mode = new QCheckBox (settings_color_modes);
+    cb_color_mode->setToolTip (settings_color_modes_tooltip);
+    cb_color_mode->setChecked (mode == 1);
+    cb_color_mode->setObjectName (cs_color_mode.key);
+    style_grid->addWidget (cb_color_mode, 0, 0);
+
+    QPushButton *pb_reload_default_colors = new QPushButton (settings_reload_colors);
+    pb_reload_default_colors->setToolTip (settings_reload_colors_tooltip);
+    style_grid->addWidget (pb_reload_default_colors, 1, 0);
+
+    int column = 1;               // column 0 is for the color mode checkbox
+    const int color_columns = 2;  // place colors in so many columns
     int row = 0;
     for (unsigned int i = 0; i < cs_colors_count; i++)
       {
         description[i] = new QLabel ("    "
             + tr (cs_color_names.at (i).toStdString ().data ()));
         description[i]->setAlignment (Qt::AlignRight);
-        QVariant default_var = cs_colors[i].def;
-        QColor setting_color = settings->value (cs_colors[i].key, cs_colors[i].def).value<QColor> ();
+        QColor setting_color = settings->color_value (cs_colors[i], mode);
         color[i] = new color_picker (setting_color);
         color[i]->setObjectName (cs_colors[i].key);
         color[i]->setMinimumSize (30, 10);
         style_grid->addWidget (description[i], row, 2*column);
         style_grid->addWidget (color[i], row, 2*column+1);
-        if (++column == 2)
+        if (++column > color_columns)
           {
             style_grid->setColumnStretch (3*column, 10);
             row++;
-            column = 0;
+            column = 1;
           }
       }
 
     // place grid with elements into the tab
     terminal_colors_box->setLayout (style_grid);
+
+    // update colors depending on second theme selection
+    connect (cb_color_mode, &QCheckBox::stateChanged,
+             this, &settings_dialog::update_terminal_colors);
+    connect (pb_reload_default_colors, &QPushButton::clicked,
+             [=] () { update_terminal_colors (settings_reload_default_colors_flag); });
+  }
+
+  void settings_dialog::update_terminal_colors (int def)
+  {
+    QCheckBox *cb_color_mode
+      = terminal_colors_box->findChild <QCheckBox *> (cs_color_mode.key);
+
+    int m = 0;
+    if (cb_color_mode && cb_color_mode->isChecked ())
+      m = 1;
+
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+    color_picker *c_picker;
+
+    for (unsigned int i = 0; i < cs_colors_count; i++)
+      {
+        c_picker = terminal_colors_box->findChild <color_picker *> (cs_colors[i].key);
+        if (c_picker)
+          {
+            if (def != settings_reload_default_colors_flag)
+              {
+                // Get current value from settings or the default
+                c_picker->set_color (settings->color_value (cs_colors[i], m));
+              }
+            else
+              {
+                // Get the default value
+                c_picker->set_color (settings->get_color_value (cs_colors[i].def, m));
+              }
+          }
+      }
   }
 
   void settings_dialog::write_terminal_colors (gui_settings *settings)
   {
+    QCheckBox *cb_color_mode
+      = terminal_colors_box->findChild <QCheckBox *> (cs_color_mode.key);
+
+    int mode = 0;
+    if (cb_color_mode && cb_color_mode->isChecked ())
+      mode = 1;
+
     color_picker *color;
 
     for (int i = 0; i < cs_color_names.size (); i++)
       {
         color = terminal_colors_box->findChild <color_picker *> (cs_colors[i].key);
         if (color)
-          settings->setValue (cs_colors[i].key, color->color ());
+          settings->set_color_value (cs_colors[i], color->color (), mode);
       }
 
+    settings->setValue (cs_color_mode.key, mode);
+
     settings->sync ();
   }
 
@@ -1164,7 +1465,20 @@
     QVector<QLabel*> description (ve_colors_count);
     QVector<color_picker*> color (ve_colors_count);
 
-    int column = 0;
+    int mode = settings->value (ve_color_mode).toInt ();
+
+    QCheckBox *cb_color_mode = new QCheckBox (settings_color_modes);
+    cb_color_mode->setToolTip (settings_color_modes_tooltip);
+    cb_color_mode->setChecked (mode == 1);
+    cb_color_mode->setObjectName (ve_color_mode.key);
+    style_grid->addWidget (cb_color_mode, 0, 0);
+
+    QPushButton *pb_reload_default_colors = new QPushButton (settings_reload_colors);
+    pb_reload_default_colors->setToolTip (settings_reload_colors_tooltip);
+    style_grid->addWidget (pb_reload_default_colors, 1, 0);
+
+    int column = 1;
+    int color_columns = 2;
     int row = 0;
     for (int i = 0; i < ve_colors_count; i++)
       {
@@ -1172,44 +1486,83 @@
             + tr (ve_color_names.at (i).toStdString ().data ()));
         description[i]->setAlignment (Qt::AlignRight);
 
-        // The default colors are given as color roles for
-        // the application's palette
-        QColor default_color = qApp->palette ().color
-                              (static_cast<QPalette::ColorRole> (ve_colors[i].def.toInt ()));
-                  // FIXME: use value<QPalette::ColorRole> instead of static cast after
-                  //        dropping support of Qt 5.4
-
-        QColor setting_color =
-            settings->value (ve_colors[i].key, default_color).value<QColor> ();
-
+        QColor setting_color = settings->color_value (ve_colors[i], mode);
         color[i] = new color_picker (setting_color);
         color[i]->setObjectName (ve_colors[i].key);
         color[i]->setMinimumSize (30, 10);
         style_grid->addWidget (description[i], row, 2*column);
         style_grid->addWidget (color[i], row, 2*column+1);
-        if (++column == 2)
+        if (++column > color_columns)
           {
             style_grid->setColumnStretch (3*column, 10);
             row++;
-            column = 0;
+            column = 1;
           }
       }
 
     // place grid with elements into the tab
     varedit_colors_box->setLayout (style_grid);
+
+    // update colors depending on second theme selection
+    connect (cb_color_mode, &QCheckBox::stateChanged,
+             this, &settings_dialog::update_varedit_colors);
+    connect (pb_reload_default_colors, &QPushButton::clicked,
+             [=] () { update_varedit_colors (settings_reload_default_colors_flag); });
+  }
+
+  void settings_dialog::update_varedit_colors (int def)
+  {
+    QCheckBox *cb_color_mode
+      = varedit_colors_box->findChild <QCheckBox *> (ve_color_mode.key);
+
+    int m = 0;
+    if (cb_color_mode && cb_color_mode->isChecked ())
+      m = 1;
+
+    resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
+    gui_settings *settings = rmgr.get_settings ();
+
+    color_picker *c_picker;
+
+    for (unsigned int i = 0; i < ve_colors_count; i++)
+      {
+        c_picker = varedit_colors_box->findChild <color_picker *> (ve_colors[i].key);
+        if (c_picker)
+          {
+            if (def != settings_reload_default_colors_flag)
+              {
+                // Get current value from settings or the default
+                c_picker->set_color (settings->color_value (ve_colors[i], m));
+              }
+            else
+              {
+                // Get the default value
+                c_picker->set_color (settings->get_color_value (ve_colors[i].def, m));
+              }
+          }
+      }
   }
 
   void settings_dialog::write_varedit_colors (gui_settings *settings)
   {
+    QCheckBox *cb_color_mode
+      = varedit_colors_box->findChild <QCheckBox *> (ve_color_mode.key);
+
+    int mode = 0;
+    if (cb_color_mode && cb_color_mode->isChecked ())
+      mode = 1;
+
     color_picker *color;
 
     for (int i = 0; i < ve_colors_count; i++)
       {
         color = varedit_colors_box->findChild <color_picker *> (ve_colors[i].key);
         if (color)
-          settings->setValue (ve_colors[i].key, color->color ());
+          settings->set_color_value (ve_colors[i], color->color (), mode);
       }
 
+    settings->setValue (ve_color_mode.key, mode);
+
     settings->sync ();
   }
 }
--- a/libgui/src/settings-dialog.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/settings-dialog.h	Sun May 16 09:44:35 2021 +0200
@@ -65,6 +65,13 @@
     void get_file_browser_dir (void);
     void get_dir (QLineEdit*, const QString&);
     void set_disabled_pref_file_browser_dir (bool disable);
+    void proxy_items_update (void);
+
+    // slots updating colors depending on theme
+    void update_terminal_colors (int def = 0);
+    void update_workspace_colors (int def = 0);
+    void update_varedit_colors (int def = 0);
+    void update_editor_lexers (int def = 0);
 
     // slots for dialog's buttons
     void button_clicked (QAbstractButton *button);
@@ -76,8 +83,11 @@
 
   private:
 
-    void read_lexer_settings (QsciLexer *lexer, gui_settings *settings);
+#if defined (HAVE_QSCINTILLA)
+    void update_lexer (QsciLexer *lexer, gui_settings *settings, int mode, int def = 0);
+    void get_lexer_settings (QsciLexer *lexer, gui_settings *settings);
     void write_lexer_settings (QsciLexer *lexer, gui_settings *settings);
+#endif
 
     void write_changed_settings (bool closing);
 
@@ -96,7 +106,6 @@
     color_picker *m_widget_title_bg_color_active;
     color_picker *m_widget_title_fg_color;
     color_picker *m_widget_title_fg_color_active;
-    color_picker *m_editor_current_line_color;
 
     QRadioButton *m_rb_comment_strings[ed_comment_strings_count];
     QCheckBox *m_rb_uncomment_strings[ed_comment_strings_count];
--- a/libgui/src/settings-dialog.ui	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/settings-dialog.ui	Sun May 16 09:44:35 2021 +0200
@@ -31,8 +31,11 @@
        <height>0</height>
       </size>
      </property>
+     <property name="toolTip">
+      <string/>
+     </property>
      <property name="currentIndex">
-      <number>5</number>
+      <number>2</number>
      </property>
      <widget class="QWidget" name="tab_general">
       <property name="enabled">
@@ -52,8 +55,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>1021</width>
-            <height>607</height>
+            <width>1023</width>
+            <height>615</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_17">
@@ -112,16 +115,6 @@
                   </property>
                  </widget>
                 </item>
-                <item row="8" column="0">
-                 <widget class="QCheckBox" name="cb_use_native_file_dialogs">
-                  <property name="text">
-                   <string>Use native file dialogs</string>
-                  </property>
-                  <property name="checked">
-                   <bool>true</bool>
-                  </property>
-                 </widget>
-                </item>
                 <item row="3" column="1">
                  <layout class="QVBoxLayout" name="verticalLayout_5">
                   <item>
@@ -174,26 +167,6 @@
                   </item>
                  </layout>
                 </item>
-                <item row="9" column="0">
-                 <widget class="QCheckBox" name="cb_cursor_blinking">
-                  <property name="text">
-                   <string>Cursor blinking</string>
-                  </property>
-                  <property name="checked">
-                   <bool>true</bool>
-                  </property>
-                 </widget>
-                </item>
-                <item row="10" column="0">
-                 <widget class="QCheckBox" name="cb_status_bar">
-                  <property name="text">
-                   <string>Show status bar</string>
-                  </property>
-                  <property name="checked">
-                   <bool>true</bool>
-                  </property>
-                 </widget>
-                </item>
                 <item row="5" column="1">
                  <layout class="QHBoxLayout" name="horizontalLayout_9">
                   <item>
@@ -414,13 +387,6 @@
                   </item>
                  </layout>
                 </item>
-                <item row="11" column="0">
-                 <widget class="QCheckBox" name="cb_prompt_to_exit">
-                  <property name="text">
-                   <string>Confirm before exiting</string>
-                  </property>
-                 </widget>
-                </item>
                 <item row="1" column="0">
                  <widget class="QLabel" name="label_2">
                   <property name="text">
@@ -464,6 +430,63 @@
                 </item>
                </layout>
               </item>
+              <item>
+               <layout class="QVBoxLayout" name="verticalLayout_35">
+                <property name="spacing">
+                 <number>0</number>
+                </property>
+                <property name="topMargin">
+                 <number>0</number>
+                </property>
+                <item>
+                 <widget class="QCheckBox" name="cb_use_native_file_dialogs">
+                  <property name="text">
+                   <string>Use native file dialogs</string>
+                  </property>
+                  <property name="checked">
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QCheckBox" name="cb_cursor_blinking">
+                  <property name="text">
+                   <string>Cursor blinking</string>
+                  </property>
+                  <property name="checked">
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QCheckBox" name="cb_status_bar">
+                  <property name="text">
+                   <string>Show status bar</string>
+                  </property>
+                  <property name="checked">
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QCheckBox" name="cb_focus_follows_mouse">
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If set, the focus of the widgets that are docked to the main window follows the mouse cursor. This is intended for having the same behavior within the main window when &amp;quot;focus follows mouse&amp;quot; is used for the desktop environment.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="text">
+                   <string>Focus follows mouse for widgets docked to the main window</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QCheckBox" name="cb_prompt_to_exit">
+                  <property name="text">
+                   <string>Confirm before exiting</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
              </layout>
             </widget>
            </item>
@@ -561,8 +584,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>1035</width>
-            <height>569</height>
+            <width>1037</width>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_7">
@@ -841,9 +864,9 @@
           <property name="geometry">
            <rect>
             <x>0</x>
-            <y>0</y>
-            <width>1021</width>
-            <height>1467</height>
+            <y>-913</y>
+            <width>1023</width>
+            <height>1492</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_16">
@@ -1007,69 +1030,6 @@
                   </item>
                  </layout>
                 </item>
-                <item row="3" column="2">
-                 <layout class="QGridLayout" name="gridLayout_16">
-                  <item row="0" column="1">
-                   <spacer name="horizontalSpacer_11">
-                    <property name="orientation">
-                     <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="sizeHint" stdset="0">
-                     <size>
-                      <width>40</width>
-                      <height>20</height>
-                     </size>
-                    </property>
-                   </spacer>
-                  </item>
-                  <item row="0" column="0">
-                   <layout class="QGridLayout" name="editor_grid_current_line">
-                    <item row="0" column="2">
-                     <widget class="QLabel" name="editor_label_cl_color">
-                      <property name="enabled">
-                       <bool>false</bool>
-                      </property>
-                      <property name="text">
-                       <string>Color</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="0" column="0">
-                     <widget class="QCheckBox" name="editor_highlightCurrentLine">
-                      <property name="enabled">
-                       <bool>true</bool>
-                      </property>
-                      <property name="sizePolicy">
-                       <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
-                        <horstretch>0</horstretch>
-                        <verstretch>0</verstretch>
-                       </sizepolicy>
-                      </property>
-                      <property name="text">
-                       <string>Highlight current line</string>
-                      </property>
-                     </widget>
-                    </item>
-                    <item row="0" column="1">
-                     <spacer name="horizontalSpacer_14">
-                      <property name="orientation">
-                       <enum>Qt::Horizontal</enum>
-                      </property>
-                      <property name="sizeType">
-                       <enum>QSizePolicy::Fixed</enum>
-                      </property>
-                      <property name="sizeHint" stdset="0">
-                       <size>
-                        <width>20</width>
-                        <height>20</height>
-                       </size>
-                      </property>
-                     </spacer>
-                    </item>
-                   </layout>
-                  </item>
-                 </layout>
-                </item>
                 <item row="3" column="0">
                  <widget class="QCheckBox" name="cb_show_eol">
                   <property name="sizePolicy">
@@ -1099,6 +1059,22 @@
                   </property>
                  </spacer>
                 </item>
+                <item row="3" column="2">
+                 <widget class="QCheckBox" name="editor_highlightCurrentLine">
+                  <property name="enabled">
+                   <bool>true</bool>
+                  </property>
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="text">
+                   <string>Highlight current line</string>
+                  </property>
+                 </widget>
+                </item>
                </layout>
               </item>
               <item>
@@ -1179,23 +1155,7 @@
              <layout class="QVBoxLayout" name="verticalLayout_32">
               <item>
                <layout class="QGridLayout" name="gridLayout_23">
-                <item row="1" column="1">
-                 <spacer name="horizontalSpacer_24">
-                  <property name="orientation">
-                   <enum>Qt::Horizontal</enum>
-                  </property>
-                  <property name="sizeType">
-                   <enum>QSizePolicy::Fixed</enum>
-                  </property>
-                  <property name="sizeHint" stdset="0">
-                   <size>
-                    <width>10</width>
-                    <height>0</height>
-                   </size>
-                  </property>
-                 </spacer>
-                </item>
-                <item row="0" column="2">
+                <item row="0" column="1">
                  <layout class="QHBoxLayout" name="horizontalLayout_21">
                   <item>
                    <widget class="QComboBox" name="editor_combox_tab_pos"/>
@@ -1205,6 +1165,76 @@
                     <property name="orientation">
                      <enum>Qt::Horizontal</enum>
                     </property>
+                    <property name="sizeType">
+                     <enum>QSizePolicy::Fixed</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                     <size>
+                      <width>20</width>
+                      <height>10</height>
+                     </size>
+                    </property>
+                   </spacer>
+                  </item>
+                  <item>
+                   <widget class="QCheckBox" name="editor_cb_tabs_rotated">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Roate tabs: Vertical when at top or bottom and horizontal when left or right. The close button is not shown in rotated tabs.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="text">
+                     <string>Rotated tabs</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
+                   <spacer name="horizontalSpacer_33">
+                    <property name="orientation">
+                     <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeType">
+                     <enum>QSizePolicy::Fixed</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                     <size>
+                      <width>20</width>
+                      <height>10</height>
+                     </size>
+                    </property>
+                   </spacer>
+                  </item>
+                 </layout>
+                </item>
+                <item row="0" column="0">
+                 <widget class="QLabel" name="label_30">
+                  <property name="text">
+                   <string>Position</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="2">
+                 <layout class="QHBoxLayout" name="horizontalLayout_15">
+                  <item>
+                   <widget class="QLabel" name="label_3">
+                    <property name="text">
+                     <string>Max. tab width in chars (0: no limit)</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QSpinBox" name="editor_sb_tabs_max_width">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Max. width of a tab in characters (average char. width). Especially useful for rotated tabs.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="maximum">
+                     <number>64</number>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
+                   <spacer name="horizontalSpacer_38">
+                    <property name="orientation">
+                     <enum>Qt::Horizontal</enum>
+                    </property>
                     <property name="sizeHint" stdset="0">
                      <size>
                       <width>40</width>
@@ -1215,113 +1245,6 @@
                   </item>
                  </layout>
                 </item>
-                <item row="0" column="0">
-                 <widget class="QLabel" name="label_30">
-                  <property name="text">
-                   <string>Tab position</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="2">
-                 <layout class="QHBoxLayout" name="horizontalLayout_20">
-                  <property name="rightMargin">
-                   <number>0</number>
-                  </property>
-                  <item>
-                   <widget class="QLabel" name="editor_lbl_min_tab_width">
-                    <property name="enabled">
-                     <bool>false</bool>
-                    </property>
-                    <property name="text">
-                     <string>Tab width min.</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QSpinBox" name="editor_notebook_tab_width_min">
-                    <property name="sizePolicy">
-                     <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                      <horstretch>0</horstretch>
-                      <verstretch>0</verstretch>
-                     </sizepolicy>
-                    </property>
-                    <property name="minimum">
-                     <number>80</number>
-                    </property>
-                    <property name="maximum">
-                     <number>600</number>
-                    </property>
-                    <property name="singleStep">
-                     <number>20</number>
-                    </property>
-                    <property name="value">
-                     <number>160</number>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QLabel" name="editor_lbl_max_tab_width">
-                    <property name="enabled">
-                     <bool>false</bool>
-                    </property>
-                    <property name="text">
-                     <string>max.</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item>
-                   <widget class="QSpinBox" name="editor_notebook_tab_width_max">
-                    <property name="enabled">
-                     <bool>false</bool>
-                    </property>
-                    <property name="sizePolicy">
-                     <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                      <horstretch>0</horstretch>
-                      <verstretch>0</verstretch>
-                     </sizepolicy>
-                    </property>
-                    <property name="minimum">
-                     <number>180</number>
-                    </property>
-                    <property name="maximum">
-                     <number>600</number>
-                    </property>
-                    <property name="singleStep">
-                     <number>20</number>
-                    </property>
-                    <property name="value">
-                     <number>300</number>
-                    </property>
-                   </widget>
-                  </item>
-                 </layout>
-                </item>
-                <item row="1" column="0">
-                 <widget class="QCheckBox" name="editor_longWindowTitle">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="text">
-                   <string>Show complete path in title</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="3">
-                 <spacer name="horizontalSpacer_5">
-                  <property name="orientation">
-                   <enum>Qt::Horizontal</enum>
-                  </property>
-                  <property name="sizeHint" stdset="0">
-                   <size>
-                    <width>40</width>
-                    <height>20</height>
-                   </size>
-                  </property>
-                 </spacer>
-                </item>
                </layout>
               </item>
              </layout>
@@ -2053,7 +1976,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 +2034,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 +2061,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 +2071,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>
@@ -2181,6 +2124,9 @@
                </widget>
               </item>
               <item>
+               <layout class="QGridLayout" name="editor_style_grid"/>
+              </item>
+              <item>
                <widget class="QTabWidget" name="tabs_editor_lexers">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@@ -2227,8 +2173,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>1035</width>
-            <height>569</height>
+            <width>1037</width>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QGridLayout" name="gridLayout_8">
@@ -2377,8 +2323,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>1035</width>
-            <height>569</height>
+            <width>1037</width>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_19">
@@ -2439,8 +2385,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>1035</width>
-            <height>569</height>
+            <width>1037</width>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_vesc_manual">
@@ -2604,8 +2550,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>1035</width>
-            <height>569</height>
+            <width>1037</width>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_25">
@@ -2618,11 +2564,18 @@
               <number>0</number>
              </property>
              <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_15">
-               <item>
+              <layout class="QVBoxLayout" name="verticalLayout_36">
+               <property name="topMargin">
+                <number>6</number>
+               </property>
+              </layout>
+             </item>
+             <item>
+              <layout class="QGridLayout" name="gridLayout_6">
+               <item row="0" column="0">
                 <widget class="QCheckBox" name="cb_prevent_readline_conflicts">
                  <property name="toolTip">
-                  <string>Select this option to prevent conflicts with readline shortcuts</string>
+                  <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&amp;lt;html&amp;gt;&amp;lt;head/&amp;gt;&amp;lt;body&amp;gt;&amp;lt;p&amp;gt;Disable global shortcuts in order to prevent interference with readline key strokes. Exceptions: Ctrl-C for interrupting the interpreter and the shortcuts for switching to other widgets.&amp;lt;/p&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                  </property>
                  <property name="text">
                   <string>Disable global shortcuts when Command Window has focus</string>
@@ -2632,6 +2585,13 @@
                  </property>
                 </widget>
                </item>
+               <item row="1" column="0">
+                <widget class="QCheckBox" name="cb_prevent_readline_conflicts_menu">
+                 <property name="text">
+                  <string>Disable menu accelerators of main window menus when Commmand Window has focus</string>
+                 </property>
+                </widget>
+               </item>
               </layout>
              </item>
              <item>
@@ -2803,130 +2763,157 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>1035</width>
-            <height>569</height>
+            <width>1037</width>
+            <height>571</height>
            </rect>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_20">
            <item>
-            <layout class="QVBoxLayout" name="verticalLayout">
-             <item>
-              <widget class="QCheckBox" name="checkbox_allow_web_connect">
-               <property name="text">
-                <string>Allow Octave to connect to the Octave web site to display current news and information</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <layout class="QGridLayout" name="gridLayout_5">
-               <item row="1" column="1">
-                <widget class="QLabel" name="label_4">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Hostname:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="2">
-                <widget class="QComboBox" name="proxyType">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <item>
-                  <property name="text">
-                   <string>HttpProxy</string>
-                  </property>
-                 </item>
-                 <item>
-                  <property name="text">
-                   <string>Socks5Proxy</string>
-                  </property>
-                 </item>
-                </widget>
-               </item>
-               <item row="3" column="1">
-                <widget class="QLabel" name="label_6">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Username:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="0">
-                <widget class="QCheckBox" name="useProxyServer">
-                 <property name="text">
-                  <string>Use proxy server</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="1">
-                <widget class="QLabel" name="label_3">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Proxy type:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="2" column="1">
-                <widget class="QLabel" name="label_5">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Port:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="4" column="1">
-                <widget class="QLabel" name="label_7">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="text">
-                  <string>Password:</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="1" column="2">
-                <widget class="QLineEdit" name="proxyHostName">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="2" column="2">
-                <widget class="QLineEdit" name="proxyPort">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="3" column="2">
-                <widget class="QLineEdit" name="proxyUserName">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                </widget>
-               </item>
-               <item row="4" column="2">
-                <widget class="QLineEdit" name="proxyPassword">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="echoMode">
-                  <enum>QLineEdit::Password</enum>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </item>
-            </layout>
+            <widget class="QGroupBox" name="groupBox_12">
+             <property name="title">
+              <string>General</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_33">
+              <item>
+               <widget class="QCheckBox" name="checkbox_allow_web_connect">
+                <property name="text">
+                 <string>Allow Octave to connect to the Octave web site to display current news and information</string>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item>
+            <widget class="QGroupBox" name="groupBox_13">
+             <property name="title">
+              <string>Proxy Server</string>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_34">
+              <item>
+               <layout class="QVBoxLayout" name="verticalLayout">
+                <item>
+                 <layout class="QGridLayout" name="gridLayout_5">
+                  <item row="1" column="2">
+                   <widget class="QLabel" name="proxy_host_name_label">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="text">
+                     <string>Hostname:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="3">
+                   <widget class="QComboBox" name="proxy_type">
+                    <property name="enabled">
+                     <bool>true</bool>
+                    </property>
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select &lt;span style=&quot; font-style:italic;&quot;&gt;HttpProxy&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;Sock5Proxy&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Environment Variables&lt;/span&gt;. With the last selection, the proxy is taken from the first non-empty environment variable ALL_PROXY, HTTP_PROXY or HTTPS_PROXY .&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="3" column="2">
+                   <widget class="QLabel" name="proxy_username_label">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="text">
+                     <string>Username:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="2">
+                   <widget class="QLabel" name="proxy_type_label">
+                    <property name="enabled">
+                     <bool>true</bool>
+                    </property>
+                    <property name="text">
+                     <string>Proxy type:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="2" column="2">
+                   <widget class="QLabel" name="proxy_port_label">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="text">
+                     <string>Port:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="4" column="2">
+                   <widget class="QLabel" name="proxy_password_label">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="text">
+                     <string>Password:</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="1" column="3">
+                   <widget class="QLineEdit" name="proxy_host_name">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="2" column="3">
+                   <widget class="QLineEdit" name="proxy_port">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="3" column="3">
+                   <widget class="QLineEdit" name="proxy_username">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="4" column="3">
+                   <widget class="QLineEdit" name="proxy_password">
+                    <property name="enabled">
+                     <bool>false</bool>
+                    </property>
+                    <property name="echoMode">
+                     <enum>QLineEdit::Password</enum>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="0">
+                   <widget class="QCheckBox" name="use_proxy_server">
+                    <property name="text">
+                     <string>Use proxy server</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="1">
+                   <spacer name="horizontalSpacer_30">
+                    <property name="orientation">
+                     <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeType">
+                     <enum>QSizePolicy::Fixed</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                     <size>
+                      <width>20</width>
+                      <height>20</height>
+                     </size>
+                    </property>
+                   </spacer>
+                  </item>
+                 </layout>
+                </item>
+               </layout>
+              </item>
+             </layout>
+            </widget>
            </item>
            <item>
             <spacer name="verticalSpacer_5">
@@ -2961,102 +2948,6 @@
  <resources/>
  <connections>
   <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_4</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>69</x>
-     <y>122</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_3</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>59</x>
-     <y>91</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyHostName</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>291</x>
-     <y>124</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_5</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>44</x>
-     <y>152</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyType</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>291</x>
-     <y>91</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyPort</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>364</x>
-     <y>154</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
    <sender>useCustomFileEditor</sender>
    <signal>toggled(bool)</signal>
    <receiver>customFileEditor</receiver>
@@ -3073,70 +2964,6 @@
    </hints>
   </connection>
   <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_7</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>67</x>
-     <y>212</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>label_6</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>68</x>
-     <y>182</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyPassword</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>364</x>
-     <y>214</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>useProxyServer</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>proxyUserName</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>249</x>
-     <y>59</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>364</x>
-     <y>184</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
    <sender>useCustomFileEditor</sender>
    <signal>toggled(bool)</signal>
    <receiver>customEditorLabel</receiver>
@@ -3185,22 +3012,6 @@
    </hints>
   </connection>
   <connection>
-   <sender>editor_highlightCurrentLine</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>editor_label_cl_color</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>184</x>
-     <y>86</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>515</x>
-     <y>86</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
    <sender>editor_codeCompletion</sender>
    <signal>toggled(bool)</signal>
    <receiver>editor_spinbox_ac_threshold</receiver>
@@ -3313,70 +3124,6 @@
    </hints>
   </connection>
   <connection>
-   <sender>editor_longWindowTitle</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>editor_lbl_min_tab_width</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>145</x>
-     <y>72</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>343</x>
-     <y>72</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>editor_longWindowTitle</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>editor_notebook_tab_width_max</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>145</x>
-     <y>72</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>437</x>
-     <y>72</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>editor_longWindowTitle</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>editor_lbl_max_tab_width</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>145</x>
-     <y>72</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>439</x>
-     <y>72</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>editor_longWindowTitle</sender>
-   <signal>toggled(bool)</signal>
-   <receiver>editor_notebook_tab_width_min</receiver>
-   <slot>setEnabled(bool)</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>145</x>
-     <y>72</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>393</x>
-     <y>72</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
    <sender>editor_checkbox_ac_keywords</sender>
    <signal>toggled(bool)</signal>
    <receiver>editor_checkbox_ac_builtins</receiver>
--- a/libgui/src/shortcut-manager.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/shortcut-manager.cc	Sun May 16 09:44:35 2021 +0200
@@ -75,11 +75,7 @@
         if (key == Qt::Key_unknown || key == 0)
           return;
 
-#if defined (HAVE_QGUIAPPLICATION)
         Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers (); //e->modifiers ();
-#else
-        Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers (); //e->modifiers ();
-#endif
 
         if (m_shift_modifier || (modifiers & Qt::ShiftModifier))
           key += Qt::SHIFT;
@@ -168,6 +164,11 @@
     init (tr ("Continue"), sc_main_debug_continue);
     init (tr ("Quit Debug Mode"), sc_main_debug_quit);
 
+    // tools
+    init (tr ("Start/Stop Profiler Session"), sc_main_tools_start_profiler);
+    init (tr ("Resume Profiler Session"), sc_main_tools_resume_profiler);
+    init (tr ("Show Profile Data"), sc_main_tools_show_profiler);
+
     // window
     init (tr ("Show Command Window"), sc_main_window_show_command);
     init (tr ("Show Command History"), sc_main_window_show_history);
@@ -304,6 +305,7 @@
     init (tr ("Go to Homepage"), sc_doc_go_home);
     init (tr ("Go Back one Page"), sc_doc_go_back);
     init (tr ("Go Forward one Page"), sc_doc_go_next);
+    init (tr ("Bookmark this Page"), sc_doc_bookmark);
   }
 
   // write one or all actual shortcut set(s) into a settings file
@@ -335,8 +337,18 @@
     settings->sync ();      // sync the settings file
   }
 
-  void shortcut_manager::set_shortcut (QAction *action, const sc_pref& scpref)
+  void shortcut_manager::set_shortcut (QAction *action, const sc_pref& scpref,
+                                       bool enable)
   {
+    if (! enable)
+      {
+        // Disable => remove existing shortcut from the action
+        action->setShortcut (QKeySequence ());
+        return;
+      }
+
+    // Enable: Is the given key known? If yes, get the value from the
+    //         settings file and set it to the action
     int index;
 
     index = m_action_hash[scpref.key] - 1;
@@ -372,11 +384,7 @@
     m_dialog = nullptr;
     m_level_hash.clear ();
 
-#if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE)
     tree_view->header ()->setSectionResizeMode (QHeaderView::ResizeToContents);
-#else
-    tree_view->header ()->setResizeMode (QHeaderView::ResizeToContents);
-#endif
 
     QTreeWidgetItem *main = new QTreeWidgetItem (tree_view);
     main->setText (0, tr ("Global"));
@@ -387,6 +395,8 @@
     main_edit->setText (0, tr ("Edit Menu"));
     QTreeWidgetItem *main_debug = new QTreeWidgetItem (main);
     main_debug->setText (0, tr ("Debug Menu"));
+    QTreeWidgetItem *main_tools = new QTreeWidgetItem (main);
+    main_tools->setText (0, tr ("Tools Menu"));
     QTreeWidgetItem *main_window = new QTreeWidgetItem (main);
     main_window->setText (0, tr ("Window Menu"));
     QTreeWidgetItem *main_help = new QTreeWidgetItem (main);
@@ -405,6 +415,7 @@
     m_level_hash[sc_main_file]   = main_file;
     m_level_hash[sc_main_edit]   = main_edit;
     m_level_hash[sc_main_debug]   = main_debug;
+    m_level_hash[sc_main_tools]   = main_tools;
     m_level_hash[sc_main_window]   = main_window;
     m_level_hash[sc_main_help]   = main_help;
     m_level_hash[sc_main_news]   = main_news;
@@ -445,8 +456,8 @@
 
     m_level_hash[sc_doc] = doc_browser;
 
-    connect (tree_view, SIGNAL (itemDoubleClicked (QTreeWidgetItem*, int)),
-             this, SLOT (handle_double_clicked (QTreeWidgetItem*, int)));
+    connect (tree_view, &QTreeWidget::itemDoubleClicked,
+             this, &shortcut_manager::handle_double_clicked);
 
     for (int i = 0; i < m_sc.count (); i++)
       {
@@ -671,8 +682,7 @@
         shift->setStyleSheet
           ("QCheckBox::indicator { subcontrol-position: left top; }");
 
-        connect (direct, SIGNAL (clicked (bool)),
-                 shift, SLOT (setEnabled (bool)));
+        connect (direct, &QCheckBox::clicked, shift, &QCheckBox::setEnabled);
 
         direct->setCheckState (Qt::Checked);
 
@@ -697,8 +707,8 @@
 
         QPushButton *set_default = new QPushButton (tr ("Set to default"));
         grid->addWidget (set_default, 0, 2);
-        connect (set_default, SIGNAL (clicked ()),
-                 this, SLOT (shortcut_dialog_set_default ()));
+        connect (set_default, &QPushButton::clicked,
+                 this, &shortcut_manager::shortcut_dialog_set_default);
 
         box->addLayout (grid);
 
@@ -709,18 +719,20 @@
         QList<QAbstractButton *> buttons = button_box->buttons ();
         for (int i = 0; i < buttons.count (); i++)
           buttons.at (i)->setShortcut (QKeySequence ());
-        connect (button_box, SIGNAL (accepted ()), m_dialog, SLOT (accept ()));
-        connect (button_box, SIGNAL (rejected ()), m_dialog, SLOT (reject ()));
+        connect (button_box, &QDialogButtonBox::accepted,
+                 m_dialog, &QDialog::accept);
+        connect (button_box, &QDialogButtonBox::rejected,
+                 m_dialog, &QDialog::reject);
         box->addWidget (button_box);
 
         m_dialog->setLayout (box);
 
-        connect (direct, SIGNAL (stateChanged (int)),
-                 m_edit_actual, SLOT (handle_direct_shortcut (int)));
-        connect (shift, SIGNAL (stateChanged (int)),
-                 m_edit_actual, SLOT (handle_shift_modifier (int)));
-        connect (m_dialog, SIGNAL (finished (int)),
-                 this, SLOT (shortcut_dialog_finished (int)));
+        connect (direct, &QCheckBox::stateChanged,
+                 m_edit_actual, &enter_shortcut::handle_direct_shortcut);
+        connect (shift, &QCheckBox::stateChanged,
+                 m_edit_actual, &enter_shortcut::handle_shift_modifier);
+        connect (m_dialog, &QDialog::finished,
+                 this, &shortcut_manager::shortcut_dialog_finished);
 
       }
 
--- a/libgui/src/shortcut-manager.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/shortcut-manager.h	Sun May 16 09:44:35 2021 +0200
@@ -90,7 +90,7 @@
 
     void write_shortcuts (gui_settings *settings, bool closing);
 
-    void set_shortcut (QAction *action, const sc_pref& scpref);
+    void set_shortcut (QAction *action, const sc_pref& scpref, bool enable = true);
 
     void shortcut (QShortcut *sc, const sc_pref& scpref);
 
--- a/libgui/src/tab-bar.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/tab-bar.cc	Sun May 16 09:44:35 2021 +0200
@@ -34,13 +34,17 @@
 
 namespace octave
 {
+  //
+  // Reimplemented QTabbar
+  //
+
   tab_bar::tab_bar (QWidget *p)
     : QTabBar (p), m_context_menu (new QMenu (this))
   { }
 
-  tab_bar::~tab_bar (void)
+  void tab_bar::set_rotated (int rotated)
   {
-    delete m_context_menu;
+    m_rotated = rotated;
   }
 
   // slots for tab navigation
@@ -56,16 +60,12 @@
 
   void tab_bar::move_tab_left (void)
   {
-#if defined (HAVE_QTABWIDGET_SETMOVABLE)
     switch_tab (-1, true);
-#endif
   }
 
   void tab_bar::move_tab_right (void)
   {
-#if defined (HAVE_QTABWIDGET_SETMOVABLE)
     switch_tab (1, true);
-#endif
   }
 
   void tab_bar::switch_tab (int direction, bool movetab)
@@ -83,11 +83,9 @@
 
     if (movetab)
       {
-#if defined (HAVE_QTABWIDGET_SETMOVABLE)
         moveTab (old_pos, new_pos);
         setCurrentIndex (old_pos);
         setCurrentIndex (new_pos);
-#endif
       }
     else
       setCurrentIndex (new_pos);
@@ -130,6 +128,52 @@
     setCurrentIndex (tab_with_focus);
   }
 
+  // The following two functions are reimplemented for allowing rotated
+  // tabs and are based on this answer on stack overflow:
+  // https://stackoverflow.com/a/50579369
+
+  // Reimplemented size hint allowing rotated tabs
+  QSize tab_bar::tabSizeHint (int idx) const
+  {
+    QSize s = QTabBar::tabSizeHint (idx);
+    if (m_rotated)
+      s.transpose();
+
+    return s;
+  }
+
+  // Reimplemented paint event allowing rotated tabs
+  void tab_bar::paintEvent(QPaintEvent *e)
+  {
+    // Just process the original event if not rotated
+    if (! m_rotated)
+      return QTabBar::paintEvent (e);
+
+    // Process the event for rotated tabs
+    QStylePainter painter (this);
+    QStyleOptionTab opt;
+
+    for (int idx = 0; idx < count(); idx++)
+      {
+        initStyleOption (&opt, idx);
+        painter.drawControl (QStyle::CE_TabBarTabShape, opt);
+        painter.save ();
+
+        QSize s = opt.rect.size();
+        s.transpose();
+        QRect rect (QPoint (), s);
+        rect.moveCenter (opt.rect.center ());
+        opt.rect = rect;
+
+        QPoint p = tabRect (idx).center ();
+        painter.translate (p);
+        painter.rotate (-m_rotated*90);
+        painter.translate (-p);
+        painter.drawControl (QStyle::CE_TabBarTabLabel, opt);
+        painter.restore ();
+      }
+  }
+
   // Reimplement mouse event for filtering out the desired mouse clicks
   void tab_bar::mousePressEvent (QMouseEvent *me)
   {
@@ -175,7 +219,23 @@
           {
             // Right click, show context menu
             setCurrentIndex (clicked_idx);
-            if (! m_context_menu->exec (click_pos))
+
+            // Fill context menu with actions for selecting current tabs
+            m_ctx_actions = m_context_menu->actions (); // Copy of basic actions
+            QMenu ctx_menu;                             // The menu actually used
+            connect (&ctx_menu, &QMenu::triggered,
+                     this, &tab_bar::ctx_menu_activated);
+
+            for (int i = count () - 1; i >= 0; i--)
+              {
+                // Prepend an action for each tab
+                QAction* a = new QAction (tabIcon (i), tabText (i), &ctx_menu);
+                m_ctx_actions.prepend (a);
+              }
+            // Add all actions to our menu
+            ctx_menu.insertActions (nullptr, m_ctx_actions);
+
+            if (! ctx_menu.exec (click_pos))
               {
                 // No action selected, back to previous tab
                 setCurrentIndex (current_idx);
@@ -211,4 +271,16 @@
         QTabBar::mousePressEvent (me);
       }
   }
+
+  // Slot if a menu entry in the context menu is activated
+  void tab_bar::ctx_menu_activated (QAction *a)
+  {
+    // If the index of the activated action is in the range of
+    // the current tabs, set the related current tab. The basic actions
+    // are handled by the editor
+    int i = m_ctx_actions.indexOf (a);
+    if ((i > -1) && (i < count ()))
+      setCurrentIndex (i);
+  }
+
 }
--- a/libgui/src/tab-bar.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/tab-bar.h	Sun May 16 09:44:35 2021 +0200
@@ -31,11 +31,15 @@
 
 #include <QMenu>
 #include <QMouseEvent>
+#include <QSize>
+#include <QStyleOptionTab>
+#include <QStylePainter>
 #include <QTabBar>
 
 namespace octave
 {
-  // Subclassed QTabBar for usable tab-bar and reimplemented mouse event
+  // Subclassed QTabBar for usable tab-bar, rotated tabs and
+  // reimplemented mouse event
 
   class tab_bar : public QTabBar
   {
@@ -45,9 +49,11 @@
 
     tab_bar (QWidget *p);
 
-    ~tab_bar (void);
+    ~tab_bar (void) = default;
 
+    void set_rotated (int rotated);
     QMenu *get_context_menu (void) { return m_context_menu; };
+    QSize tabSizeHint (int idx) const;
 
   signals:
 
@@ -61,15 +67,22 @@
     void move_tab_right (void);
     void sort_tabs_alph (void);
 
+  private slots:
+
+    void ctx_menu_activated (QAction *a);
+
   protected:
 
+    void paintEvent(QPaintEvent *e);
     void mousePressEvent(QMouseEvent *event);
 
   private:
 
-    QMenu *m_context_menu;
+    void switch_tab (int direction, bool movetab = false);
 
-    void switch_tab (int direction, bool movetab = false);
+    QMenu *m_context_menu;
+    QList <QAction *> m_ctx_actions;
+    int m_rotated;
   };
 }
 
--- a/libgui/src/terminal-dock-widget.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/terminal-dock-widget.cc	Sun May 16 09:44:35 2021 +0200
@@ -29,23 +29,32 @@
 
 #include <QDesktopWidget>
 
+// This header is only needed for the new terminal widget.
+#include "command-widget.h"
+
+// This header is only needed for the old terminal widget.
+#include "QTerminal.h"
+
 #include "gui-preferences-cs.h"
 #include "gui-preferences-global.h"
+
 #include "octave-qobject.h"
 #include "terminal-dock-widget.h"
 
-#include "quit.h"
-#include "signal-wrappers.h"
-
-#include "sighandlers.h"
-
 namespace octave
 {
   terminal_dock_widget::terminal_dock_widget (QWidget *p,
                                               base_qobject& oct_qobj)
     : octave_dock_widget ("TerminalDockWidget", p, oct_qobj),
-      m_terminal (QTerminal::create (oct_qobj, p))
+      m_experimental_terminal_widget (oct_qobj.experimental_terminal_widget ())
   {
+    // FIXME: we could do this in a better way, but improving it doesn't
+    // matter much if we will eventually be removing the old terminal.
+    if (m_experimental_terminal_widget)
+      m_terminal = new command_widget (oct_qobj, this);
+    else
+      m_terminal = QTerminal::create (oct_qobj, this, p);
+
     m_terminal->setObjectName ("OctaveTerminal");
     m_terminal->setFocusPolicy (Qt::StrongFocus);
 
@@ -55,12 +64,40 @@
     setWidget (m_terminal);
     setFocusProxy (m_terminal);
 
-    connect (m_terminal, SIGNAL (interrupt_signal (void)),
-             this, SLOT (terminal_interrupt (void)));
+    // FIXME: The new terminal needs to be a more specific type than
+    // QWidget for this to work properly and to be able to use the new
+    // signal/slot connection style.  Probably the new terminal widget
+    // should be derived from QTerminal.
+    connect (this, SIGNAL (settings_changed (const gui_settings *)),
+             m_terminal, SLOT (notice_settings (const gui_settings *)));
+
+    if (m_experimental_terminal_widget)
+      {
+        // Any interpreter_event signal from the terminal widget is
+        // handled the same as for the parent terminal dock widget.
+
+        connect (m_terminal, SIGNAL (interpreter_event (const fcn_callback&)),
+                 this, SIGNAL (interpreter_event (const fcn_callback&)));
 
-    // Connect the visibility signal to the terminal for dis-/enabling timers
-    connect (this, SIGNAL (visibilityChanged (bool)),
-             m_terminal, SLOT (handle_visibility_changed (bool)));
+        connect (m_terminal, SIGNAL (interpreter_event (const meth_callback&)),
+                 this, SIGNAL (interpreter_event (const meth_callback&)));
+      }
+    else
+      {
+        // FIXME: As with the settings_changed signal above, the
+        // following connections won't work with the new signal/slot
+        // connection style because m_terminal is a pointer to QWidget
+        // instead of QTerminal.
+
+        // Connect the interrupt signal (emitted by Ctrl-C)
+        connect (m_terminal, SIGNAL (interrupt_signal (void)),
+                 &oct_qobj, SLOT (interpreter_interrupt (void)));
+
+        // Connect the visibility signal to the terminal for
+        // dis-/enabling timers.
+        connect (this, SIGNAL (visibilityChanged (bool)),
+                 m_terminal, SLOT (handle_visibility_changed (bool)));
+      }
 
     // Chose a reasonable size at startup in order to avoid truncated
     // startup messages
@@ -91,31 +128,27 @@
     setGeometry (0, 0, win_x, win_y);
   }
 
-  terminal_dock_widget::~terminal_dock_widget (void)
-  {
-    delete m_terminal;
-  }
-
   bool terminal_dock_widget::has_focus (void) const
   {
     QWidget *w = widget ();
-
     return w->hasFocus ();
   }
 
-  void terminal_dock_widget::terminal_interrupt (void)
+  void terminal_dock_widget::notice_settings (const gui_settings *settings)
   {
-    // FIXME: Protect with mutex?
-
-    octave_signal_caught = 1;
-    octave_interrupt_state++;
+    emit settings_changed (settings);
+  }
 
-    // Send SIGINT to all other processes in our process group.
-    // This is needed to interrupt calls to system (), for example.
+  void terminal_dock_widget::interpreter_output (const QString& msg)
+  {
+    if (m_experimental_terminal_widget)
+      emit interpreter_output_signal (msg);
+  }
 
-    int sigint;
-    octave_get_sig_number ("SIGINT", &sigint);
+  void terminal_dock_widget::update_prompt (const QString& prompt)
+  {
+    if (m_experimental_terminal_widget)
+      emit update_prompt_signal (prompt);
+  }
 
-    octave_kill_wrapper (0, sigint);
-  }
 }
--- a/libgui/src/terminal-dock-widget.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/terminal-dock-widget.h	Sun May 16 09:44:35 2021 +0200
@@ -28,8 +28,6 @@
 
 #include <QString>
 
-#include "QTerminal.h"
-
 #include "octave-dock-widget.h"
 
 namespace octave
@@ -44,21 +42,38 @@
 
     terminal_dock_widget (QWidget *parent, base_qobject& oct_qobj);
 
-    ~terminal_dock_widget (void);
+    ~terminal_dock_widget (void) = default;
 
     bool has_focus (void) const;
 
   signals:
 
-    void interrupt_signal (void);
+    void settings_changed (const gui_settings *settings);
+
+    // Note: UPDATE_PROMPT_SIGNAL and INTERPRETER_OUTPUT_SIGNAL are
+    // currently only used by the new experimental terminal widget.
+
+    void update_prompt_signal (const QString&);
+
+    void interpreter_output_signal (const QString&);
 
-  protected slots:
+  public slots:
+
+    void notice_settings (const gui_settings *settings);
 
-    void terminal_interrupt (void);
+    // Note: INTERPRETER_OUTPUT and UPDATE_PROMPT are currently only
+    // used by the new experimental terminal widget.
+
+    void interpreter_output (const QString&);
+
+    void update_prompt (const QString&);
 
   private:
 
-    QTerminal *m_terminal;
+    bool m_experimental_terminal_widget;
+
+    // FIXME!!!  Maybe my_term should just be derived from QTerminal?
+    QWidget *m_terminal;
   };
 }
 
--- a/libgui/src/variable-editor-model.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/variable-editor-model.cc	Sun May 16 09:44:35 2021 +0200
@@ -954,14 +954,14 @@
   {
     update_description ();
 
-    connect (this, SIGNAL (user_error_signal (const QString&, const QString&)),
-             this, SLOT (user_error (const QString&, const QString&)));
+    connect (this, &variable_editor_model::user_error_signal,
+             this, &variable_editor_model::user_error);
 
-    connect (this, SIGNAL (update_data_signal (const octave_value&)),
-             this, SLOT (update_data (const octave_value&)));
+    connect (this, &variable_editor_model::update_data_signal,
+             this, &variable_editor_model::update_data);
 
-    connect (this, SIGNAL (data_error_signal (const QString&)),
-             this, SLOT (data_error (const QString&)));
+    connect (this, &variable_editor_model::data_error_signal,
+             this, &variable_editor_model::data_error);
 
     if (is_editable ())
       {
@@ -987,12 +987,7 @@
   variable_editor_model::setData (const QModelIndex& idx,
                                   const QVariant& v_user_input, int role)
   {
-#if defined (QVARIANT_CANCONVERT_ACCEPTS_QMETATYPE_TYPE)
-    QMetaType::Type string_type = QMetaType::QString;
-#else
-    QVariant::Type string_type = QVariant::String;
-#endif
-    if (role != Qt::EditRole || ! v_user_input.canConvert (string_type)
+    if (role != Qt::EditRole || ! v_user_input.canConvert (QMetaType::QString)
         || ! idx.isValid ())
       return false;
 
@@ -1029,7 +1024,7 @@
     std::string expr = os.str ();
 
     emit interpreter_event
-      ([this, nm, expr, idx] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1178,7 +1173,7 @@
     std::string expr = expr_arg.toStdString ();
 
     emit interpreter_event
-      ([this, expr] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER THREAD
 
@@ -1250,7 +1245,7 @@
   variable_editor_model::update_data_cache (void)
   {
     emit interpreter_event
-      ([this] (interpreter& interp)
+      ([=] (interpreter& interp)
        {
          // INTERPRETER_THREAD
 
--- a/libgui/src/variable-editor.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/variable-editor.cc	Sun May 16 09:44:35 2021 +0200
@@ -48,11 +48,15 @@
 #include <QToolButton>
 #include <QVBoxLayout>
 
+#include "builtin-defun-decls.h"
 #include "dw-main-window.h"
 #include "gui-preferences-cs.h"
 #include "gui-preferences-global.h"
+#include "gui-preferences-sc.h"
 #include "gui-preferences-ve.h"
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
+#include "ovl.h"
 #include "qt-utils.h"
 #include "shortcut-manager.h"
 #include "variable-editor-model.h"
@@ -91,16 +95,13 @@
     setFocusPolicy (Qt::StrongFocus);
     setAttribute (Qt::WA_DeleteOnClose);
 
-    connect (m_dock_action, SIGNAL (triggered (bool)),
-             this, SLOT (change_floating (bool)));
-    connect (m_close_action, SIGNAL (triggered (bool)),
-             this, SLOT (change_existence (bool)));
-    connect (this, SIGNAL (topLevelChanged(bool)),
-             this, SLOT (toplevel_change (bool)));
-    connect (p, SIGNAL (visibilityChanged (bool)),
-             this, SLOT (setVisible (bool)));
+    connect (m_dock_action, &QAction::triggered,
+             this, &variable_dock_widget::change_floating);
+    connect (m_close_action, &QAction::triggered,
+             this, &variable_dock_widget::change_existence);
+    connect (this, &variable_dock_widget::topLevelChanged,
+             this, &variable_dock_widget::toplevel_change);
 
-#if defined (HAVE_QGUIAPPLICATION)
 #define DOCKED_FULLSCREEN_BUTTON_TOOLTIP "Fullscreen undock"
 #define UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP "Fullscreen"
     // Add a fullscreen button
@@ -122,15 +123,14 @@
     QString css_button = QString ("QToolButton {background: transparent; border: 0px;}");
     fullscreen_button->setStyleSheet (css_button);
 
-    connect (m_fullscreen_action, SIGNAL (triggered ()),
-             this, SLOT (change_fullscreen ()));
+    connect (m_fullscreen_action, &QAction::triggered,
+             this, &variable_dock_widget::change_fullscreen);
 
     int index = -1;
     QToolButton *first = m_title_widget->findChild<QToolButton *> ();
     if (first != nullptr)
       index = h_layout->indexOf (first);
     h_layout->insertWidget (index, fullscreen_button);
-#endif
 
     // Custom title bars cause loss of decorations, add a frame
     m_frame = new QFrame (this);
@@ -142,7 +142,6 @@
   void
   variable_dock_widget::change_floating (bool)
   {
-#if defined (HAVE_QGUIAPPLICATION)
     if (isFloating ())
       {
         if (m_full_screen)
@@ -156,7 +155,6 @@
       }
     else
       m_fullscreen_action->setToolTip (tr (UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP));
-#endif
 
     setFloating (! isFloating ());
   }
@@ -206,7 +204,6 @@
   void
   variable_dock_widget::change_fullscreen (void)
   {
-#if defined (HAVE_QGUIAPPLICATION)
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
 
     if (! m_full_screen)
@@ -246,7 +243,6 @@
       }
 #undef DOCKED_FULLSCREEN_BUTTON_TOOLTIP
 #undef UNDOCKED_FULLSCREEN_BUTTON_TOOLTIP
-#endif
   }
 
   void
@@ -443,12 +439,55 @@
       }
   }
 
+  // Slot for saving a variable into a file
   void
-  variable_editor_stack::save (void)
+  variable_editor_stack::save (const QString& format)
   {
     if (! hasFocus ())
       return;
 
+    // Check whether a format for saving the variable is given
+    QString format_string;
+    if (! format.isEmpty ())
+      {
+        format_string = "-" + format;
+        do_save (format_string, format_string);
+        return;
+      }
+
+    // No format given, test save default options
+    emit interpreter_event
+      ([=] (interpreter& interp)
+        {
+          // INTERPRETER THREAD
+
+          octave_value_list argout
+            = Fsave_default_options (interp, octave_value_list (), 1);
+          QString save_opts = QString::fromStdString (argout(0).string_value ());
+
+          connect (this, &variable_editor_stack::do_save_signal,
+                   this, &variable_editor_stack::do_save);
+
+          emit (do_save_signal (format_string, save_opts));
+
+        });
+  }
+
+
+  // Perform saving the variable after desired format is determined
+  void
+  variable_editor_stack::do_save (const QString& format, const QString& save_opts)
+  {
+    QString file_ext = "txt";
+    for (int i = 0; i < ve_save_formats_ext.length ()/2; i++)
+      {
+        if (save_opts.contains (ve_save_formats_ext.at (2*i), Qt::CaseInsensitive))
+          {
+            file_ext = ve_save_formats_ext.at (2*i + 1);
+            break;
+          }
+      }
+
     // FIXME: Remove, if for all common KDE versions (bug #54607) is resolved.
     int opts = 0;  // No options by default.
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
@@ -460,17 +499,27 @@
     QString file
       = QFileDialog::getSaveFileName (this,
                                       tr ("Save Variable %1 As").arg (name),
-    // FIXME: Should determine extension from save_default_options
-                                      QString ("./%1.txt").arg (name),
+                                      QString ("./%1.%2").arg (name).arg (file_ext),
                                       0, 0, QFileDialog::Option (opts));
 
-    // FIXME: Type? binary, float-binary, ascii, text, hdf5, matlab format?
-    // FIXME: Call octave_value::save_* directly?
+    if (file.isEmpty ())
+      return; // No file selected: Just return
+
+    // Let the interpreter thread do the saving
+    emit interpreter_event
+      ([=] (interpreter& interp)
+        {
+          // INTERPRETER THREAD
 
-    if (! file.isEmpty ())
-      emit command_signal (QString ("save (\"%1\", \"%2\");")
-                           .arg (file)
-                           .arg (name));
+          octave_value_list ovl;
+          std::list<octave_value> str_list
+                              = {octave_value (file.toStdString ()),
+                                 octave_value (name.toStdString ())};
+          if (! format.isEmpty ())
+            str_list.push_front (octave_value (format.toStdString ()));
+
+          Fsave (interp, octave_value_list (str_list));
+        });
   }
 
 
@@ -490,11 +539,7 @@
     setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel);
     setVerticalScrollMode (QAbstractItemView::ScrollPerPixel);
 
-#if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE)
     verticalHeader ()->setSectionResizeMode (QHeaderView::Interactive);
-#else
-    verticalHeader ()->setResizeMode (QHeaderView::Interactive);
-#endif
   }
 
   void
@@ -502,11 +547,7 @@
   {
     QTableView::setModel (model);
 
-#if defined (HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE)
     horizontalHeader ()->setSectionResizeMode (QHeaderView::Interactive);
-#else
-    horizontalHeader ()->setResizeMode (QHeaderView::Interactive);
-#endif
 
     m_var_model = parent ()->findChild<variable_editor_model *> ();
 
@@ -602,29 +643,29 @@
 
     menu->addAction (rmgr.icon ("edit-cut"),
                      tr ("Cut") + qualifier_string,
-                     this, SLOT (cutClipboard ()));
+                     this, &variable_editor_view::cutClipboard);
 
     menu->addAction (rmgr.icon ("edit-copy"),
                      tr ("Copy") + qualifier_string,
-                     this, SLOT (copyClipboard ()));
+                     this, &variable_editor_view::copyClipboard);
 
     menu->addAction (rmgr.icon ("edit-paste"),
                      tr ("Paste"),
-                     this, SLOT (pasteClipboard ()));
+                     this, &variable_editor_view::pasteClipboard);
 
     menu->addSeparator ();
 
     menu->addAction (rmgr.icon ("edit-delete"),
                      tr ("Clear") + qualifier_string,
-                     this, SLOT (clearContent ()));
+                     this, &variable_editor_view::clearContent);
 
     menu->addAction (rmgr.icon ("edit-delete"),
                      tr ("Delete") + qualifier_string,
-                     this, SLOT (delete_selected ()));
+                     this, &variable_editor_view::delete_selected);
 
     menu->addAction (rmgr.icon ("document-new"),
                      tr ("Variable from Selection"),
-                     this, SLOT (createVariable ()));
+                     this, &variable_editor_view::createVariable);
   }
 
   void
@@ -641,7 +682,8 @@
         // FIXME: addAction for sort?
         // FIXME: Add icon for transpose.
 
-        menu->addAction (tr ("Transpose"), this, SLOT (transposeContent ()));
+        menu->addAction (tr ("Transpose"),
+                         this, &variable_editor_view::transposeContent);
 
         QItemSelectionModel *sel = selectionModel ();
 
@@ -1105,9 +1147,6 @@
     m_main->setCentralWidget (central_mdiarea);
 
     setWidget (m_main);
-
-    connect (this, SIGNAL (command_signal (const QString&)),
-             p, SLOT (execute_command_in_terminal (const QString&)));
   }
 
   void variable_editor::focusInEvent (QFocusEvent *ev)
@@ -1144,27 +1183,16 @@
       }
   }
 
-  // Add an action to a menu or the widget itself.
-
-  QAction*
-  variable_editor::add_action (QMenu *menu, const QIcon& icon,
-                               const QString& text,
-                               const char *member)
+  variable_editor::~variable_editor (void)
   {
-    QAction *a;
+    // FIXME: Maybe toolbar actions could be handled with signals and
+    // slots so that deleting the toolbar here would disconnect all
+    // toolbar actions and any other slots that might try to access the
+    // toolbar would work properly (I'm looking at you,
+    // handle_focus_change).
 
-    if (menu)
-      a = menu->addAction (icon, text, this, member);
-    else
-      {
-        a = new QAction (this);
-        connect (a, SIGNAL (triggered ()), this, member);
-      }
-
-    addAction (a);  // important for shortcut context
-    a->setShortcutContext (Qt::WidgetWithChildrenShortcut);
-
-    return a;
+    delete m_tool_bar;
+    m_tool_bar = nullptr;
   }
 
   void
@@ -1207,18 +1235,26 @@
     page->setObjectName (name);
     m_main->addDockWidget (Qt::LeftDockWidgetArea, page);
 
-    connect (QApplication::instance(), SIGNAL (focusChanged (QWidget *, QWidget *)),
-             page, SLOT (handle_focus_change (QWidget *, QWidget *)));
-    connect (page, SIGNAL (destroyed (QObject *)),
-             this, SLOT (variable_destroyed (QObject *)));
-    connect (page, SIGNAL (variable_focused_signal (const QString&)),
-             this, SLOT (variable_focused (const QString&)));
-// See  Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
+    // The old-style signal/slot connection appears to be needed here to
+    // prevent a crash when closing a variable_dock_widget object.
+    connect (qApp, SIGNAL (focusChanged (QWidget*, QWidget*)),
+             page, SLOT (handle_focus_change (QWidget*, QWidget*)));
+
+    connect (this, &variable_editor::visibilityChanged,
+             page, &variable_dock_widget::setVisible);
+
+    // Notify the variable editor for page actions.
+    connect (page, &variable_dock_widget::destroyed,
+             this, &variable_editor::variable_destroyed);
+    connect (page, &variable_dock_widget::variable_focused_signal,
+             this, &variable_editor::variable_focused);
+
+    // See  Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
 #if (QT_VERSION >= 0x050302) && (QT_VERSION <= QTBUG_44813_FIX_VERSION)
     connect (page, SIGNAL (queue_unfloat_float ()),
              page, SLOT (unfloat_float ()), Qt::QueuedConnection);
     connect (page, SIGNAL (queue_float ()),
-             page, SLOT (refloat ()), Qt::QueuedConnection);
+             page, SIGNAL (refloat ()), Qt::QueuedConnection);
 #endif
 
     variable_editor_stack *stack
@@ -1228,14 +1264,20 @@
     page->setWidget (stack);
     page->setFocusProxy (stack);
 
-    connect (stack, SIGNAL (command_signal (const QString&)),
-             this, SIGNAL (command_signal (const QString&)));
-    connect (stack, SIGNAL (edit_variable_signal (const QString&, const octave_value&)),
-             this, SLOT (edit_variable (const QString&, const octave_value&)));
-    connect (this, SIGNAL (level_up_signal ()),
-             stack, SLOT (levelUp ()));
-    connect (this, SIGNAL (save_signal ()),
-             stack, SLOT (save ()));
+    // Any interpreter_event signal from a variable_editor_stack object is
+    // handled the same as for the parent variable_editor object.
+    connect (stack, QOverload<const fcn_callback&>::of (&variable_editor_stack::interpreter_event),
+             this, QOverload<const fcn_callback&>::of (&variable_editor::interpreter_event));
+
+    connect (stack, QOverload<const meth_callback&>::of (&variable_editor_stack::interpreter_event),
+             this, QOverload<const meth_callback&>::of (&variable_editor::interpreter_event));
+
+    connect (stack, &variable_editor_stack::edit_variable_signal,
+             this, &variable_editor::edit_variable);
+    connect (this, &variable_editor::level_up_signal,
+             stack, &variable_editor_stack::levelUp);
+    connect (this, &variable_editor::save_signal,
+             stack, [=] () { stack->save (); });
 
     variable_editor_view *edit_view = stack->edit_view ();
 
@@ -1248,54 +1290,56 @@
 
     connect (m_plot_mapper, SIGNAL (mapped (const QString&)),
              edit_view, SLOT (selected_command_requested (const QString&)));
+    connect (m_save_mapper, SIGNAL (mapped (const QString&)),
+             stack, SLOT (save (const QString&)));
 
-    connect (edit_view, SIGNAL (command_signal (const QString&)),
-             this, SIGNAL (command_signal (const QString&)));
-    connect (this, SIGNAL (delete_selected_signal ()),
-             edit_view, SLOT (delete_selected ()));
-    connect (this, SIGNAL (clear_content_signal ()),
-             edit_view, SLOT (clearContent ()));
-    connect (this, SIGNAL (copy_clipboard_signal ()),
-             edit_view, SLOT (copyClipboard ()));
-    connect (this, SIGNAL (paste_clipboard_signal ()),
-             edit_view, SLOT (pasteClipboard ()));
+    connect (edit_view, &variable_editor_view::command_signal,
+             this, &variable_editor::command_signal);
+    connect (this, &variable_editor::delete_selected_signal,
+             edit_view, &variable_editor_view::delete_selected);
+    connect (this, &variable_editor::clear_content_signal,
+             edit_view, &variable_editor_view::clearContent);
+    connect (this, &variable_editor::copy_clipboard_signal,
+             edit_view, &variable_editor_view::copyClipboard);
+    connect (this, &variable_editor::paste_clipboard_signal,
+             edit_view, &variable_editor_view::pasteClipboard);
     connect (edit_view->horizontalHeader (),
-             SIGNAL (customContextMenuRequested (const QPoint&)),
-             edit_view, SLOT (createColumnMenu (const QPoint&)));
+             &QHeaderView::customContextMenuRequested,
+             edit_view, &variable_editor_view::createColumnMenu);
     connect (edit_view->verticalHeader (),
-             SIGNAL (customContextMenuRequested (const QPoint&)),
-             edit_view, SLOT (createRowMenu (const QPoint&)));
-    connect (edit_view, SIGNAL (customContextMenuRequested (const QPoint&)),
-             edit_view, SLOT (createContextMenu (const QPoint&)));
-    connect (edit_view->horizontalScrollBar (), SIGNAL (actionTriggered (int)),
-             edit_view, SLOT (handle_horizontal_scroll_action (int)));
-    connect (edit_view->verticalScrollBar (), SIGNAL (actionTriggered (int)),
-             edit_view, SLOT (handle_vertical_scroll_action (int)));
+             &QHeaderView::customContextMenuRequested,
+             edit_view, &variable_editor_view::createRowMenu);
+    connect (edit_view, &variable_editor_view::customContextMenuRequested,
+             edit_view, &variable_editor_view::createContextMenu);
+    connect (edit_view->horizontalScrollBar (), &QScrollBar::actionTriggered,
+             edit_view, &variable_editor_view::handle_horizontal_scroll_action);
+    connect (edit_view->verticalScrollBar (), &QScrollBar::actionTriggered,
+             edit_view, &variable_editor_view::handle_vertical_scroll_action);
 
     variable_editor_model *model =
       new variable_editor_model (name, val, stack);
 
-    connect (model, SIGNAL (edit_variable_signal (const QString&, const octave_value&)),
-             this, SLOT (edit_variable (const QString&, const octave_value&)));
-    connect (model, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
-             this, SLOT (callUpdate (const QModelIndex&, const QModelIndex&)));
-    connect (this, SIGNAL (refresh_signal ()),
-             model, SLOT (update_data_cache ()));
-    connect (model, SIGNAL (set_editable_signal (bool)),
-             stack, SLOT (set_editable (bool)));
+    connect (model, &variable_editor_model::edit_variable_signal,
+             this, &variable_editor::edit_variable);
+    connect (model, &variable_editor_model::dataChanged,
+             this, &variable_editor::callUpdate);
+    connect (this, &variable_editor::refresh_signal,
+             model, &variable_editor_model::update_data_cache);
+    connect (model, &variable_editor_model::set_editable_signal,
+             stack, &variable_editor_stack::set_editable);
 
     edit_view->setModel (model);
-    connect (edit_view, SIGNAL (doubleClicked (const QModelIndex&)),
-             model, SLOT (double_click (const QModelIndex&)));
+    connect (edit_view, &variable_editor_view::doubleClicked,
+             model, &variable_editor_model::double_click);
 
     // Any interpreter_event signal from a variable_editor_model object is
     // handled the same as for the parent variable_editor object.
 
-    connect (model, SIGNAL (interpreter_event (const fcn_callback&)),
-             this, SIGNAL (interpreter_event (const fcn_callback&)));
+    connect (model, QOverload<const fcn_callback&>::of (&variable_editor_model::interpreter_event),
+             this, QOverload<const fcn_callback&>::of (&variable_editor::interpreter_event));
 
-    connect (model, SIGNAL (interpreter_event (const meth_callback&)),
-             this, SIGNAL (interpreter_event (const meth_callback&)));
+    connect (model, QOverload<const meth_callback&>::of (&variable_editor_model::interpreter_event),
+             this, QOverload<const meth_callback&>::of (&variable_editor::interpreter_event));
 
     // Must supply a title for a QLabel to be created.  Calling set_title()
     // more than once will add more QLabels.  Could change octave_dock_widget
@@ -1305,6 +1349,9 @@
     if (page->titleBarWidget () != nullptr)
       {
         QLabel *existing_ql = page->titleBarWidget ()->findChild<QLabel *> ();
+
+        // FIXME: What was the intent here?  update_label_signal does
+        // not seem to exist now.
         connect (model, SIGNAL (update_label_signal (const QString&)),
                  existing_ql, SLOT (setText (const QString&)));
         existing_ql->setMargin (2);
@@ -1312,11 +1359,16 @@
 
     model->update_data (val);
 
-    QList<QTableView *> viewlist = findChildren<QTableView *> ();
-    if (viewlist.size () == 1)
-      m_tool_bar->setEnabled (true);
+    if (m_tool_bar)
+      {
+        QList<QTableView *> viewlist = findChildren<QTableView *> ();
+        if (viewlist.size () == 1 && m_tool_bar)
+          m_tool_bar->setEnabled (true);
+      }
 
-    m_main->parentWidget ()->show ();
+    make_window ();
+
+    show ();
     page->show ();
     page->raise ();
     page->activateWindow ();
@@ -1327,18 +1379,25 @@
   void
   variable_editor::tab_to_front (void)
   {
-    if (parent () != nullptr)
+    QWidget *parent = parentWidget ();
+
+    if (parent)
       {
-        QList<QTabBar *> barlist = main_win ()->findChildren<QTabBar *> ();
+        QList<QTabBar *> barlist = parent->findChildren<QTabBar *> ();
+
         QVariant this_value (reinterpret_cast<quintptr> (this));
 
         for (auto *tbar : barlist)
-          for (int i = 0; i < tbar->count (); i++)
-            if (tbar->tabData (i) == this_value)
+          {
+            for (int i = 0; i < tbar->count (); i++)
               {
-                tbar->setCurrentIndex (i);
-                return;
+                if (tbar->tabData (i) == this_value)
+                  {
+                    tbar->setCurrentIndex (i);
+                    return;
+                  }
               }
+          }
       }
   }
 
@@ -1388,18 +1447,11 @@
 
     m_add_font_height = fm.height ();
 
+    int mode = settings->value (ve_color_mode).toInt ();
+
     for (int i = 0; i < ve_colors_count; i++)
       {
-        // The default colors are given as color roles for
-        // the application's palette
-        QColor default_color = qApp->palette ().color
-                               (static_cast<QPalette::ColorRole> (ve_colors[i].def.toInt ()));
-        // FIXME: use value<QPalette::ColorRole> instead of static cast after
-        //        dropping support of Qt 5.4
-
-        QColor setting_color =
-          settings->value (ve_colors[i].key, default_color).value<QColor> ();
-
+        QColor setting_color = settings->color_value (ve_colors[i], mode);
         m_table_colors.replace (i, setting_color);
       }
 
@@ -1407,12 +1459,19 @@
 
     // Icon size in the toolbar.
 
-    int size_idx = settings->value (global_icon_size).toInt ();
-    size_idx = (size_idx > 0) - (size_idx < 0) + 1;  // Make valid index from 0 to 2
+    if (m_tool_bar)
+      {
+        int size_idx = settings->value (global_icon_size).toInt ();
+        size_idx = (size_idx > 0) - (size_idx < 0) + 1;  // Make valid index from 0 to 2
 
-    QStyle *st = style ();
-    int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
-    m_tool_bar->setIconSize (QSize (icon_size, icon_size));
+        QStyle *st = style ();
+        int icon_size = st->pixelMetric (global_icon_sizes[size_idx]);
+        m_tool_bar->setIconSize (QSize (icon_size, icon_size));
+      }
+
+    // Shortcuts (same as file editor)
+    shortcut_manager& scmgr = m_octave_qobj.get_shortcut_manager ();
+    scmgr.set_shortcut (m_save_action, sc_edit_file_save);
   }
 
   void
@@ -1433,10 +1492,13 @@
         m_focus_widget_vdw = nullptr;
       }
 
-    // If no variable pages remain, deactivate the tool bar.
-    QList<variable_dock_widget *> vdwlist = findChildren<variable_dock_widget *> ();
-    if (vdwlist.isEmpty ())
-      m_tool_bar->setEnabled (false);
+    if (m_tool_bar)
+      {
+        // If no variable pages remain, deactivate the tool bar.
+        QList<variable_dock_widget *> vdwlist = findChildren<variable_dock_widget *> ();
+        if (vdwlist.isEmpty ())
+          m_tool_bar->setEnabled (false);
+      }
 
     QFocusEvent ev (QEvent::FocusIn);
     focusInEvent (&ev);
@@ -1533,7 +1595,7 @@
     m_stylesheet = "";
 
     if (m_table_colors.length () > 0)
-      m_stylesheet += "QTableView::item{ foreground-color: "
+      m_stylesheet += "QTableView::item{ color: "
                       + m_table_colors[0].name () +" }";
 
     if (m_table_colors.length () > 1)
@@ -1601,13 +1663,35 @@
 
     resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
 
-    QAction *action;
-    action = add_tool_bar_button (rmgr.icon ("document-save"), tr ("Save"),
+    m_save_action = add_tool_bar_button (rmgr.icon ("document-save"), tr ("Save"),
                                   this, SLOT (save ()));
-    addAction (action);
-    action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
-    action->setShortcuts (QKeySequence::Save);
-    action->setStatusTip(tr("Save variable to a file"));
+    addAction (m_save_action);
+    m_save_action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
+    m_save_action->setStatusTip(tr("Save variable to a file"));
+
+    QAction *action = new QAction (rmgr.icon ("document-save-as"), tr ("Save in format ..."), m_tool_bar);
+
+    QToolButton *save_tool_button = new HoverToolButton (m_tool_bar);
+    save_tool_button->setDefaultAction (action);
+
+    save_tool_button->setText (tr ("Save in format ..."));
+    save_tool_button->setToolTip (tr("Save variable to a file in different format"));
+    save_tool_button->setIcon (rmgr.icon ("document-save-as"));
+    save_tool_button->setPopupMode (QToolButton::InstantPopup);
+
+    QMenu *save_menu = new ReturnFocusMenu (save_tool_button);
+    save_menu->setTitle (tr ("Save in format ..."));
+    save_menu->setSeparatorsCollapsible (false);
+
+    m_save_mapper = new QSignalMapper (save_menu);
+    for (int i = 0; i < ve_save_formats.length (); i++)
+      m_save_mapper->setMapping
+        (save_menu->addAction (ve_save_formats.at (i),
+                               m_save_mapper, SLOT (map ())),
+                               ve_save_formats.at (i));
+
+    save_tool_button->setMenu (save_menu);
+    m_tool_bar->addWidget (save_tool_button);
 
     m_tool_bar->addSeparator ();
 
@@ -1661,28 +1745,24 @@
     // that restores active window and focus before acting.
     QList<HoverToolButton *> hbuttonlist
       = m_tool_bar->findChildren<HoverToolButton *> (""
-#if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
                                                      , Qt::FindDirectChildrenOnly
-#endif
                                                     );
     for (int i = 0; i < hbuttonlist.size (); i++)
       {
-        connect (hbuttonlist.at (i), SIGNAL (hovered_signal ()),
-                 this, SLOT (record_hovered_focus_variable ()));
-        connect (hbuttonlist.at (i), SIGNAL (popup_shown_signal ()),
-                 this, SLOT (restore_hovered_focus_variable ()));
+        connect (hbuttonlist.at (i), &HoverToolButton::hovered_signal,
+                 this, &variable_editor::record_hovered_focus_variable);
+        connect (hbuttonlist.at (i), &HoverToolButton::popup_shown_signal,
+                 this, &variable_editor::restore_hovered_focus_variable);
       }
 
     QList<ReturnFocusToolButton *> rfbuttonlist
       = m_tool_bar->findChildren<ReturnFocusToolButton *> (""
-#if defined (QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS)
                                                            , Qt::FindDirectChildrenOnly
-#endif
                                                           );
     for (int i = 0; i < rfbuttonlist.size (); i++)
       {
-        connect (rfbuttonlist.at (i), SIGNAL (about_to_activate ()),
-                 this, SLOT (restore_hovered_focus_variable ()));
+        connect (rfbuttonlist.at (i), &ReturnFocusToolButton::about_to_activate,
+                 this, &variable_editor::restore_hovered_focus_variable);
       }
 
     // Same for QMenu
@@ -1690,8 +1770,8 @@
       = m_tool_bar->findChildren<ReturnFocusMenu *> ();
     for (int i = 0; i < menulist.size (); i++)
       {
-        connect (menulist.at (i), SIGNAL (about_to_activate ()),
-                 this, SLOT (restore_hovered_focus_variable ()));
+        connect (menulist.at (i), &ReturnFocusMenu::about_to_activate,
+                 this, &variable_editor::restore_hovered_focus_variable);
       }
 
     m_tool_bar->setAttribute(Qt::WA_ShowWithoutActivating);
@@ -1701,4 +1781,5 @@
 
     m_tool_bar->setEnabled (false);
   }
+
 }
--- a/libgui/src/variable-editor.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/variable-editor.h	Sun May 16 09:44:35 2021 +0200
@@ -34,6 +34,7 @@
 #include "dw-main-window.h"
 #include "gui-settings.h"
 #include "octave-dock-widget.h"
+#include "qt-interpreter-events.h"
 #include "tab-bar.h"
 
 class octave_value;
@@ -59,6 +60,8 @@
 
     variable_dock_widget (QWidget *p, base_qobject& oct_qobj);
 
+    ~variable_dock_widget (void) = default;
+
   signals:
 
     void variable_focused_signal (const QString& name);
@@ -87,8 +90,6 @@
 
     QFrame *m_frame;
 
-#if defined (HAVE_QGUIAPPLICATION)
-
     QAction *m_fullscreen_action;
 
     bool m_full_screen;
@@ -97,8 +98,6 @@
 
     QRect m_prev_geom;
 
-#endif
-
 // See Octave bug #53807 and https://bugreports.qt.io/browse/QTBUG-44813
 #define QTBUG_44813_FIX_VERSION 0x999999
   signals:
@@ -134,15 +133,20 @@
 
     variable_editor_stack (QWidget *p, base_qobject& oct_qobj);
 
+    ~variable_editor_stack (void) = default;
+
     variable_editor_view *edit_view (void) {return m_edit_view;};
 
     QTextEdit *disp_view (void) {return m_disp_view;};
 
   signals:
 
-    void command_signal (const QString& cmd);
+    void edit_variable_signal (const QString& name, const octave_value& val);
 
-    void edit_variable_signal (const QString& name, const octave_value& val);
+    void do_save_signal (const QString& format, const QString& save_opts);
+
+    void interpreter_event (const fcn_callback& fcn);
+    void interpreter_event (const meth_callback& meth);
 
   public slots:
 
@@ -150,7 +154,9 @@
 
     void levelUp (void);
 
-    void save (void);
+    void save (const QString& format = QString ());
+
+    void do_save (const QString& format, const QString& save_opts);
 
   private:
 
@@ -172,6 +178,8 @@
 
     variable_editor_view (QWidget *p, base_qobject& oct_qobj);
 
+    ~variable_editor_view (void) = default;
+
     void setModel (QAbstractItemModel *model);
 
   signals:
@@ -230,6 +238,8 @@
 
     HoverToolButton (QWidget *parent = nullptr);
 
+    ~HoverToolButton (void) = default;
+
   signals:
 
     void hovered_signal (void);
@@ -249,6 +259,8 @@
 
     ReturnFocusToolButton (QWidget *parent = nullptr);
 
+    ~ReturnFocusToolButton (void) = default;
+
   signals:
 
     void about_to_activate (void);
@@ -266,6 +278,8 @@
 
     ReturnFocusMenu (QWidget *parent = nullptr);
 
+    ~ReturnFocusMenu (void) = default;
+
   signals:
 
     void about_to_activate (void);
@@ -285,7 +299,7 @@
 
     variable_editor (QWidget *parent, base_qobject& oct_qobj);
 
-    ~variable_editor (void) = default;
+    ~variable_editor (void);
 
     // No copying!
 
@@ -355,12 +369,10 @@
 
   private:
 
-    QAction * add_action (QMenu *menu, const QIcon& icon, const QString& text,
-                          const char *member);
-
     dw_main_window *m_main;
 
     QToolBar *m_tool_bar;
+    QAction *m_save_action;
 
     int m_default_width;
 
@@ -394,6 +406,7 @@
     QString m_hovered_focus_vname;
 
     QSignalMapper *m_plot_mapper;
+    QSignalMapper *m_save_mapper;
 
     QWidget *m_focus_widget;
 
--- a/libgui/src/welcome-wizard.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/welcome-wizard.cc	Sun May 16 09:44:35 2021 +0200
@@ -213,8 +213,8 @@
     m_next->setDefault (true);
     m_next->setFocus ();
 
-    connect (m_next, SIGNAL (clicked ()), wizard, SLOT (next_page ()));
-    connect (m_cancel, SIGNAL (clicked ()), wizard, SLOT (reject ()));
+    connect (m_next, &QPushButton::clicked, wizard, &welcome_wizard::next_page);
+    connect (m_cancel, &QPushButton::clicked, wizard, &welcome_wizard::reject);
   }
 
   setup_community_news::setup_community_news (base_qobject&,
@@ -265,9 +265,6 @@
 
     m_checkbox_message->setText
       (tr ("<html><head>\n"
-           "<style>\n"
-           "a:link { text-decoration: underline; color: #0000ff; }\n"
-           "</style>\n"
            "</head><body>\n"
            "<p>Allow Octave to connect to the Octave web site when it starts to display current news and information about the Octave community.</p>\n"
            "</body></html>"));
@@ -306,12 +303,12 @@
     m_next->setDefault (true);
     m_next->setFocus ();
 
-    connect (m_checkbox, SIGNAL (stateChanged (int)),
-             wizard, SLOT (handle_web_connect_option (int)));
+    connect (m_checkbox, &QCheckBox::stateChanged,
+             wizard, &welcome_wizard::handle_web_connect_option);
 
-    connect (m_previous, SIGNAL (clicked ()), wizard, SLOT (previous_page ()));
-    connect (m_next, SIGNAL (clicked ()), wizard, SLOT (next_page ()));
-    connect (m_cancel, SIGNAL (clicked ()), wizard, SLOT (reject ()));
+    connect (m_previous, &QPushButton::clicked, wizard, &welcome_wizard::previous_page);
+    connect (m_next, &QPushButton::clicked, wizard, &welcome_wizard::next_page);
+    connect (m_cancel, &QPushButton::clicked, wizard, &welcome_wizard::reject);
   }
 
   final_page::final_page (base_qobject&, welcome_wizard *wizard)
@@ -351,9 +348,6 @@
 
     m_links->setText
       (tr ("<html><head>\n"
-           "<style>\n"
-           "a:link { text-decoration: underline; color: #0000ff; }\n"
-           "</style>\n"
            "</head><body>\n"
            "<p>For more information about Octave:</p>\n"
            "<ul>\n"
@@ -387,8 +381,9 @@
     m_finish->setDefault (true);
     m_finish->setFocus ();
 
-    connect (m_previous, SIGNAL (clicked ()), wizard, SLOT (previous_page ()));
-    connect (m_finish, SIGNAL (clicked ()), wizard, SLOT (accept ()));
-    connect (m_cancel, SIGNAL (clicked ()), wizard, SLOT (reject ()));
+    connect (m_previous, &QPushButton::clicked,
+             wizard, &welcome_wizard::previous_page);
+    connect (m_finish, &QPushButton::clicked, wizard, &welcome_wizard::accept);
+    connect (m_cancel, &QPushButton::clicked, wizard, &welcome_wizard::reject);
   }
 }
--- a/libgui/src/welcome-wizard.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/welcome-wizard.h	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
     int m_max_height;
     int m_max_width;
 
-  private slots:
+  public slots:
 
     void handle_web_connect_option (int state);
 
--- a/libgui/src/workspace-model.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/workspace-model.cc	Sun May 16 09:44:35 2021 +0200
@@ -200,10 +200,11 @@
   {
     m_enable_colors = settings->value (ws_enable_colors).toBool ();
 
+    int mode = settings->value (ws_color_mode).toInt ();
+
     for (int i = 0; i < ws_colors_count; i++)
       {
-        QColor setting_color = settings->value (ws_colors[i].key,
-                                                ws_colors[i].def).value<QColor> ();
+        QColor setting_color = settings->color_value (ws_colors[i], mode);
 
         QPalette p (setting_color);
         m_storage_class_colors.replace (i,setting_color);
--- a/libgui/src/workspace-model.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/workspace-model.h	Sun May 16 09:44:35 2021 +0200
@@ -75,6 +75,9 @@
 
     symbol_info_list get_symbol_info (void) const { return m_syminfo_list; }
 
+    QStringList get_symbol_names (void) const { return m_symbols; }
+    QStringList get_symbol_values (void) const { return m_values; }
+
   signals:
 
     void model_changed (void);
--- a/libgui/src/workspace-view.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/workspace-view.cc	Sun May 16 09:44:35 2021 +0200
@@ -43,6 +43,7 @@
 
 #include "gui-preferences-ws.h"
 #include "octave-qobject.h"
+#include "octave-qtutils.h"
 #include "workspace-view.h"
 
 #include "interpreter-private.h"
@@ -120,16 +121,8 @@
           (settings->value (ws_column_state.key).toByteArray ());
 
         // Set header properties for sorting
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE)
         m_view->horizontalHeader ()->setSectionsClickable (true);
-#else
-        m_view->horizontalHeader ()->setClickable (true);
-#endif
-#if defined (HAVE_QHEADERVIEW_SETSECTIONSMOVABLE)
         m_view->horizontalHeader ()->setSectionsMovable (true);
-#else
-        m_view->horizontalHeader ()->setMovable (true);
-#endif
         m_view->horizontalHeader ()->setSortIndicator (
           settings->value (ws_sort_column).toInt (),
           static_cast<Qt::SortOrder> (settings->value (ws_sort_order).toUInt ()));
@@ -140,8 +133,8 @@
 
         m_view->horizontalHeader ()->setContextMenuPolicy (Qt::CustomContextMenu);
         connect (m_view->horizontalHeader (),
-                 SIGNAL (customContextMenuRequested (const QPoint &)),
-                 this, SLOT (header_contextmenu_requested (const QPoint &)));
+                 &QTableView::customContextMenuRequested,
+                 this, &workspace_view::header_contextmenu_requested);
 
         // Init state of the filter
         m_filter->addItems (settings->value (ws_mru_list.key).toStringList ());
@@ -154,25 +147,21 @@
 
     // Connect signals and slots.
 
-    connect (m_filter, SIGNAL (editTextChanged (const QString&)),
-             this, SLOT (filter_update (const QString&)));
-    connect (m_filter_checkbox, SIGNAL (toggled (bool)),
-             this, SLOT (filter_activate (bool)));
-    connect (m_filter->lineEdit (), SIGNAL (editingFinished ()),
-             this, SLOT (update_filter_history ()));
-
-    connect (m_view, SIGNAL (customContextMenuRequested (const QPoint&)),
-             this, SLOT (contextmenu_requested (const QPoint&)));
+    connect (m_filter, &QComboBox::editTextChanged,
+             this, &workspace_view::filter_update);
+    connect (m_filter_checkbox, &QCheckBox::toggled,
+             this, &workspace_view::filter_activate);
+    connect (m_filter->lineEdit (), &QLineEdit::editingFinished,
+             this, &workspace_view::update_filter_history);
 
-    connect (m_view, SIGNAL (activated (QModelIndex)),
-             this, SLOT (handle_contextmenu_edit (void)));
+    connect (m_view, &QTableView::customContextMenuRequested,
+             this, &workspace_view::contextmenu_requested);
 
-    connect (this, SIGNAL (command_requested (const QString&)),
-             p, SLOT (execute_command_in_terminal (const QString&)));
+    connect (m_view, &QTableView::activated,
+             this, &workspace_view::handle_contextmenu_edit);
 
-    connect (this,
-             SIGNAL (edit_variable_signal (const QString&, const octave_value&)),
-             p, SLOT (edit_variable (const QString&, const octave_value&)));
+    if (! p)
+      make_window ();
   }
 
   void workspace_view::setModel (workspace_model *model)
@@ -217,7 +206,7 @@
               .arg (m_model->storage_class_color (i).name ())
               .arg (m_model->storage_class_color (i + ws_colors_count).name ())
               .arg (QCoreApplication::translate ("octave::settings_dialog",
-                                ws_color_names.at (i).toStdString ().data ()));
+                                                 ws_color_names.at (i).toStdString ().data ()));
           }
       }
 
@@ -254,6 +243,20 @@
     octave_dock_widget::save_settings ();
   }
 
+  void workspace_view::set_filter_focus (bool focus)
+  {
+    if (focus)
+      {
+        m_filter->setFocus ();
+        setFocusProxy (m_filter);
+      }
+    else
+      {
+        m_view->setFocus ();
+        setFocusProxy (m_view);
+      }
+  }
+
   void
   workspace_view::filter_update (const QString& expression)
   {
@@ -271,6 +274,8 @@
       filter_update (m_filter->currentText ());
     else
       filter_update (QString ());
+
+    set_filter_focus (state);
   }
 
   void
@@ -305,6 +310,20 @@
         action->setChecked (settings->value (ws_columns_shown_keys.at (i),true).toBool ());
       }
 
+    // FIXME: We could use
+    //
+    //   connect (&m_sig_mapper, QOverload<int>::of (&QSignalMapper::mapped),
+    //            this, &workspace_view::toggle_header);
+    //
+    // but referring to QSignalMapper::mapped will generate deprecated
+    // function warnings from GCC.  We could also use
+    //
+    //   connect (&m_sig_mapper, &QSignalMapper::mappedInt,
+    //            this, &workspace_view::toggle_header);
+    //
+    // but the function mappedInt was not introduced until Qt 5.15 so
+    // we'll need a feature test.
+
     connect (&sig_mapper, SIGNAL (mapped (int)),
              this, SLOT (toggle_header (int)));
 
@@ -341,16 +360,17 @@
         QString var_name = get_var_name (index);
 
         menu.addAction (tr ("Open in Variable Editor"), this,
-                        SLOT (handle_contextmenu_edit ()));
+                        &workspace_view::handle_contextmenu_edit);
 
         menu.addAction (tr ("Copy name"), this,
-                        SLOT (handle_contextmenu_copy ()));
+                        &workspace_view::handle_contextmenu_copy);
 
         menu.addAction (tr ("Copy value"), this,
-                        SLOT (handle_contextmenu_copy_value ()));
+                        &workspace_view::handle_contextmenu_copy_value);
 
-        QAction *rename = menu.addAction (tr ("Rename"), this,
-                                          SLOT (handle_contextmenu_rename ()));
+        QAction *rename
+          = menu.addAction (tr ("Rename"), this,
+                            &workspace_view::handle_contextmenu_rename);
 
         // Use m_model here instead of using "m_view->model ()" because
         // that points to the proxy model.
@@ -361,18 +381,18 @@
           }
 
         menu.addAction ("Clear " + var_name, this,
-                        SLOT (handle_contextmenu_clear ()));
+                        &workspace_view::handle_contextmenu_clear);
 
         menu.addSeparator ();
 
         menu.addAction ("disp (" + var_name + ')', this,
-                        SLOT (handle_contextmenu_disp ()));
+                        &workspace_view::handle_contextmenu_disp);
 
         menu.addAction ("plot (" + var_name + ')', this,
-                        SLOT (handle_contextmenu_plot ()));
+                        &workspace_view::handle_contextmenu_plot);
 
         menu.addAction ("stem (" + var_name + ')', this,
-                        SLOT (handle_contextmenu_stem ()));
+                        &workspace_view::handle_contextmenu_stem);
 
         menu.addSeparator ();
 
@@ -380,10 +400,10 @@
 
     if (m_filter_shown)
       menu.addAction (tr ("Hide filter"), this,
-                      SLOT (handle_contextmenu_filter ()));
+                      &workspace_view::handle_contextmenu_filter);
     else
       menu.addAction (tr ("Show filter"), this,
-                      SLOT (handle_contextmenu_filter ()));
+                      &workspace_view::handle_contextmenu_filter);
 
     menu.exec (m_view->mapToGlobal (qpos));
   }
@@ -413,7 +433,7 @@
         QString var_name = get_var_name (index);
 
         emit interpreter_event
-          ([var_name] (interpreter& interp)
+          ([=] (interpreter& interp)
            {
              // INTERPRETER THREAD
 
@@ -503,6 +523,8 @@
   {
     m_filter_shown = ! m_filter_shown;
     m_filter_widget->setVisible (m_filter_shown);
+
+    set_filter_focus (m_filter_shown && m_filter_checkbox->isChecked ());
   }
 
   void
--- a/libgui/src/workspace-view.h	Sun May 16 09:43:43 2021 +0200
+++ b/libgui/src/workspace-view.h	Sun May 16 09:44:35 2021 +0200
@@ -97,6 +97,8 @@
     void handle_contextmenu_stem (void);
     void handle_contextmenu_filter (void);
 
+  public slots:
+
     void handle_model_changed (void);
 
     void copyClipboard (void);
@@ -105,6 +107,7 @@
   private:
 
     void relay_contextmenu_command (const QString& cmdname, bool str = false);
+    void set_filter_focus (bool focus);
 
     QString get_var_name (const QModelIndex& index);
 
--- a/libinterp/build-env.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/build-env.h	Sun May 16 09:44:35 2021 +0200
@@ -34,152 +34,152 @@
 {
   namespace build_env
   {
-    extern OCTAVE_API octave_scalar_map features (void);
+    extern OCTINTERP_API octave_scalar_map features (void);
 
-    extern const char *AMD_CPPFLAGS;
-    extern const char *AMD_LDFLAGS;
-    extern const char *AMD_LIBS;
-    extern const char *ARFLAGS;
-    extern const char *AR;
-    extern const char *ARPACK_CPPFLAGS;
-    extern const char *ARPACK_LDFLAGS;
-    extern const char *ARPACK_LIBS;
-    extern const char *BLAS_LIBS;
-    extern const char *CAMD_CPPFLAGS;
-    extern const char *CAMD_LDFLAGS;
-    extern const char *CAMD_LIBS;
-    extern const char *CARBON_LIBS;
-    extern const char *CC;
-    extern const char *CCOLAMD_CPPFLAGS;
-    extern const char *CCOLAMD_LDFLAGS;
-    extern const char *CCOLAMD_LIBS;
-    extern const char *CFLAGS;
-    extern const char *CHOLMOD_CPPFLAGS;
-    extern const char *CHOLMOD_LDFLAGS;
-    extern const char *CHOLMOD_LIBS;
-    extern const char *COLAMD_CPPFLAGS;
-    extern const char *COLAMD_LDFLAGS;
-    extern const char *COLAMD_LIBS;
-    extern const char *CPICFLAG;
-    extern const char *CPPFLAGS;
-    extern const char *CURL_CPPFLAGS;
-    extern const char *CURL_LDFLAGS;
-    extern const char *CURL_LIBS;
-    extern const char *CXSPARSE_CPPFLAGS;
-    extern const char *CXSPARSE_LDFLAGS;
-    extern const char *CXSPARSE_LIBS;
-    extern const char *CXXCPP;
-    extern const char *CXXFLAGS;
-    extern const char *CXXPICFLAG;
-    extern const char *CXX;
-    extern const char *DEFAULT_PAGER;
-    extern const char *DEFS;
-    extern const char *DL_LDFLAGS;
-    extern const char *EXEEXT;
-    extern const char *GCC_VERSION;
-    extern const char *GXX_VERSION;
-    extern const char *F77;
-    extern const char *F77_FLOAT_STORE_FLAG;
-    extern const char *F77_INTEGER_8_FLAG;
-    extern const char *FFLAGS;
-    extern const char *FFTW3_CPPFLAGS;
-    extern const char *FFTW3_LDFLAGS;
-    extern const char *FFTW3_LIBS;
-    extern const char *FFTW3F_CPPFLAGS;
-    extern const char *FFTW3F_LDFLAGS;
-    extern const char *FFTW3F_LIBS;
-    extern const char *FLIBS;
-    extern const char *FLTK_CPPFLAGS;
-    extern const char *FLTK_LDFLAGS;
-    extern const char *FLTK_LIBS;
-    extern const char *FONTCONFIG_CPPFLAGS;
-    extern const char *FONTCONFIG_LIBS;
-    extern const char *FPICFLAG;
-    extern const char *FT2_CPPFLAGS;
-    extern const char *FT2_LIBS;
-    extern const char *GLPK_CPPFLAGS;
-    extern const char *GLPK_LDFLAGS;
-    extern const char *GLPK_LIBS;
-    extern const char *GNUPLOT;
-    extern const char *HDF5_CPPFLAGS;
-    extern const char *HDF5_LDFLAGS;
-    extern const char *HDF5_LIBS;
-    extern const char *INCLUDEDIR;
-    extern const char *KLU_CPPFLAGS;
-    extern const char *KLU_LDFLAGS;
-    extern const char *KLU_LIBS;
-    extern const char *LAPACK_LIBS;
-    extern const char *LDFLAGS;
-    extern const char *LD_STATIC_FLAG;
-    extern const char *LEXLIB;
-    extern const char *LEX;
-    extern const char *LFLAGS;
-    extern const char *LIBOCTAVE;
-    extern const char *LIBOCTINTERP;
-    extern const char *LIBS;
-    extern const char *LN_S;
-    extern const char *MAGICK_CPPFLAGS;
-    extern const char *MAGICK_LDFLAGS;
-    extern const char *MAGICK_LIBS;
-    extern const char *LLVM_CPPFLAGS;
-    extern const char *LLVM_LDFLAGS;
-    extern const char *LLVM_LIBS;
-    extern const char *MKOCTFILE_DL_LDFLAGS;
-    extern const char *OCTAVE_LINK_DEPS;
-    extern const char *OCTAVE_LINK_OPTS;
-    extern const char *OCTINCLUDEDIR;
-    extern const char *OCTLIBDIR;
-    extern const char *OCT_LINK_DEPS;
-    extern const char *OCT_LINK_OPTS;
-    extern const char *OPENGL_LIBS;
-    extern const char *PCRE_CPPFLAGS;
-    extern const char *PCRE_LDFLAGS;
-    extern const char *PCRE_LIBS;
-    extern const char *PREFIX;
-    extern const char *PTHREAD_CFLAGS;
-    extern const char *PTHREAD_LIBS;
-    extern const char *QHULL_CPPFLAGS;
-    extern const char *QHULL_LDFLAGS;
-    extern const char *QHULL_LIBS;
-    extern const char *QRUPDATE_CPPFLAGS;
-    extern const char *QRUPDATE_LDFLAGS;
-    extern const char *QRUPDATE_LIBS;
-    extern const char *QT_CPPFLAGS;
-    extern const char *QT_LDFLAGS;
-    extern const char *QT_LIBS;
-    extern const char *QT_OPENGL_LIBS;
-    extern const char *RANLIB;
-    extern const char *RDYNAMIC_FLAG;
-    extern const char *READLINE_LIBS;
-    extern const char *SHARED_LIBS;
-    extern const char *SH_LDFLAGS;
-    extern const char *STATIC_LIBS;
-    extern const char *SUITESPARSECONFIG_LIBS;
-    extern const char *SUNDIALS_IDA_CPPFLAGS;
-    extern const char *SUNDIALS_IDA_LDFLAGS;
-    extern const char *SUNDIALS_IDA_LIBS;
-    extern const char *SUNDIALS_NVECSERIAL_CPPFLAGS;
-    extern const char *SUNDIALS_NVECSERIAL_LDFLAGS;
-    extern const char *SUNDIALS_NVECSERIAL_LIBS;
-    extern const char *SUNDIALS_SUNLINSOLKLU_CPPFLAGS;
-    extern const char *SUNDIALS_SUNLINSOLKLU_LDFLAGS;
-    extern const char *SUNDIALS_SUNLINSOLKLU_LIBS;
-    extern const char *TERM_LIBS;
-    extern const char *UMFPACK_CPPFLAGS;
-    extern const char *UMFPACK_LDFLAGS;
-    extern const char *UMFPACK_LIBS;
-    extern const char *WARN_CFLAGS;
-    extern const char *WARN_CXXFLAGS;
-    extern const char *X11_INCFLAGS;
-    extern const char *X11_LIBS;
-    extern const char *XTRA_CFLAGS;
-    extern const char *XTRA_CXXFLAGS;
-    extern const char *YACC;
-    extern const char *YFLAGS;
-    extern const char *Z_CPPFLAGS;
-    extern const char *Z_LDFLAGS;
-    extern const char *Z_LIBS;
-    extern const char *config_opts;
+    extern OCTINTERP_API const char *AMD_CPPFLAGS;
+    extern OCTINTERP_API const char *AMD_LDFLAGS;
+    extern OCTINTERP_API const char *AMD_LIBS;
+    extern OCTINTERP_API const char *ARFLAGS;
+    extern OCTINTERP_API const char *AR;
+    extern OCTINTERP_API const char *ARPACK_CPPFLAGS;
+    extern OCTINTERP_API const char *ARPACK_LDFLAGS;
+    extern OCTINTERP_API const char *ARPACK_LIBS;
+    extern OCTINTERP_API const char *BLAS_LIBS;
+    extern OCTINTERP_API const char *CAMD_CPPFLAGS;
+    extern OCTINTERP_API const char *CAMD_LDFLAGS;
+    extern OCTINTERP_API const char *CAMD_LIBS;
+    extern OCTINTERP_API const char *CARBON_LIBS;
+    extern OCTINTERP_API const char *CC;
+    extern OCTINTERP_API const char *CCOLAMD_CPPFLAGS;
+    extern OCTINTERP_API const char *CCOLAMD_LDFLAGS;
+    extern OCTINTERP_API const char *CCOLAMD_LIBS;
+    extern OCTINTERP_API const char *CFLAGS;
+    extern OCTINTERP_API const char *CHOLMOD_CPPFLAGS;
+    extern OCTINTERP_API const char *CHOLMOD_LDFLAGS;
+    extern OCTINTERP_API const char *CHOLMOD_LIBS;
+    extern OCTINTERP_API const char *COLAMD_CPPFLAGS;
+    extern OCTINTERP_API const char *COLAMD_LDFLAGS;
+    extern OCTINTERP_API const char *COLAMD_LIBS;
+    extern OCTINTERP_API const char *CPICFLAG;
+    extern OCTINTERP_API const char *CPPFLAGS;
+    extern OCTINTERP_API const char *CURL_CPPFLAGS;
+    extern OCTINTERP_API const char *CURL_LDFLAGS;
+    extern OCTINTERP_API const char *CURL_LIBS;
+    extern OCTINTERP_API const char *CXSPARSE_CPPFLAGS;
+    extern OCTINTERP_API const char *CXSPARSE_LDFLAGS;
+    extern OCTINTERP_API const char *CXSPARSE_LIBS;
+    extern OCTINTERP_API const char *CXXCPP;
+    extern OCTINTERP_API const char *CXXFLAGS;
+    extern OCTINTERP_API const char *CXXPICFLAG;
+    extern OCTINTERP_API const char *CXX;
+    extern OCTINTERP_API const char *DEFAULT_PAGER;
+    extern OCTINTERP_API const char *DEFS;
+    extern OCTINTERP_API const char *DL_LDFLAGS;
+    extern OCTINTERP_API const char *EXEEXT;
+    extern OCTINTERP_API const char *GCC_VERSION;
+    extern OCTINTERP_API const char *GXX_VERSION;
+    extern OCTINTERP_API const char *F77;
+    extern OCTINTERP_API const char *F77_FLOAT_STORE_FLAG;
+    extern OCTINTERP_API const char *F77_INTEGER_8_FLAG;
+    extern OCTINTERP_API const char *FFLAGS;
+    extern OCTINTERP_API const char *FFTW3_CPPFLAGS;
+    extern OCTINTERP_API const char *FFTW3_LDFLAGS;
+    extern OCTINTERP_API const char *FFTW3_LIBS;
+    extern OCTINTERP_API const char *FFTW3F_CPPFLAGS;
+    extern OCTINTERP_API const char *FFTW3F_LDFLAGS;
+    extern OCTINTERP_API const char *FFTW3F_LIBS;
+    extern OCTINTERP_API const char *FLIBS;
+    extern OCTINTERP_API const char *FLTK_CPPFLAGS;
+    extern OCTINTERP_API const char *FLTK_LDFLAGS;
+    extern OCTINTERP_API const char *FLTK_LIBS;
+    extern OCTINTERP_API const char *FONTCONFIG_CPPFLAGS;
+    extern OCTINTERP_API const char *FONTCONFIG_LIBS;
+    extern OCTINTERP_API const char *FPICFLAG;
+    extern OCTINTERP_API const char *FT2_CPPFLAGS;
+    extern OCTINTERP_API const char *FT2_LIBS;
+    extern OCTINTERP_API const char *GLPK_CPPFLAGS;
+    extern OCTINTERP_API const char *GLPK_LDFLAGS;
+    extern OCTINTERP_API const char *GLPK_LIBS;
+    extern OCTINTERP_API const char *GNUPLOT;
+    extern OCTINTERP_API const char *HDF5_CPPFLAGS;
+    extern OCTINTERP_API const char *HDF5_LDFLAGS;
+    extern OCTINTERP_API const char *HDF5_LIBS;
+    extern OCTINTERP_API const char *INCLUDEDIR;
+    extern OCTINTERP_API const char *KLU_CPPFLAGS;
+    extern OCTINTERP_API const char *KLU_LDFLAGS;
+    extern OCTINTERP_API const char *KLU_LIBS;
+    extern OCTINTERP_API const char *LAPACK_LIBS;
+    extern OCTINTERP_API const char *LDFLAGS;
+    extern OCTINTERP_API const char *LD_STATIC_FLAG;
+    extern OCTINTERP_API const char *LEXLIB;
+    extern OCTINTERP_API const char *LEX;
+    extern OCTINTERP_API const char *LFLAGS;
+    extern OCTINTERP_API const char *LIBOCTAVE;
+    extern OCTINTERP_API const char *LIBOCTINTERP;
+    extern OCTINTERP_API const char *LIBS;
+    extern OCTINTERP_API const char *LN_S;
+    extern OCTINTERP_API const char *MAGICK_CPPFLAGS;
+    extern OCTINTERP_API const char *MAGICK_LDFLAGS;
+    extern OCTINTERP_API const char *MAGICK_LIBS;
+    extern OCTINTERP_API const char *LLVM_CPPFLAGS;
+    extern OCTINTERP_API const char *LLVM_LDFLAGS;
+    extern OCTINTERP_API const char *LLVM_LIBS;
+    extern OCTINTERP_API const char *MKOCTFILE_DL_LDFLAGS;
+    extern OCTINTERP_API const char *OCTAVE_LINK_DEPS;
+    extern OCTINTERP_API const char *OCTAVE_LINK_OPTS;
+    extern OCTINTERP_API const char *OCTINCLUDEDIR;
+    extern OCTINTERP_API const char *OCTLIBDIR;
+    extern OCTINTERP_API const char *OCT_LINK_DEPS;
+    extern OCTINTERP_API const char *OCT_LINK_OPTS;
+    extern OCTINTERP_API const char *OPENGL_LIBS;
+    extern OCTINTERP_API const char *PCRE_CPPFLAGS;
+    extern OCTINTERP_API const char *PCRE_LDFLAGS;
+    extern OCTINTERP_API const char *PCRE_LIBS;
+    extern OCTINTERP_API const char *PREFIX;
+    extern OCTINTERP_API const char *PTHREAD_CFLAGS;
+    extern OCTINTERP_API const char *PTHREAD_LIBS;
+    extern OCTINTERP_API const char *QHULL_CPPFLAGS;
+    extern OCTINTERP_API const char *QHULL_LDFLAGS;
+    extern OCTINTERP_API const char *QHULL_LIBS;
+    extern OCTINTERP_API const char *QRUPDATE_CPPFLAGS;
+    extern OCTINTERP_API const char *QRUPDATE_LDFLAGS;
+    extern OCTINTERP_API const char *QRUPDATE_LIBS;
+    extern OCTINTERP_API const char *QT_CPPFLAGS;
+    extern OCTINTERP_API const char *QT_LDFLAGS;
+    extern OCTINTERP_API const char *QT_LIBS;
+    extern OCTINTERP_API const char *QT_OPENGL_LIBS;
+    extern OCTINTERP_API const char *RANLIB;
+    extern OCTINTERP_API const char *RDYNAMIC_FLAG;
+    extern OCTINTERP_API const char *READLINE_LIBS;
+    extern OCTINTERP_API const char *SHARED_LIBS;
+    extern OCTINTERP_API const char *SH_LDFLAGS;
+    extern OCTINTERP_API const char *STATIC_LIBS;
+    extern OCTINTERP_API const char *SUITESPARSECONFIG_LIBS;
+    extern OCTINTERP_API const char *SUNDIALS_IDA_CPPFLAGS;
+    extern OCTINTERP_API const char *SUNDIALS_IDA_LDFLAGS;
+    extern OCTINTERP_API const char *SUNDIALS_IDA_LIBS;
+    extern OCTINTERP_API const char *SUNDIALS_NVECSERIAL_CPPFLAGS;
+    extern OCTINTERP_API const char *SUNDIALS_NVECSERIAL_LDFLAGS;
+    extern OCTINTERP_API const char *SUNDIALS_NVECSERIAL_LIBS;
+    extern OCTINTERP_API const char *SUNDIALS_SUNLINSOLKLU_CPPFLAGS;
+    extern OCTINTERP_API const char *SUNDIALS_SUNLINSOLKLU_LDFLAGS;
+    extern OCTINTERP_API const char *SUNDIALS_SUNLINSOLKLU_LIBS;
+    extern OCTINTERP_API const char *TERM_LIBS;
+    extern OCTINTERP_API const char *UMFPACK_CPPFLAGS;
+    extern OCTINTERP_API const char *UMFPACK_LDFLAGS;
+    extern OCTINTERP_API const char *UMFPACK_LIBS;
+    extern OCTINTERP_API const char *WARN_CFLAGS;
+    extern OCTINTERP_API const char *WARN_CXXFLAGS;
+    extern OCTINTERP_API const char *X11_INCFLAGS;
+    extern OCTINTERP_API const char *X11_LIBS;
+    extern OCTINTERP_API const char *XTRA_CFLAGS;
+    extern OCTINTERP_API const char *XTRA_CXXFLAGS;
+    extern OCTINTERP_API const char *YACC;
+    extern OCTINTERP_API const char *YFLAGS;
+    extern OCTINTERP_API const char *Z_CPPFLAGS;
+    extern OCTINTERP_API const char *Z_LDFLAGS;
+    extern OCTINTERP_API const char *Z_LIBS;
+    extern OCTINTERP_API const char *config_opts;
   }
 }
 
--- a/libinterp/corefcn/Cell.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/Cell.cc	Sun May 16 09:44:35 2021 +0200
@@ -191,7 +191,7 @@
 
         case 1:
           {
-            idx_vector i = idx_arg(0).index_vector ();
+            octave::idx_vector i = idx_arg(0).index_vector ();
 
             retval = Array<octave_value>::index (i, resize_ok, Matrix ());
           }
@@ -199,10 +199,10 @@
 
         case 2:
           {
-            idx_vector i = idx_arg(0).index_vector ();
+            octave::idx_vector i = idx_arg(0).index_vector ();
 
             k = 1;
-            idx_vector j = idx_arg(1).index_vector ();
+            octave::idx_vector j = idx_arg(1).index_vector ();
 
             retval = Array<octave_value>::index (i, j, resize_ok, Matrix ());
           }
@@ -210,7 +210,7 @@
 
         default:
           {
-            Array<idx_vector> iv (dim_vector (n, 1));
+            Array<octave::idx_vector> iv (dim_vector (n, 1));
 
             for (k = 0; k < n; k++)
               iv(k) = idx_arg(k).index_vector ();
@@ -220,10 +220,10 @@
           break;
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (n, k+1);
+      ie.set_pos_if_unset (n, k+1);
       throw;
     }
 
@@ -234,7 +234,7 @@
 %% This behavior is required for Matlab compatibility.
 %!shared a
 %! a = {"foo", "bar"};
-%!assert (a(), a);
+%!assert (a(), a)
 %!error <invalid empty index expression> a{}
 */
 
@@ -245,7 +245,7 @@
 {
   octave_idx_type len = idx_arg.length ();
 
-  Array<idx_vector> ra_idx (dim_vector (len, 1));
+  Array<octave::idx_vector> ra_idx (dim_vector (len, 1));
 
   for (octave_idx_type i = 0; i < len; i++)
     {
@@ -253,10 +253,10 @@
         {
           ra_idx(i) = idx_arg(i).index_vector ();
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
           // Rethrow to allow more info to be reported later.
-          e.set_pos (len, i+1);
+          ie.set_pos (len, i+1);
           throw;
         }
     }
@@ -270,17 +270,17 @@
 {
   octave_idx_type len = idx_arg.length ();
 
-  Array<idx_vector> ra_idx (dim_vector (len, 1));
+  Array<octave::idx_vector> ra_idx (dim_vector (len, 1));
 
   for (octave_idx_type i = 0; i < len; i++)
     try
       {
         ra_idx.xelem (i) = idx_arg(i).index_vector ();
       }
-    catch (octave::index_exception& e)
+    catch (octave::index_exception& ie)
       {
         // Rethrow to allow more info to be reported later.
-        e.set_pos (len, i+1);
+        ie.set_pos (len, i+1);
         throw;
       }
 
--- a/libinterp/corefcn/__betainc__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__betainc__.cc	Sun May 16 09:44:35 2021 +0200
@@ -37,9 +37,7 @@
 Continued fraction for incomplete beta function.
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 3)
+  if (args.length () != 3)
     print_usage ();
 
   bool is_single = (args(0).is_single_type () || args(1).is_single_type ()
--- a/libinterp/corefcn/__contourc__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__contourc__.cc	Sun May 16 09:44:35 2021 +0200
@@ -55,27 +55,25 @@
 #define CONTOUR_QUANT 50
 
 // Add a coordinate point (x,y) to this_contour.
-
 static void
 add_point (double x, double y)
 {
   if (elem % CONTOUR_QUANT == 0)
     this_contour = this_contour.append (Matrix (2, CONTOUR_QUANT, 0));
 
-  this_contour (0, elem) = x;
-  this_contour (1, elem) = y;
+  this_contour(0, elem) = x;
+  this_contour(1, elem) = y;
   elem++;
 }
 
 // Add contents of current contour to contourc.
 // this_contour.cols () - 1;
-
 static void
 end_contour (void)
 {
   if (elem > 2)
     {
-      this_contour (1, 0) = elem - 1;
+      this_contour(1, 0) = elem - 1;
       contourc = contourc.append (this_contour.extract_n (0, 0, 2, elem));
     }
 
@@ -302,13 +300,10 @@
 
 DEFUN (__contourc__, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn {} {} __contourc__ (@var{x}, @var{y}, @var{z}, @var{levels})
-Undocumented internal function.
+@deftypefn {} {@var{c} =} __contourc__ (@var{x}, @var{y}, @var{z}, @var{levels})
+Calculate Z-level contours (isolines).
 @end deftypefn */)
 {
-  if (args.length () != 4)
-    print_usage ();
-
   RowVector X = args(0).row_vector_value ();
   RowVector Y = args(1).row_vector_value ();
   Matrix Z = args(2).matrix_value ();
@@ -317,7 +312,7 @@
   contourc.resize (2, 0);
 
   for (int i = 0; i < L.numel (); i++)
-    cntr (X, Y, Z, L (i));
+    cntr (X, Y, Z, L(i));
 
   end_contour ();
 
--- a/libinterp/corefcn/__dsearchn__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__dsearchn__.cc	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
   Matrix xi = args(1).matrix_value ().transpose ();
 
   if (x.rows () != xi.rows () || x.columns () < 1)
-    error ("__dsearch__: number of rows of X and XI must match");
+    error ("__dsearchn__: number of rows of X and XI must match");
 
   octave_idx_type n = x.rows ();
   octave_idx_type nx = x.columns ();
--- a/libinterp/corefcn/__eigs__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__eigs__.cc	Sun May 16 09:44:35 2021 +0200
@@ -47,17 +47,25 @@
 
 #if defined (HAVE_ARPACK)
 
-// Global pointer for user defined function.
-static octave_value eigs_fcn;
+struct eigs_callback {
+  // Pointer for user defined function.
+  octave_value eigs_fcn;
+
+  // Have we warned about imaginary values returned from user function?
+  bool warned_imaginary = false;
 
-// Have we warned about imaginary values returned from user function?
-static bool warned_imaginary = false;
+  ColumnVector
+  eigs_func (const ColumnVector& x, int& eigs_error);
+  
+  ComplexColumnVector
+  eigs_complex_func (const ComplexColumnVector& x, int& eigs_error);
+};
 
 // Is this a recursive call?
 static int call_depth = 0;
 
 ColumnVector
-eigs_func (const ColumnVector& x, int& eigs_error)
+eigs_callback::eigs_func (const ColumnVector& x, int& eigs_error)
 {
   ColumnVector retval;
   octave_value_list args;
@@ -71,9 +79,9 @@
         {
           tmp = octave::feval (eigs_fcn, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "eigs");
+          err_user_supplied_eval (ee, "eigs");
         }
 
       if (tmp.length () && tmp(0).is_defined ())
@@ -97,7 +105,8 @@
 }
 
 ComplexColumnVector
-eigs_complex_func (const ComplexColumnVector& x, int& eigs_error)
+eigs_callback::eigs_complex_func (const ComplexColumnVector& x,
+                                  int& eigs_error)
 {
   ComplexColumnVector retval;
   octave_value_list args;
@@ -111,9 +120,9 @@
         {
           tmp = octave::feval (eigs_fcn, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "eigs");
+          err_user_supplied_eval (ee, "eigs");
         }
 
       if (tmp.length () && tmp(0).is_defined ())
@@ -197,12 +206,9 @@
   ComplexColumnVector cresid;
   octave_idx_type info = 1;
 
-  warned_imaginary = false;
+  eigs_callback callback;
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (eigs_fcn);
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
@@ -211,9 +217,9 @@
   if (args(0).is_function_handle () || args(0).is_inline_function ()
       || args(0).is_string ())
     {
-      eigs_fcn = octave::get_function_handle (interp, args(0), "x");
+      callback.eigs_fcn = octave::get_function_handle (interp, args(0), "x");
 
-      if (eigs_fcn.is_undefined ())
+      if (callback.eigs_fcn.is_undefined ())
         error ("eigs: unknown function");
 
       if (nargin < 2)
@@ -429,6 +435,13 @@
   octave_idx_type nconv;
   if (a_is_complex || b_is_complex)
     {
+      EigsComplexFunc
+      eigs_complex_fcn = [&callback] (const ComplexColumnVector& x,
+                                      int& eigs_error)
+                           {
+                             return callback.eigs_complex_func (x, eigs_error);
+                           };
+
       ComplexMatrix eig_vec;
       ComplexColumnVector eig_val;
 
@@ -436,12 +449,12 @@
         {
           if (b_is_sparse)
             nconv = EigsComplexNonSymmetricFunc
-              (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec,
+              (eigs_complex_fcn, n, typ, sigma, k, p, info, eig_vec,
                eig_val, bscm, permB, cresid, octave_stdout, tol,
                (nargout > 1), cholB, disp, maxit);
           else
             nconv = EigsComplexNonSymmetricFunc
-              (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec,
+              (eigs_complex_fcn, n, typ, sigma, k, p, info, eig_vec,
                eig_val, bcm, permB, cresid, octave_stdout, tol,
                (nargout > 1), cholB, disp, maxit);
         }
@@ -489,6 +502,13 @@
     }
   else if (sigmai != 0.0)
     {
+      EigsComplexFunc
+      eigs_complex_fcn = [&callback] (const ComplexColumnVector& x,
+                                      int& eigs_error)
+                           {
+                             return callback.eigs_complex_func (x, eigs_error);
+                           };
+
       // Promote real problem to a complex one.
       ComplexMatrix eig_vec;
       ComplexColumnVector eig_val;
@@ -497,12 +517,12 @@
         {
           if (b_is_sparse)
             nconv = EigsComplexNonSymmetricFunc
-              (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec,
+              (eigs_complex_fcn, n, typ, sigma, k, p, info, eig_vec,
                eig_val, bscm, permB, cresid, octave_stdout, tol,
                (nargout > 1), cholB, disp, maxit);
           else
             nconv = EigsComplexNonSymmetricFunc
-              (eigs_complex_func, n, typ, sigma, k, p, info, eig_vec,
+              (eigs_complex_fcn, n, typ, sigma, k, p, info, eig_vec,
                eig_val, bcm, permB, cresid, octave_stdout, tol,
                (nargout > 1), cholB, disp, maxit);
         }
@@ -537,6 +557,11 @@
     }
   else
     {
+      EigsFunc eigs_fcn = [&callback] (const ColumnVector& x, int& eigs_error)
+                            {
+                              return callback.eigs_func (x, eigs_error);
+                            };
+
       if (symmetric)
         {
           Matrix eig_vec;
@@ -546,12 +571,12 @@
             {
               if (b_is_sparse)
                 nconv = EigsRealSymmetricFunc
-                       (eigs_func, n, typ, sigmar, k, p, info, eig_vec,
+                       (eigs_fcn, n, typ, sigmar, k, p, info, eig_vec,
                         eig_val, bsmm, permB, resid, octave_stdout, tol,
                         (nargout > 1), cholB, disp, maxit);
               else
                 nconv = EigsRealSymmetricFunc
-                       (eigs_func, n, typ, sigmar, k, p, info, eig_vec,
+                       (eigs_fcn, n, typ, sigmar, k, p, info, eig_vec,
                         eig_val, bmm, permB, resid, octave_stdout, tol,
                         (nargout > 1), cholB, disp, maxit);
             }
@@ -596,12 +621,12 @@
             {
               if (b_is_sparse)
                 nconv = EigsRealNonSymmetricFunc
-                        (eigs_func, n, typ, sigmar, k, p, info, eig_vec,
+                        (eigs_fcn, n, typ, sigmar, k, p, info, eig_vec,
                          eig_val, bsmm, permB, resid, octave_stdout, tol,
                          (nargout > 1), cholB, disp, maxit);
               else
                 nconv = EigsRealNonSymmetricFunc
-                        (eigs_func, n, typ, sigmar, k, p, info, eig_vec,
+                        (eigs_fcn, n, typ, sigmar, k, p, info, eig_vec,
                          eig_val, bmm, permB, resid, octave_stdout, tol,
                          (nargout > 1), cholB, disp, maxit);
             }
--- a/libinterp/corefcn/__expint__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__expint__.cc	Sun May 16 09:44:35 2021 +0200
@@ -37,9 +37,7 @@
 Continued fraction expansion for the exponential integral.
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 1)
+  if (args.length () != 1)
     print_usage ();
 
   octave_value_list retval;
--- a/libinterp/corefcn/__ftp__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__ftp__.cc	Sun May 16 09:44:35 2021 +0200
@@ -52,12 +52,6 @@
 #include "unwind-prot.h"
 #include "url-handle-manager.h"
 
-static void
-delete_file (const std::string& file)
-{
-  octave::sys::unlink (file);
-}
-
 DEFMETHOD (__ftp__, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{handle} =} __ftp__ (@var{host})
@@ -67,9 +61,6 @@
 {
   int nargin = args.length ();
 
-  if (nargin < 1 || nargin > 3)
-    print_usage ();
-
   std::string host = args(0).xstring_value ("__ftp__: HOST must be a string");
 
   std::string user = (nargin > 1)
@@ -94,9 +85,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 1)
-    error ("__ftp_pwd__: incorrect number of arguments");
-
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
 
   octave::url_transfer url_xfer = uhm.get_object (args(0));
@@ -115,9 +103,6 @@
 {
   int nargin = args.length ();
 
-  if (nargin != 1 && nargin != 2)
-    error ("__ftp_cwd__: incorrect number of arguments");
-
   std::string path = "";
   if (nargin > 1)
     path = args(1).xstring_value ("__ftp_cwd__: PATH must be a string");
@@ -140,9 +125,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 1)
-    error ("__ftp_dir__: incorrect number of arguments");
-
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
 
   octave::url_transfer url_xfer = uhm.get_object (args(0));
@@ -190,10 +172,10 @@
 
               url_xfer.get_fileinfo (sv(i), fsize, ftime, fisdir);
 
-              fileisdir (i) = fisdir;
-              filectime (i) = ctime (&ftime);
-              filesize (i) = fsize;
-              filedatenum (i) = double (ftime);
+              fileisdir(i) = fisdir;
+              filectime(i) = ctime (&ftime);
+              filesize(i)  = fsize;
+              filedatenum(i) = double (ftime);
             }
 
           st.assign ("date", filectime);
@@ -214,9 +196,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 1)
-    error ("__ftp_ascii__: incorrect number of arguments");
-
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
 
   octave::url_transfer url_xfer = uhm.get_object (args(0));
@@ -235,9 +214,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 1)
-    error ("__ftp_binary__: incorrect number of arguments");
-
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
 
   octave::url_transfer url_xfer = uhm.get_object (args(0));
@@ -256,9 +232,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 1)
-    error ("__ftp_close__: incorrect number of arguments");
-
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
 
   octave::url_handle h = uhm.lookup (args(0));
@@ -277,9 +250,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 1)
-    error ("__ftp_mode__: incorrect number of arguments");
-
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
 
   octave::url_transfer url_xfer = uhm.get_object (args(0));
@@ -296,9 +266,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 2)
-    error ("__ftp_delete__: incorrect number of arguments");
-
   std::string file = args(1).xstring_value ("__ftp_delete__: FILE must be a string");
 
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
@@ -319,9 +286,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 2)
-    error ("__ftp_rmdir__: incorrect number of arguments");
-
   std::string dir = args(1).xstring_value ("__ftp_rmdir__: DIR must be a string");
 
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
@@ -342,9 +306,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 2)
-    error ("__ftp_mkdir__: incorrect number of arguments");
-
   std::string dir = args(1).xstring_value ("__ftp_mkdir__: DIR must be a string");
 
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
@@ -365,9 +326,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 3)
-    error ("__ftp_rename__: incorrect number of arguments");
-
   std::string oldname = args(1).xstring_value ("__ftp_rename__: OLDNAME must be a string");
   std::string newname = args(2).xstring_value ("__ftp_rename__: NEWNAME must be a string");
 
@@ -389,9 +347,6 @@
 Undocumented internal function
 @end deftypefn */)
 {
-  if (args.length () != 2)
-    error ("__ftp_mput__: incorrect number of arguments");
-
   std::string pat = args(1).xstring_value ("__ftp_mput__: PATTERN must be a string");
 
   octave::url_handle_manager& uhm = interp.get_url_handle_manager ();
@@ -425,7 +380,7 @@
       else
         {
           // FIXME: Does ascii mode need to be flagged here?
-          std::ifstream ifile = 
+          std::ifstream ifile =
             octave::sys::ifstream (file.c_str (),
                                    std::ios::in | std::ios::binary);
 
@@ -458,9 +413,6 @@
 {
   int nargin = args.length ();
 
-  if (nargin != 2 && nargin != 3)
-    error ("__ftp_mget__: incorrect number of arguments");
-
   std::string file = args(1).xstring_value ("__ftp_mget__: PATTERN must be a string");
 
   std::string target;
@@ -503,20 +455,20 @@
               if (! ofile.is_open ())
                 error ("__ftp_mget__: unable to open file");
 
-              octave::unwind_protect_safe frame;
-
-              frame.add_fcn (delete_file, target + sv(i));
+              int(*unlink_fptr)(const std::string&) = octave::sys::unlink;
+              octave::unwind_action_safe delete_file
+                (unlink_fptr, target + sv(i));
 
               url_xfer.get (sv(i), ofile);
 
               ofile.close ();
 
               if (url_xfer.good ())
-                frame.discard ();
+                delete_file.discard ();
             }
 
           if (! url_xfer.good ())
-            error ("__ftp_mget__: %s", url_xfer.lasterror().c_str());
+            error ("__ftp_mget__: %s", url_xfer.lasterror ().c_str ());
         }
     }
 
--- a/libinterp/corefcn/__gammainc__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__gammainc__.cc	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 Continued fraction for incomplete gamma function.
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 2)
+  if (args.length () != 2)
     print_usage ();
 
   bool is_single = args(0).is_single_type () || args(1).is_single_type ();
--- a/libinterp/corefcn/__ilu__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__ilu__.cc	Sun May 16 09:44:35 2021 +0200
@@ -892,7 +892,7 @@
     {
       U = U.transpose ();
       // The diagonal, conveniently permuted is added to U
-      U += diag.index (idx_vector::colon, perm_vec);
+      U += diag.index (octave::idx_vector::colon, perm_vec);
       L = L.transpose ();
     }
 }
@@ -938,8 +938,8 @@
           retval(0) = L + speye;
           if (nargout == 3)
             {
-              retval(1) = U.index (idx_vector::colon, perm);
-              retval(2) = speye.index (idx_vector::colon, perm);
+              retval(1) = U.index (octave::idx_vector::colon, perm);
+              retval(2) = speye.index (octave::idx_vector::colon, perm);
             }
           else
             retval(1) = U;
@@ -949,11 +949,11 @@
           retval(1) = U;
           if (nargout == 3)
             {
-              retval(0) = L.index (perm, idx_vector::colon) + speye;
-              retval(2) = speye.index (perm, idx_vector::colon);
+              retval(0) = L.index (perm, octave::idx_vector::colon) + speye;
+              retval(2) = speye.index (perm, octave::idx_vector::colon);
             }
           else
-            retval(0) = L + speye.index (idx_vector::colon, perm);
+            retval(0) = L + speye.index (octave::idx_vector::colon, perm);
         }
     }
   else
@@ -979,8 +979,8 @@
           retval(0) = L + speye;
           if (nargout == 3)
             {
-              retval(1) = U.index (idx_vector::colon, perm);
-              retval(2) = speye.index (idx_vector::colon, perm);
+              retval(1) = U.index (octave::idx_vector::colon, perm);
+              retval(2) = speye.index (octave::idx_vector::colon, perm);
             }
           else if (nargout == 2)
             retval(1) = U;
@@ -990,11 +990,11 @@
           retval(1) = U;
           if (nargout == 3)
             {
-              retval(0) = L.index (perm, idx_vector::colon) + speye;
-              retval(2) = speye.index (perm, idx_vector::colon);
+              retval(0) = L.index (perm, octave::idx_vector::colon) + speye;
+              retval(2) = speye.index (perm, octave::idx_vector::colon);
             }
           else
-            retval(0) = L + speye.index (idx_vector::colon, perm);
+            retval(0) = L + speye.index (octave::idx_vector::colon, perm);
         }
     }
 
--- a/libinterp/corefcn/__magick_read__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__magick_read__.cc	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,7 @@
 #endif
 
 #include "file-stat.h"
+#include "lo-sysdep.h"
 #include "oct-env.h"
 #include "oct-time.h"
 
@@ -140,17 +141,17 @@
 // width 1.  In those cases, the type will come as scalar instead of range
 // since that's the behavior of the colon operator (1:1:1 will be a scalar,
 // not a range).
-static Range
+static octave::range<double>
 get_region_range (const octave_value& region)
 {
-  Range output;
+  octave::range<double> output;
 
   if (region.is_range ())
     output = region.range_value ();
   else if (region.is_scalar_type ())
     {
       double value = region.scalar_value ();
-      output = Range (value, value);
+      output = octave::range<double> (value, value);
     }
   else if (region.is_matrix_type ())
     {
@@ -158,7 +159,7 @@
       double base = array(0);
       double limit = array(array.numel () - 1);
       double incr = array(1) - base;
-      output = Range (base, limit, incr);
+      output = octave::range<double> (base, incr, limit);
     }
   else
     error ("__magick_read__: unknown datatype for Region option");
@@ -180,8 +181,8 @@
 
     // Subtract 1 to account for 0 indexing.
 
-    const Range rows = get_region_range (pixel_region (0));
-    const Range cols = get_region_range (pixel_region (1));
+    const octave::range<double> rows = get_region_range (pixel_region (0));
+    const octave::range<double> cols = get_region_range (pixel_region (1));
 
     m_row_start = rows.base () - 1;
     m_col_start = cols.base () - 1;
@@ -191,8 +192,8 @@
     m_row_cache = m_row_end - m_row_start + 1;
     m_col_cache = m_col_end - m_col_start + 1;
 
-    m_row_shift = m_col_cache * rows.inc ();
-    m_col_shift = m_col_cache * (m_row_cache + rows.inc () - 1) - cols.inc ();
+    m_row_shift = m_col_cache * rows.increment ();
+    m_col_shift = m_col_cache * (m_row_cache + rows.increment () - 1) - cols.increment ();
 
     m_row_out = rows.numel ();
     m_col_out = cols.numel ();
@@ -754,15 +755,21 @@
 void static
 read_file (const std::string& filename, std::vector<Magick::Image>& imvec)
 {
+  // FIXME: We need this on Windows because GraphicsMagick uses the ANSI API
+  // to open files on disc.  In contrast, the API of ImageMagick uses UTF-8
+  // encoded strings.  Should we somehow detect which is used on runtime and
+  // pass the file names accordingly? (See also bug #58493.)
+  std::string ascii_fname = octave::sys::get_ASCII_filename (filename, true);
+
   try
     {
-      Magick::readImages (&imvec, filename);
+      Magick::readImages (&imvec, ascii_fname);
     }
-  catch (Magick::Warning& w)
+  catch (const Magick::Warning& w)
     {
       warning ("Magick++ warning: %s", w.what ());
     }
-  catch (Magick::Exception& e)
+  catch (const Magick::Exception& e)
     {
       error ("Magick++ exception: %s", e.what ());
     }
@@ -1454,15 +1461,15 @@
     {
       Magick::writeImages (imvec.begin (), imvec.end (), ext + ':' + filename);
     }
-  catch (Magick::Warning& w)
+  catch (const Magick::Warning& w)
     {
       warning ("Magick++ warning: %s", w.what ());
     }
-  catch (Magick::ErrorCoder& e)
+  catch (const Magick::ErrorCoder& e)
     {
       warning ("Magick++ coder error: %s", e.what ());
     }
-  catch (Magick::Exception& e)
+  catch (const Magick::Exception& e)
     {
       error ("Magick++ exception: %s", e.what ());
     }
@@ -1551,7 +1558,7 @@
         encode_indexed_images<uint16NDArray> (imvec, img.uint16_array_value (),
                                               cmap);
       else
-        error ("__magick_write__: indexed image must be uint8, uint16 or float.");
+        error ("__magick_write__: indexed image must be uint8, uint16 or float");
     }
   static std::map<std::string, octave_idx_type> disposal_methods
     = init_reverse_disposal_methods ();
@@ -1687,15 +1694,22 @@
   Magick::Image img;
   img.subImage (idx); // start ping from this image (in case of multi-page)
   img.subRange (1);   // ping only one of them
+
+  // FIXME: We need this on Windows because GraphicsMagick uses the ANSI API
+  // to open files on disc.  In contrast, the API of ImageMagick uses UTF-8
+  // encoded strings.  Should we somehow detect which is used on runtime and
+  // pass the file names accordingly? (See also bug #58493.)
+  std::string ascii_fname = octave::sys::get_ASCII_filename (filename, true);
+
   try
     {
-      img.ping (filename);
+      img.ping (ascii_fname);
     }
-  catch (Magick::Warning& w)
+  catch (const Magick::Warning& w)
     {
       warning ("Magick++ warning: %s", w.what ());
     }
-  catch (Magick::Exception& e)
+  catch (const Magick::Exception& e)
     {
       error ("Magick++ exception: %s", e.what ());
     }
@@ -2370,7 +2384,7 @@
             fmt.setfield ("write", Matrix ());
           formats.fast_elem_insert (idx, fmt);
         }
-      catch (Magick::Exception& e)
+      catch (const Magick::Exception&)
         {
           // Exception here are missing formats.  So we remove the format
           // from the structure and reduce idx.
--- a/libinterp/corefcn/__pchip_deriv__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__pchip_deriv__.cc	Sun May 16 09:44:35 2021 +0200
@@ -85,7 +85,8 @@
               k++;
 
               if (ierr < 0)
-                error ("__pchip_deriv__: PCHIM failed with ierr = %i", ierr);
+                error ("__pchip_deriv__: PCHIM failed with ierr = %"
+                       OCTAVE_F77_INT_TYPE_FORMAT, ierr);
             }
 
           retval = dmat;
@@ -122,7 +123,8 @@
               k++;
 
               if (ierr < 0)
-                error ("__pchip_deriv__: DPCHIM failed with ierr = %i", ierr);
+                error ("__pchip_deriv__: DPCHIM failed with ierr = %"
+                       OCTAVE_F77_INT_TYPE_FORMAT, ierr);
             }
 
           retval = dmat;
--- a/libinterp/corefcn/__qp__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/__qp__.cc	Sun May 16 09:44:35 2021 +0200
@@ -157,9 +157,9 @@
     {
       eigH = EIG (H);
     }
-  catch (octave::execution_exception& e)
+  catch (octave::execution_exception& ee)
     {
-      error (e, "qp: failed to compute eigenvalues of H");
+      error (ee, "qp: failed to compute eigenvalues of H");
     }
 
   ColumnVector eigenvalH = real (eigH.eigenvalues ());
@@ -298,9 +298,9 @@
                 {
                   eigrH = EIG (rH);
                 }
-              catch (octave::execution_exception& e)
+              catch (octave::execution_exception& ee)
                 {
-                  error (e, "qp: failed to compute eigenvalues of rH");
+                  error (ee, "qp: failed to compute eigenvalues of rH");
                 }
 
               ColumnVector eigenvalrH = real (eigrH.eigenvalues ());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/base-text-renderer.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,173 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2009-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "base-text-renderer.h"
+
+namespace octave
+{
+  void
+  base_text_renderer::rotate_pixels (uint8NDArray& pixels, int rot_mode) const
+  {
+    switch (rot_mode)
+      {
+      case ROTATION_0:
+        break;
+
+      case ROTATION_90:
+        {
+          Array<octave_idx_type> perm (dim_vector (3, 1));
+          perm(0) = 0;
+          perm(1) = 2;
+          perm(2) = 1;
+          pixels = pixels.permute (perm);
+
+          Array<idx_vector> idx (dim_vector (3, 1));
+          idx(0) = idx_vector (':');
+          idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1);
+          idx(2) = idx_vector (':');
+          pixels = uint8NDArray (pixels.index (idx));
+        }
+        break;
+
+      case ROTATION_180:
+        {
+          Array<idx_vector> idx (dim_vector (3, 1));
+          idx(0) = idx_vector (':');
+          idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1);
+          idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1);
+          pixels = uint8NDArray (pixels.index (idx));
+        }
+        break;
+
+      case ROTATION_270:
+        {
+          Array<octave_idx_type> perm (dim_vector (3, 1));
+          perm(0) = 0;
+          perm(1) = 2;
+          perm(2) = 1;
+          pixels = pixels.permute (perm);
+
+          Array<idx_vector> idx (dim_vector (3, 1));
+          idx(0) = idx_vector (':');
+          idx(1) = idx_vector (':');
+          idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1);
+          pixels = uint8NDArray (pixels.index (idx));
+        }
+        break;
+
+      }
+  }
+
+  int
+  base_text_renderer::rotation_to_mode (double rotation) const
+  {
+    // Wrap rotation to range [0, 360]
+    while (rotation < 0)
+      rotation += 360.0;
+    while (rotation > 360.0)
+      rotation -= 360.0;
+
+    if (rotation == 0.0)
+      return ROTATION_0;
+    else if (rotation == 90.0)
+      return ROTATION_90;
+    else if (rotation == 180.0)
+      return ROTATION_180;
+    else if (rotation == 270.0)
+      return ROTATION_270;
+    else
+      return ROTATION_0;
+  }
+
+  void
+  base_text_renderer::fix_bbox_anchor (Matrix& bbox, int halign,
+                                       int valign, int rot_mode,
+                                       bool handle_rotation) const
+  {
+    switch (halign)
+      {
+      case 1:
+        bbox(0) = -bbox(2)/2;
+        break;
+
+      case 2:
+        bbox(0) = -bbox(2);
+        break;
+
+      default:
+        bbox(0) = 0;
+        break;
+      }
+
+    switch (valign)
+      {
+      case 1:
+        bbox(1) = -bbox(3)/2;
+        break;
+
+      case 2:
+        bbox(1) = -bbox(3);
+        break;
+
+      case 3:
+        break;
+
+      case 4:
+        bbox(1) = -bbox(3)-bbox(1);
+        break;
+
+      default:
+        bbox(1) = 0;
+        break;
+      }
+
+    if (handle_rotation)
+      {
+        switch (rot_mode)
+          {
+          case ROTATION_90:
+            std::swap (bbox(0), bbox(1));
+            std::swap (bbox(2), bbox(3));
+            bbox(0) = -bbox(0)-bbox(2);
+            break;
+
+          case ROTATION_180:
+            bbox(0) = -bbox(0)-bbox(2);
+            bbox(1) = -bbox(1)-bbox(3);
+            break;
+
+          case ROTATION_270:
+            std::swap (bbox(0), bbox(1));
+            std::swap (bbox(2), bbox(3));
+            bbox(1) = -bbox(1)-bbox(3);
+            break;
+          }
+      }
+  }
+}
--- a/libinterp/corefcn/base-text-renderer.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/base-text-renderer.h	Sun May 16 09:44:35 2021 +0200
@@ -45,6 +45,14 @@
   {
   public:
 
+    enum
+    {
+      ROTATION_0   = 0,
+      ROTATION_90  = 1,
+      ROTATION_180 = 2,
+      ROTATION_270 = 3
+    };
+
     base_text_renderer (void) : text_processor () { }
 
     // No copying!
@@ -69,6 +77,9 @@
     set_font (const std::string& name, const std::string& weight,
               const std::string& angle, double size) = 0;
 
+    virtual bool
+    ok (void) { return true; };
+
     virtual octave_map
     get_system_fonts (void) = 0;
 
@@ -85,6 +96,15 @@
                      std::list<text_renderer::string>& lst,
                      Matrix& box, int halign, int valign, double rotation,
                      const caseless_str& interpreter = "tex") = 0;
+
+    void rotate_pixels (uint8NDArray& pixels, int rot_mode) const;
+
+    int rotation_to_mode (double rotation) const;
+
+    void fix_bbox_anchor (Matrix& bbox, int halign,
+                          int valign, int rot_mode,
+                          bool handle_rotation) const;
+
   };
 }
 
--- a/libinterp/corefcn/besselj.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/besselj.cc	Sun May 16 09:44:35 2021 +0200
@@ -737,12 +737,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %!assert (besselj (-alpha,x), jx, 100*eps)
 %!assert (bessely (-alpha,x), yx, 100*eps)
@@ -751,12 +751,12 @@
 %!assert (besselh (-alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (-alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! x *= -1;
 %! yx = -1.193199310178553861283790424 + 0.3421822624810469647226182835*I;
@@ -769,12 +769,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, odd order, positive and negative x
 %! alpha = 3;  x = 2.5;
@@ -790,12 +790,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %!assert (besselj (-alpha,x), -jx, 100*eps)
 %!assert (bessely (-alpha,x), -yx, 100*eps)
@@ -804,12 +804,12 @@
 %!assert (besselh (-alpha,1,x), -(jx + I*yx), 100*eps)
 %!assert (besselh (-alpha,2,x), -(jx - I*yx), 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), -jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), -yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), -(jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), -(jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), -jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), -yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), -(jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), -(jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! x *= -1;
 %! jx = -jx;
@@ -824,12 +824,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, fractional order, positive and negative x
 %!
@@ -846,12 +846,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! nix = 0.2119931212254662995364461998;
 %!
@@ -862,12 +862,12 @@
 %!assert (besselh (-alpha,1,x), -I*(jx + I*yx), 100*eps)
 %!assert (besselh (-alpha,2,x), I*(jx - I*yx), 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), -jx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), nix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), -I*(jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), I*(jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), -jx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), nix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), -I*(jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), I*(jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! x *= -1;
 %! jx *= -I;
@@ -882,12 +882,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, even order, complex x
 %!
@@ -904,12 +904,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %!assert (besselj (-alpha,x), jx, 100*eps)
 %!assert (bessely (-alpha,x), yx, 100*eps)
@@ -918,12 +918,12 @@
 %!assert (besselh (-alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (-alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, odd order, complex x
 %!
@@ -940,12 +940,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %!assert (besselj (-alpha,x), -jx, 100*eps)
 %!assert (bessely (-alpha,x), -yx, 100*eps)
@@ -954,12 +954,12 @@
 %!assert (besselh (-alpha,1,x), -(jx + I*yx), 100*eps)
 %!assert (besselh (-alpha,2,x), -(jx - I*yx), 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), -jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), -yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), -(jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), -(jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), -jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), -yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), -(jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), -(jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! ## Bessel functions, fractional order, complex x
 %!
@@ -976,12 +976,12 @@
 %!assert (besselh (alpha,1,x), jx + I*yx, 100*eps)
 %!assert (besselh (alpha,2,x), jx - I*yx, 100*eps)
 %!
-%!assert (besselj (alpha,x,1), jx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (alpha,x,1), ix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (alpha,x,1), jx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (alpha,x,1), ix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (alpha,1,x,1), (jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (alpha,2,x,1), (jx - I*yx)*exp (I*x), 100*eps)
 %!
 %! nix = 0.09822388691172060573913739253 - 0.7110230642207380127317227407*I;
 %!
@@ -992,12 +992,12 @@
 %!assert (besselh (-alpha,1,x), -I*(jx + I*yx), 100*eps)
 %!assert (besselh (-alpha,2,x), I*(jx - I*yx), 100*eps)
 %!
-%!assert (besselj (-alpha,x,1), yx*exp(-abs(imag(x))), 100*eps)
-%!assert (bessely (-alpha,x,1), -jx*exp(-abs(imag(x))), 100*eps)
-%!assert (besseli (-alpha,x,1), nix*exp(-abs(real(x))), 100*eps)
-%!assert (besselk (-alpha,x,1), kx*exp(x), 100*eps)
-%!assert (besselh (-alpha,1,x,1), -I*(jx + I*yx)*exp(-I*x), 100*eps)
-%!assert (besselh (-alpha,2,x,1), I*(jx - I*yx)*exp(I*x), 100*eps)
+%!assert (besselj (-alpha,x,1), yx*exp (-abs (imag (x))), 100*eps)
+%!assert (bessely (-alpha,x,1), -jx*exp (-abs (imag (x))), 100*eps)
+%!assert (besseli (-alpha,x,1), nix*exp (-abs (real (x))), 100*eps)
+%!assert (besselk (-alpha,x,1), kx*exp (x), 100*eps)
+%!assert (besselh (-alpha,1,x,1), -I*(jx + I*yx)*exp (-I*x), 100*eps)
+%!assert (besselh (-alpha,2,x,1), I*(jx - I*yx)*exp (I*x), 100*eps)
 
 Tests contributed by Robert T. Short.
 Tests are based on the properties and tables in A&S:
--- a/libinterp/corefcn/bsxfun.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/bsxfun.cc	Sun May 16 09:44:35 2021 +0200
@@ -540,7 +540,7 @@
                         {
                           have_NDArray = false;
                           C = result_NDArray;
-                          C = do_cat_op (C, tmp(0), ra_idx);
+                          C = octave::cat_op (C, tmp(0), ra_idx);
                         }
                       else if (tmp(0).isreal ())
                         result_NDArray.insert (tmp(0).array_value (), ra_idx);
@@ -560,7 +560,7 @@
                         {
                           have_FloatNDArray = false;
                           C = result_FloatNDArray;
-                          C = do_cat_op (C, tmp(0), ra_idx);
+                          C = octave::cat_op (C, tmp(0), ra_idx);
                         }
                       else if (tmp(0).isreal ())
                         result_FloatNDArray.insert
@@ -583,7 +583,7 @@
                         {                                               \
                           have_ ## T = false;                           \
                           C = result_ ## T;                             \
-                          C = do_cat_op (C, tmp(0), ra_idx);            \
+                          C = octave::cat_op (C, tmp(0), ra_idx);       \
                         }                                               \
                       else                                              \
                         result_ ## T .insert (tmp(0). EXTRACTOR ## _array_value (), ra_idx); \
@@ -601,7 +601,7 @@
                   else if BSXLOOP(uint32NDArray, "uint32", uint32)
                   else if BSXLOOP(uint64NDArray, "uint64", uint64)
                   else
-                    C = do_cat_op (C, tmp(0), ra_idx);
+                    C = octave::cat_op (C, tmp(0), ra_idx);
                 }
             }
 
@@ -637,12 +637,12 @@
 %! b = mean (a, 1);
 %! c = mean (a, 2);
 %! f = @minus;
-%!error (bsxfun (f))
-%!error (bsxfun (f, a))
-%!error (bsxfun (a, b))
-%!error (bsxfun (a, b, c))
-%!error (bsxfun (f, a, b, c))
-%!error (bsxfun (f, ones (4, 0), ones (4, 4)))
+%!error bsxfun (f)
+%!error bsxfun (f, a)
+%!error bsxfun (a, b)
+%!error bsxfun (a, b, c)
+%!error bsxfun (f, a, b, c)
+%!error bsxfun (f, ones (4, 0), ones (4, 4))
 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
@@ -655,12 +655,12 @@
 %! b = mean (a, 1);
 %! c = mean (a, 2);
 %! f = @minus;
-%!error (bsxfun (f))
-%!error (bsxfun (f, a))
-%!error (bsxfun (a, b))
-%!error (bsxfun (a, b, c))
-%!error (bsxfun (f, a, b, c))
-%!error (bsxfun (f, ones (4, 0), ones (4, 4)))
+%!error bsxfun (f)
+%!error bsxfun (f, a)
+%!error bsxfun (a, b)
+%!error bsxfun (a, b, c)
+%!error bsxfun (f, a, b, c)
+%!error bsxfun (f, ones (4, 0), ones (4, 4))
 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
@@ -673,12 +673,12 @@
 %! b = mean (a, 1);
 %! c = mean (a, 2);
 %! f = @minus;
-%!error (bsxfun (f))
-%!error (bsxfun (f, a))
-%!error (bsxfun (a, b))
-%!error (bsxfun (a, b, c))
-%!error (bsxfun (f, a, b, c))
-%!error (bsxfun (f, ones (4, 0), ones (4, 4)))
+%!error bsxfun (f)
+%!error bsxfun (f, a)
+%!error bsxfun (a, b)
+%!error bsxfun (a, b, c)
+%!error bsxfun (f, a, b, c)
+%!error bsxfun (f, ones (4, 0), ones (4, 4))
 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
@@ -690,12 +690,12 @@
 %! b = a (1, :);
 %! c = a (:, 1);
 %! f = @(x, y) x == y;
-%!error (bsxfun (f))
-%!error (bsxfun (f, a))
-%!error (bsxfun (a, b))
-%!error (bsxfun (a, b, c))
-%!error (bsxfun (f, a, b, c))
-%!error (bsxfun (f, ones (4, 0), ones (4, 4)))
+%!error bsxfun (f)
+%!error bsxfun (f, a)
+%!error bsxfun (a, b)
+%!error bsxfun (a, b, c)
+%!error bsxfun (f, a, b, c)
+%!error bsxfun (f, ones (4, 0), ones (4, 4))
 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0, "logical"))
 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), ones (4, 4, "logical"))
 %!assert (bsxfun (f, a, b), a == repmat (b, 4, 1))
@@ -707,7 +707,7 @@
 %! c = mean (a, 2);
 %! d = mean (a, 3);
 %! f = @minus;
-%!error (bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4])))
+%!error bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4]))
 %!assert (bsxfun (f, ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
 %!assert (bsxfun (f, ones ([4, 4, 0]), ones ([4, 1, 1])), zeros ([4, 4, 0]))
 %!assert (bsxfun (f, ones ([1, 4, 4]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
--- a/libinterp/corefcn/call-stack.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/call-stack.cc	Sun May 16 09:44:35 2021 +0200
@@ -829,7 +829,7 @@
 
   void call_stack::clear_global_variable_regexp (const std::string& pattern)
   {
-    octave::regexp pat (pattern);
+    regexp pat (pattern);
 
     for (auto& nm_ov : m_global_values)
       {
@@ -974,14 +974,13 @@
         // implement this option there so that the variables are never
         // stored at all.
 
-        unwind_protect frame;
-
         // Set up temporary scope.
 
         symbol_scope tmp_scope ("$dummy_scope$");
 
         push (tmp_scope);
-        frame.add_method (*this, &call_stack::pop);
+
+        unwind_action restore_scope ([=] (void) { pop (); });
 
         feval ("load", octave_value (file_name), 0);
 
@@ -1031,7 +1030,7 @@
 
         if (have_regexp)
           {
-            octave::regexp pat (pattern);
+            regexp pat (pattern);
 
             for (auto& nm_ov : m_global_values)
               {
@@ -1168,7 +1167,7 @@
 %! max_stack_depth (orig_val);
 %! assert (max_stack_depth (), orig_val);
 
-%!error (max_stack_depth (1, 2))
+%!error max_stack_depth (1, 2)
 */
 
 DEFMETHOD (who, interp, args, nargout,
--- a/libinterp/corefcn/cdisplay.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/cdisplay.h	Sun May 16 09:44:35 2021 +0200
@@ -32,7 +32,7 @@
 extern "C" {
 #endif
 
-OCTINTERP_API extern const char *
+extern OCTINTERP_API const char *
 octave_get_display_info (const char *dpy_name, int *ht, int *wd, int *dp,
                          double *rx, double *ry, int *dpy_avail);
 
--- a/libinterp/corefcn/cellfun.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/cellfun.cc	Sun May 16 09:44:35 2021 +0200
@@ -1011,7 +1011,7 @@
 %!  __errmsg = S.message;
 %!  retval = NaN;
 %!endfunction
-%!test <58411>
+%!test <*58411>
 %! global __errmsg;
 %! assert (cellfun (@factorial, {1, 2, -3}, "ErrorHandler", @__errfcn), [1, 2, NaN]);
 %! assert (! isempty (__errmsg));
@@ -1260,7 +1260,7 @@
               for (int j = 0; j < nargin; j++)
                 {
                   if (mask[j])
-                    inputlist.xelem (j) = inputs[j].do_index_op (idx_list);
+                    inputlist.xelem (j) = inputs[j].index_op (idx_list);
                 }
 
               const octave_value_list tmp
@@ -1352,7 +1352,7 @@
               for (int j = 0; j < nargin; j++)
                 {
                   if (mask[j])
-                    inputlist.xelem (j) = inputs[j].do_index_op (idx_list);
+                    inputlist.xelem (j) = inputs[j].index_op (idx_list);
                 }
 
               const octave_value_list tmp
@@ -1580,14 +1580,14 @@
 %! A = arrayfun (@(x,y) x.a:y.a, a, b, "UniformOutput", false);
 %! assert (isequal (A, {[1.1, 2.1, 3.1]}));
 %!test
-%! A = arrayfun (@(x) mat2str(x), "a", "ErrorHandler", @__arrayfunerror);
+%! A = arrayfun (@(x) mat2str (x), "a", "ErrorHandler", @__arrayfunerror);
 %! assert (isfield (A, "identifier"), true);
 %! assert (isfield (A, "message"), true);
 %! assert (isfield (A, "index"), true);
 %! assert (isempty (A.message), false);
 %! assert (A.index, 1);
 %!test  # Overwriting setting of "UniformOutput" true
-%! A = arrayfun (@(x) mat2str(x), "a", "UniformOutput", true, ...
+%! A = arrayfun (@(x) mat2str (x), "a", "UniformOutput", true, ...
 %!               "ErrorHandler", @__arrayfunerror);
 %! assert (isfield (A, "identifier"), true);
 %! assert (isfield (A, "message"), true);
@@ -1921,14 +1921,14 @@
 {
   octave_idx_type nidx = (idim < nd ? d[idim].numel () : 1);
   if (nidx == 1)
-    idx[0] = idx_vector::colon;
+    idx[0] = octave::idx_vector::colon;
   else
     {
       octave_idx_type l = 0;
       for (octave_idx_type i = 0; i < nidx; i++)
         {
           octave_idx_type u = l + d[idim](i);
-          idx[i] = idx_vector (l, u);
+          idx[i] = octave::idx_vector (l, u);
           l = u;
         }
     }
@@ -1966,17 +1966,17 @@
       for (octave_idx_type i = 0; i < nidx; i++)
         {
           octave_idx_type u = l + d[ivec](i);
-          retval.xelem (i) = a.index (idx_vector (l, u));
+          retval.xelem (i) = a.index (octave::idx_vector (l, u));
           l = u;
         }
     }
   else
     {
       // General 2D case.  Use 2D indexing.
-      OCTAVE_LOCAL_BUFFER (idx_vector, ridx, nridx);
+      OCTAVE_LOCAL_BUFFER (octave::idx_vector, ridx, nridx);
       prepare_idx (ridx, 0, nd, d);
 
-      OCTAVE_LOCAL_BUFFER (idx_vector, cidx, ncidx);
+      OCTAVE_LOCAL_BUFFER (octave::idx_vector, cidx, ncidx);
       prepare_idx (cidx, 1, nd, d);
 
       for (octave_idx_type j = 0; j < ncidx; j++)
@@ -2015,8 +2015,8 @@
 
   retval.clear (rdv);
 
-  OCTAVE_LOCAL_BUFFER (idx_vector, xidx, idxtot);
-  OCTAVE_LOCAL_BUFFER (idx_vector *, idx, nd);
+  OCTAVE_LOCAL_BUFFER (octave::idx_vector, xidx, idxtot);
+  OCTAVE_LOCAL_BUFFER (octave::idx_vector *, idx, nd);
 
   idxtot = 0;
   for (int i = 0; i < nd; i++)
@@ -2027,8 +2027,8 @@
     }
 
   OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, ridx, nd, 0);
-  Array<idx_vector> ra_idx
-    (dim_vector (1, std::max (nd, a.ndims ())), idx_vector::colon);
+  Array<octave::idx_vector> ra_idx
+    (dim_vector (1, std::max (nd, a.ndims ())), octave::idx_vector::colon);
 
   for (octave_idx_type j = 0; j < retval.numel (); j++)
     {
@@ -2101,7 +2101,7 @@
       for (int i = 0; i < nd; i++)
         ra_idx(i) = idx[i][ridx[i]];
 
-      retval.xelem (j) = a.do_index_op (ra_idx);
+      retval.xelem (j) = a.index_op (ra_idx);
 
       rdv.increment_index (ridx);
     }
@@ -2301,7 +2301,7 @@
                             || (dim == 1 && array.rows () == 1)))
     {
       for (octave_idx_type i = 0; i < n; i++)
-        retval.xelem (i) = array.index (idx_vector (lb(i) - 1, ub(i)));
+        retval.xelem (i) = array.index (octave::idx_vector (lb(i) - 1, ub(i)));
     }
   else
     {
@@ -2311,11 +2311,11 @@
         dim = dv.first_non_singleton ();
       ndims = std::max (ndims, dim + 1);
 
-      Array<idx_vector> idx (dim_vector (ndims, 1), idx_vector::colon);
+      Array<octave::idx_vector> idx (dim_vector (ndims, 1), octave::idx_vector::colon);
 
       for (octave_idx_type i = 0; i < n; i++)
         {
-          idx(dim) = idx_vector (lb(i) - 1, ub(i));
+          idx(dim) = octave::idx_vector (lb(i) - 1, ub(i));
           retval.xelem (i) = array.index (idx);
         }
     }
@@ -2435,8 +2435,8 @@
       octave_value_list idx (ndims, octave_value::magic_colon_t);
       for (octave_idx_type i = 0; i < n; i++)
         {
-          idx(dim) = Range (lb(i), ub(i));
-          retcell.xelem (i) = x.do_index_op (idx);
+          idx(dim) = octave::range<double> (lb(i), ub(i));
+          retcell.xelem (i) = x.index_op (idx);
         }
     }
 
@@ -2487,7 +2487,7 @@
 
       octave_value tmp = x(i);
 
-      y.xelem (i) = tmp.do_index_op (idx);
+      y.xelem (i) = tmp.index_op (idx);
     }
 
   return octave_value (y);
--- a/libinterp/corefcn/chol.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/chol.cc	Sun May 16 09:44:35 2021 +0200
@@ -581,11 +581,11 @@
 %! sparse_chol2inv (B, eps*100);
 
 %!testif HAVE_CHOLMOD
-%! C = gallery("tridiag", 5);
+%! C = gallery ("tridiag", 5);
 %! sparse_chol2inv (C, eps*10);
 
 %!testif HAVE_CHOLMOD
-%! D = gallery("wathen", 1, 1);
+%! D = gallery ("wathen", 1, 1);
 %! sparse_chol2inv (D, eps*10^4);
 
 */
--- a/libinterp/corefcn/colamd.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/colamd.cc	Sun May 16 09:44:35 2021 +0200
@@ -680,21 +680,31 @@
   octave_idx_type *ridx = nullptr;
   octave_idx_type *cidx = nullptr;
 
-  if (! args(0).issparse ())
-    error ("etree: S must be a sparse matrix");
+  SparseComplexMatrix scm;
+  SparseBoolMatrix sbm;
+  SparseMatrix sm;
 
   if (args(0).iscomplex ())
     {
-      SparseComplexMatrix scm = args(0).sparse_complex_matrix_value ();
+      scm = args(0).sparse_complex_matrix_value ();
 
       n_row = scm.rows ();
       n_col = scm.cols ();
       ridx = scm.xridx ();
       cidx = scm.xcidx ();
     }
+  else if (args(0).islogical ())
+    {
+      sbm = args(0).sparse_bool_matrix_value ();
+
+      n_row = sbm.rows ();
+      n_col = sbm.cols ();
+      ridx = sbm.xridx ();
+      cidx = sbm.xcidx ();
+    }
   else
     {
-      SparseMatrix sm = args(0).sparse_matrix_value ();
+      sm = args(0).sparse_matrix_value ();
 
       n_row = sm.rows ();
       n_col = sm.cols ();
@@ -738,7 +748,7 @@
   NDArray tree (dim_vector (1, n_col));
   for (octave_idx_type i = 0; i < n_col; i++)
     // We flag a root with n_col while Matlab does it with zero
-    // Convert for matlab compatible output
+    // Convert for Matlab-compatible output
     if (etree[i] == n_col)
       tree(i) = 0;
     else
@@ -763,12 +773,13 @@
 }
 
 /*
-%!assert (etree (speye (2)), [0, 0]);
-%!assert (etree (gallery ("poisson", 16)), [2:256, 0]);
+%!assert (etree (sparse ([1,2], [1,2], [1,1], 2, 2)), [0, 0])
+%!assert (etree (sparse ([1,2], [1,2], [true, true], 2, 2)), [0, 0])
+%!assert (etree (sparse ([1,2], [1,2], [i,i], 2, 2)), [0, 0])
+%!assert (etree (gallery ("poisson", 16)), [2:256, 0])
 
-%!error etree ()
-%!error etree (1, 2, 3)
-%!error <S must be a sparse matrix> etree ([1, 2; 3, 4])
+%!error <Invalid call> etree ()
+%!error <Invalid call> etree (1, 2, 3)
 %!error <TYP must be a string> etree (speye (2), 3)
 %!error <is not square> etree (sprand (2, 4, .25))
 */
--- a/libinterp/corefcn/conv2.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/conv2.cc	Sun May 16 09:44:35 2021 +0200
@@ -550,18 +550,18 @@
 %!    925  1976  2363  1971  1636  1600  1844  2239  1664   626
 %!    372  1133  1558  1687  1570  1401  1243  1122   883   264
 %!     60   270   556   857  1024   870   569   282    66     0];
-%!assert (convn(a, b, "full"), c)
-%!assert (convn(a, b, "same"), c(3:6,2:9,2:5,:))
-%!assert (convn(a, b, "valid"), c(4,3:8,3:4,:))
+%!assert (convn (a, b, "full"), c)
+%!assert (convn (a, b, "same"), c(3:6,2:9,2:5,:))
+%!assert (convn (a, b, "valid"), c(4,3:8,3:4,:))
 
 ## test correct class
-%!assert (class (convn (rand(5), rand(3))), "double")
-%!assert (class (convn (rand(5, "single"), rand(3))), "single")
-%!assert (class (convn (rand(5), rand(3, "single"))), "single")
-%!assert (class (convn (true (5), rand(3))), "double")
-%!assert (class (convn (true (5), rand(3, "single"))), "single")
-%!assert (class (convn (ones(5, "uint8"), rand(3))), "double")
-%!assert (class (convn (rand (3, "single"), ones(5, "uint8"))), "single")
+%!assert (class (convn (rand (5), rand (3))), "double")
+%!assert (class (convn (rand (5, "single"), rand (3))), "single")
+%!assert (class (convn (rand (5), rand (3, "single"))), "single")
+%!assert (class (convn (true (5), rand (3))), "double")
+%!assert (class (convn (true (5), rand (3, "single"))), "single")
+%!assert (class (convn (ones (5, "uint8"), rand (3))), "double")
+%!assert (class (convn (rand (3, "single"), ones (5, "uint8"))), "single")
 
 %!error convn ()
 %!error convn (1)
--- a/libinterp/corefcn/daspk.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/daspk.cc	Sun May 16 09:44:35 2021 +0200
@@ -82,9 +82,9 @@
         {
           tmp = octave::feval (daspk_fcn, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "daspk");
+          err_user_supplied_eval (ee, "daspk");
         }
 
       int tlen = tmp.length ();
@@ -132,9 +132,9 @@
         {
           tmp = octave::feval (daspk_jac, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "daspk");
+          err_user_supplied_eval (ee, "daspk");
         }
 
       int tlen = tmp.length ();
@@ -269,9 +269,7 @@
 
   octave_value_list retval (4);
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/dasrt.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/dasrt.cc	Sun May 16 09:44:35 2021 +0200
@@ -83,9 +83,9 @@
         {
           tmp = octave::feval (dasrt_fcn, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "dasrt");
+          err_user_supplied_eval (ee, "dasrt");
         }
 
       if (tmp.empty () || ! tmp(0).is_defined ())
@@ -124,9 +124,9 @@
         {
           tmp = octave::feval (dasrt_cf, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "dasrt");
+          err_user_supplied_eval (ee, "dasrt");
         }
 
       if (tmp.empty () || ! tmp(0).is_defined ())
@@ -170,9 +170,9 @@
         {
           tmp = octave::feval (dasrt_jac, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "dasrt");
+          err_user_supplied_eval (ee, "dasrt");
         }
 
       int tlen = tmp.length ();
@@ -348,9 +348,7 @@
 
   octave_value_list retval (5);
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/dassl.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/dassl.cc	Sun May 16 09:44:35 2021 +0200
@@ -81,9 +81,9 @@
         {
           tmp = octave::feval (dassl_fcn, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "dassl");
+          err_user_supplied_eval (ee, "dassl");
         }
 
       int tlen = tmp.length ();
@@ -131,9 +131,9 @@
         {
           tmp = octave::feval (dassl_jac, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "dassl");
+          err_user_supplied_eval (ee, "dassl");
         }
 
       int tlen = tmp.length ();
@@ -269,9 +269,7 @@
 
   octave_value_list retval (4);
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/data.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/data.cc	Sun May 16 09:44:35 2021 +0200
@@ -889,7 +889,7 @@
 %!assert (mod (uint8 (5), uint8 (4)), uint8 (1))
 %!assert (mod (uint8 ([1:5]), uint8 (4)), uint8 ([1,2,3,0,1]))
 %!assert (mod (uint8 ([1:5]), uint8 (0)), uint8 ([1:5]))
-%!error (mod (uint8 (5), int8 (4)))
+%!error mod (uint8 (5), int8 (4))
 
 ## mixed integer/real types
 %!assert (mod (uint8 (5), 4), uint8 (1))
@@ -1040,8 +1040,8 @@
 @end group
 @end example
 
-See @code{sum} for an explanation of the optional parameters @qcode{"native"}
-and @qcode{"double"}.
+For an explanation of the optional parameters @qcode{"native"} and
+@qcode{"double"}, @pxref{XREFsum,,@code{sum}}.
 @seealso{sum, cumprod}
 @end deftypefn */)
 {
@@ -1648,9 +1648,9 @@
         {
           result = octave::feval (fcn, ovl (ov), 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          error (e, "conversion from %s to %s failed", dtype.c_str (),
+          error (ee, "conversion from %s to %s failed", dtype.c_str (),
                  cname.c_str ());
         }
 
@@ -1676,9 +1676,9 @@
         {
           result = octave::feval (fcn, ovl (ov), 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          error (e, "%s constructor failed for %s argument", dtype.c_str (),
+          error (ee, "%s constructor failed for %s argument", dtype.c_str (),
                  cname.c_str ());
         }
 
@@ -1715,9 +1715,9 @@
         {
           tmp2 = octave::feval (fcn, ovl, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          error (e, "%s/%s method failed", dtype.c_str (), cattype.c_str ());
+          error (ee, "%s/%s method failed", dtype.c_str (), cattype.c_str ());
         }
 
       if (tmp2.empty ())
@@ -1955,7 +1955,7 @@
               // Can't fast return here to skip empty matrices as something
               // like cat (1,[],single ([])) must return an empty matrix of
               // the right type.
-              tmp = do_cat_op (tmp, args(j), ra_idx);
+              tmp = octave::cat_op (tmp, args(j), ra_idx);
 
               dim_vector dv_tmp = args(j).dims ();
 
@@ -2213,8 +2213,8 @@
 
 %!error horzcat (struct ("foo", "bar"), cell (1))
 
-%!test <*39041> assert (class (horzcat (cell(0), struct())), "cell")
-%!test <51086> assert (class (horzcat (struct(), cell(0))), "struct")
+%!test <*39041> assert (class (horzcat (cell (0), struct ())), "cell")
+%!test <51086> assert (class (horzcat (struct (), cell (0))), "struct")
 */
 
 DEFUN (vertcat, args, ,
@@ -2796,10 +2796,10 @@
 %!assert (nnz (-5:0), 5)
 %!assert (nnz (-5:5), 10)
 %!assert (nnz (-2:1:2), 4)
-%!assert (nnz (-2+eps(2):1:2), 5)
-%!assert (nnz (-2-eps(2):1:2), 5)
-%!assert (nnz (-2:1+eps(1):2), 5)
-%!assert (nnz (-2:1-eps(1):2), 5)
+%!assert (nnz (-2+eps (2):1:2), 5)
+%!assert (nnz (-2-eps (2):1:2), 5)
+%!assert (nnz (-2:1+eps (1):2), 5)
+%!assert (nnz (-2:1-eps (1):2), 5)
 %!assert (nnz ([1:5] * 0), 0)
 %!assert (nnz ([-5:-1] * 0), 0)
 %!assert (nnz ([-1:1] * 0), 0)
@@ -3631,7 +3631,7 @@
 
 /*
 ## Debian bug #706376
-%!assert (isempty (speye(2^16)), false)
+%!assert (isempty (speye (2^16)), false)
 */
 
 DEFUN (isnumeric, args, ,
@@ -3944,6 +3944,8 @@
   oct_data_conv::data_type dt = oct_data_conv::dt_double;
 
   dim_vector dims (1, 1);
+  bool issparse = false;
+  bool iscomplex = false;
 
   if (nargin > 0 && args(nargin-1).is_string ())
     {
@@ -3953,6 +3955,16 @@
       dt = oct_data_conv::string_to_data_type (nm);
     }
 
+  if (nargin > 1 && args(nargin-2).is_string ()
+      && args(nargin-2).string_value () == "like")
+    {
+      std::string nm = args(nargin-1).class_name ();
+      issparse = args(nargin-1).issparse ();
+      iscomplex = args(nargin-1).iscomplex ();
+      nargin -= 2;
+      dt = oct_data_conv::string_to_data_type (nm);
+    }
+
   switch (nargin)
     {
     case 0:
@@ -3982,6 +3994,33 @@
   // Note that automatic narrowing will handle conversion from
   // NDArray to scalar.
 
+  if (issparse)
+    {
+      if (dims.ndims () > 2)
+        error ("%s: sparse ND arrays not supported.", fcn);
+
+      switch (dt)
+        {
+        case oct_data_conv::dt_double:
+          if (iscomplex)
+            retval = SparseComplexMatrix (dims(0), dims(1), Complex (val, 0));
+          else
+            retval = SparseMatrix (dims(0), dims(1), static_cast<double> (val));
+          break;
+
+        case oct_data_conv::dt_logical:
+          retval = SparseBoolMatrix (dims(0), dims(1), static_cast<bool> (val));
+          break;
+
+        default:
+          // FIXME: It shouldn't be possible to ever reach this.
+          error ("%s: invalid class name for sparse", fcn);
+          break;
+        }
+
+      return retval;
+    }
+
   switch (dt)
     {
     case oct_data_conv::dt_int8:
@@ -4017,16 +4056,25 @@
       break;
 
     case oct_data_conv::dt_single:
-      retval = FloatNDArray (dims, val);
+      if (iscomplex)
+        retval = FloatComplexNDArray (dims, val);
+      else
+        retval = FloatNDArray (dims, val);
       break;
 
     case oct_data_conv::dt_double:
-      {
-        if (dims.ndims () == 2 && dims(0) == 1)
-          retval = Range (static_cast<double> (val), 0.0, dims(1));
-        else
-          retval = NDArray (dims, val);
-      }
+      if (iscomplex)
+        retval = ComplexNDArray (dims, Complex (val, 0));
+      else if (dims.ndims () == 2 && dims(0) == 1)
+        {
+          // FIXME: If this optimization provides a significant
+          // benefit, then maybe there should be a special storage
+          // type for constant value arrays.
+          double dval = static_cast<double> (val);
+          retval = octave::range<double>::make_constant (dval, dims(1));
+        }
+      else
+        retval = NDArray (dims, val);
       break;
 
     case oct_data_conv::dt_logical:
@@ -4052,6 +4100,8 @@
   oct_data_conv::data_type dt = oct_data_conv::dt_double;
 
   dim_vector dims (1, 1);
+  bool issparse = false;
+  bool iscomplex = false;
 
   if (nargin > 0 && args(nargin-1).is_string ())
     {
@@ -4061,6 +4111,20 @@
       dt = oct_data_conv::string_to_data_type (nm);
     }
 
+  if (nargin > 1 && args(nargin-2).is_string ()
+      && args(nargin-2).string_value () == "like"
+      && (std::string(fcn) ==  "Inf"
+          || std::string(fcn) == "NaN" || std::string(fcn) == "NA"))
+    {
+      if (! args(nargin-1).isfloat ())
+        error ("%s: input followed by 'like' must be floating point", fcn);
+      std::string nm = args(nargin-1).class_name ();
+      issparse = args(nargin-1).issparse ();
+      iscomplex = args(nargin-1).iscomplex ();
+      nargin -= 2;
+      dt = oct_data_conv::string_to_data_type (nm);
+    }
+
   switch (nargin)
     {
     case 0:
@@ -4087,15 +4151,37 @@
   // Note that automatic narrowing will handle conversion from
   // NDArray to scalar.
 
+  if (issparse)
+    {
+      if (dims.ndims () > 2)
+        error ("%s: sparse ND arrays not supported", fcn);
+
+      if (iscomplex)
+        retval = SparseComplexMatrix (dims(0), dims(1), Complex (val, 0));
+      else
+        retval = SparseMatrix (dims(0), dims(1), static_cast<double> (val));
+
+      return retval;
+    }
+
   switch (dt)
     {
     case oct_data_conv::dt_single:
-      retval = FloatNDArray (dims, fval);
+      if (iscomplex)
+        retval = FloatComplexNDArray (dims, fval);
+      else
+        retval = FloatNDArray (dims, fval);
       break;
 
     case oct_data_conv::dt_double:
-      if (dims.ndims () == 2 && dims(0) == 1 && octave::math::isfinite (val))
-        retval = Range (val, 0.0, dims(1));  // Packed form
+      if (iscomplex)
+        retval = ComplexNDArray (dims, Complex (val, 0));
+      else if (dims.ndims () == 2 && dims(0) == 1
+               && octave::math::isfinite (val))
+        // FIXME: If this optimization provides a significant benefit,
+        // then maybe there should be a special storage type for
+        // constant value arrays.
+        retval = octave::range<double>::make_constant (val, dims(1));
       else
         retval = NDArray (dims, val);
       break;
@@ -4161,7 +4247,10 @@
 
     case oct_data_conv::dt_double:
       if (dims.ndims () == 2 && dims(0) == 1 && octave::math::isfinite (val))
-        retval = Range (val, 0.0, dims(1));  // Packed form
+        // FIXME: If this optimization provides a significant benefit,
+        // then maybe there should be a special storage type for
+        // constant value arrays.
+        retval = octave::range<double>::make_constant (val, dims(1));
       else
         retval = NDArray (dims, val);
       break;
@@ -4248,6 +4337,30 @@
 
   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 ());
+    }
+
+  bool issparse = false;
+
+  if (nargin > 1 && args(nargin-2).is_string ()
+      && args(nargin-2).string_value () == "like")
+  {
+    if (! args(nargin-1).islogical ())
+      error (R"(%s: input followed by "like" must be logical)", fcn);
+
+    issparse = args(nargin-1).issparse ();
+    nargin -= 2;
+  }
+
   switch (nargin)
     {
     case 0:
@@ -4274,18 +4387,27 @@
   // Note that automatic narrowing will handle conversion from
   // NDArray to scalar.
 
-  retval = boolNDArray (dims, val);
+  if (issparse)
+    {
+      if (dims.ndims () > 2)
+        error ("%s: sparse ND arrays not supported", fcn);
+
+      retval = SparseBoolMatrix (dims(0), dims(1), val);
+    }
+  else
+    retval = boolNDArray (dims, val);
 
   return retval;
 }
 
 DEFUN (ones, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {} ones (@var{n})
-@deftypefnx {} {} ones (@var{m}, @var{n})
-@deftypefnx {} {} ones (@var{m}, @var{n}, @var{k}, @dots{})
-@deftypefnx {} {} ones ([@var{m} @var{n} @dots{}])
-@deftypefnx {} {} ones (@dots{}, @var{class})
+@deftypefn  {} {@var{val} =} ones (@var{n})
+@deftypefnx {} {@var{val} =} ones (@var{m}, @var{n})
+@deftypefnx {} {@var{val} =} ones (@var{m}, @var{n}, @var{k}, @dots{})
+@deftypefnx {} {@var{val} =} ones ([@var{m} @var{n} @dots{}])
+@deftypefnx {} {@var{val} =} ones (@dots{}, "@var{like}", @var{var}))
+@deftypefnx {} {@var{val} =} ones (@dots{}, @var{class})
 Return a matrix or N-dimensional array whose elements are all 1.
 
 If invoked with a single scalar integer argument @var{n}, return a square
@@ -4301,6 +4423,9 @@
 val_matrix = val * ones (m, n)
 @end example
 
+If a variable @var{var} is specified after @qcode{"like"}, the output @var{val}
+will have the same data type, complexity, and sparsity as @var{var}.
+
 The optional argument @var{class} specifies the class of the return array
 and defaults to double.  For example:
 
@@ -4329,12 +4454,21 @@
 %!assert (ones (3, 2, "int8"), int8 ([1, 1; 1, 1; 1, 1]))
 %!assert (size (ones (3, 4, 5, "int8")), [3, 4, 5])
 
+%!assert (ones (2, 2, "like", double (1)), double ([1, 1; 1, 1]))
+%!assert (ones (2, 2, "like", complex (ones (2, 2))), [1, 1; 1, 1])
+%!assert (ones (1, 2, "like", single (1)), single ([1, 1]))
+%!assert (ones (1, "like", single (1i)), single (1))
+%!assert (ones (2, 2, "like", uint8 (8)), uint8 ([1, 1; 1, 1]))
+%!assert (ones (2, "like", speye (2)), sparse ([1, 1; 1, 1]))
+%!assert (ones (2, "like", sparse (1i)), sparse (complex ([1, 1; 1, 1])))
+
 %!assert (size (ones (1, -2, 2)), [1, 0, 2])
 
 ## Test input validation
 %!error <conversion of 1.1 .*failed> ones (1.1)
 %!error <conversion of 1.1 .*failed> ones (1, 1.1)
 %!error <conversion of 1.1 .*failed> ones ([1, 1.1])
+%!error <sparse ND .* not supported> ones (3, 3, 3, "like", speye (1))
 */
 
 /*
@@ -4356,11 +4490,12 @@
 
 DEFUN (zeros, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {} zeros (@var{n})
-@deftypefnx {} {} zeros (@var{m}, @var{n})
-@deftypefnx {} {} zeros (@var{m}, @var{n}, @var{k}, @dots{})
-@deftypefnx {} {} zeros ([@var{m} @var{n} @dots{}])
-@deftypefnx {} {} zeros (@dots{}, @var{class})
+@deftypefn  {} {@var{val} =} zeros (@var{n})
+@deftypefnx {} {@var{val} =} zeros (@var{m}, @var{n})
+@deftypefnx {} {@var{val} =} zeros (@var{m}, @var{n}, @var{k}, @dots{})
+@deftypefnx {} {@var{val} =} zeros ([@var{m} @var{n} @dots{}])
+@deftypefnx {} {@var{val} =} zeros (@dots{}, "@var{like}", @var{var}))
+@deftypefnx {} {@var{val} =} zeros (@dots{}, @var{class})
 Return a matrix or N-dimensional array whose elements are all 0.
 
 If invoked with a single scalar integer argument, return a square
@@ -4369,6 +4504,9 @@
 If invoked with two or more scalar integer arguments, or a vector of integer
 values, return an array with the given dimensions.
 
+If a variable @var{var} is specified after @qcode{"like"}, the output @var{val}
+will have the same data type, complexity, and sparsity as @var{var}.
+
 The optional argument @var{class} specifies the class of the return array
 and defaults to double.  For example:
 
@@ -4387,6 +4525,13 @@
 %!assert (zeros (3, 2), [0, 0; 0, 0; 0, 0])
 %!assert (size (zeros (3, 4, 5)), [3, 4, 5])
 
+%!assert (zeros (2, 2, "like", double (1)), double ([0, 0; 0, 0]))
+%!assert (zeros (2, 2, "like", complex (ones (2, 2))), [0, 0; 0, 0])
+%!assert (zeros (1, 2, "like", single (1)), single ([0, 0]))
+%!assert (zeros (1, 2, "like", single (1i)), single ([0, 0]))
+%!assert (zeros (2, 2, "like", uint8 (8)), uint8 ([0, 0; 0, 0]))
+%!assert (zeros (2, "like", speye (2)), sparse ([0, 0; 0, 0]))
+
 %!assert (zeros (3, "single"), single ([0, 0, 0; 0, 0, 0; 0, 0, 0]))
 %!assert (zeros (2, 3, "single"), single ([0, 0, 0; 0, 0, 0]))
 %!assert (zeros (3, 2, "single"), single ([0, 0; 0, 0; 0, 0]))
@@ -4404,6 +4549,7 @@
 %!error <conversion of 1.1 .*failed> zeros ([1, 1.1])
 %!error <conversion of 1.1 .*failed> zeros (1, 1.1, 2)
 %!error <conversion of 1.1 .*failed> zeros ([1, 1.1, 2])
+%!error <sparse ND .* not supported> zeros (3, 3, 3, "like", speye (1))
 */
 
 DEFUN (Inf, args, ,
@@ -4451,20 +4597,30 @@
 DEFALIAS (inf, Inf);
 
 /*
-%!assert (inf (3), [Inf, Inf, Inf; Inf, Inf, Inf; Inf, Inf, Inf])
-%!assert (inf (2, 3), [Inf, Inf, Inf; Inf, Inf, Inf])
-%!assert (inf (3, 2), [Inf, Inf; Inf, Inf; Inf, Inf])
-%!assert (size (inf (3, 4, 5)), [3, 4, 5])
-
-%!assert (inf (3, "single"), single ([Inf, Inf, Inf; Inf, Inf, Inf; Inf, Inf, Inf]))
-%!assert (inf (2, 3, "single"), single ([Inf, Inf, Inf; Inf, Inf, Inf]))
-%!assert (inf (3, 2, "single"), single ([Inf, Inf; Inf, Inf; Inf, Inf]))
+%!assert (Inf (3), [Inf, Inf, Inf; Inf, Inf, Inf; Inf, Inf, Inf])
+%!assert (Inf (2, 3), [Inf, Inf, Inf; Inf, Inf, Inf])
+%!assert (Inf (3, 2), [Inf, Inf; Inf, Inf; Inf, Inf])
+%!assert (size (Inf (3, 4, 5)), [3, 4, 5])
+
+%!assert (Inf (3, "single"), single ([Inf, Inf, Inf; Inf, Inf, Inf; Inf, Inf, Inf]))
+%!assert (Inf (2, 3, "single"), single ([Inf, Inf, Inf; Inf, Inf, Inf]))
+%!assert (Inf (3, 2, "single"), single ([Inf, Inf; Inf, Inf; Inf, Inf]))
 %!assert (size (inf (3, 4, 5, "single")), [3, 4, 5])
 
-%!error (inf (3, "int8"))
-%!error (inf (2, 3, "int8"))
-%!error (inf (3, 2, "int8"))
-%!error (inf (3, 4, 5, "int8"))
+%!assert (Inf (2, 2, "like", speye (2)), sparse ([Inf, Inf; Inf, Inf]))
+%!assert (Inf (2, 2, "like", complex (ones (2, 2))), [Inf, Inf; Inf, Inf])
+%!assert (Inf (2, 2, "like", double (1)), double ([Inf, Inf; Inf, Inf]))
+%!assert (Inf (3, 3, "like", single (1)), single ([Inf, Inf, Inf; Inf, Inf, Inf; Inf, Inf, Inf]))
+%!assert (Inf (2, "like", single (1i)), single ([Inf, Inf; Inf, Inf]))
+
+%!error Inf (3, "like", int8 (1))
+
+%!error Inf (3, "int8")
+%!error Inf (2, 3, "int8")
+%!error Inf (3, 2, "int8")
+%!error Inf (3, 4, 5, "int8")
+%!error <input .* floating> Inf (3, 3, "like", true)
+%!error <input .* floating> Inf (2, "like", uint8 (1))
 */
 
 DEFUN (NaN, args, ,
@@ -4472,11 +4628,12 @@
 @c List other form of function in documentation index
 @findex nan
 
-@deftypefn  {} {} NaN
-@deftypefnx {} {} NaN (@var{n})
-@deftypefnx {} {} NaN (@var{n}, @var{m})
-@deftypefnx {} {} NaN (@var{n}, @var{m}, @var{k}, @dots{})
-@deftypefnx {} {} NaN (@dots{}, @var{class})
+@deftypefn  {} {@var{val} =} NaN
+@deftypefnx {} {@var{val} =} NaN (@var{n})
+@deftypefnx {} {@var{val} =} NaN (@var{n}, @var{m})
+@deftypefnx {} {@var{val} =} NaN (@var{n}, @var{m}, @var{k}, @dots{})
+@deftypefnx {} {@var{val} =} NaN (@dots{}, "@var{like}", @var{var}))
+@deftypefnx {} {@var{val} =} NaN (@dots{}, @var{class})
 Return a scalar, matrix, or N-dimensional array whose elements are all equal
 to the IEEE symbol NaN (Not a Number).
 
@@ -4504,6 +4661,9 @@
 taken as the number of rows and columns and any further arguments specify
 additional matrix dimensions.
 
+If a variable @var{var} is specified after @qcode{"like"}, the output @var{val}
+will have the same data type, complexity, and sparsity as @var{var}.
+
 The optional argument @var{class} specifies the return type and may be
 either @qcode{"double"} or @qcode{"single"}.
 @seealso{isnan, Inf}
@@ -4526,10 +4686,20 @@
 %!assert (NaN (3, 2, "single"), single ([NaN, NaN; NaN, NaN; NaN, NaN]))
 %!assert (size (NaN (3, 4, 5, "single")), [3, 4, 5])
 
-%!error (NaN (3, "int8"))
-%!error (NaN (2, 3, "int8"))
-%!error (NaN (3, 2, "int8"))
-%!error (NaN (3, 4, 5, "int8"))
+%!assert (NaN (2, 2, "like", double (1)), double ([NaN, NaN; NaN, NaN]))
+%!assert (NaN (2, 2, "like", complex (ones(2, 2))), [NaN, NaN; NaN, NaN])
+%!assert (NaN (3, 3, "like", single (1)), single ([NaN, NaN, NaN; NaN, NaN, NaN; NaN, NaN, NaN]))
+%!assert (NaN (2, "like", single (1i)), single ([NaN, NaN; NaN, NaN]))
+%!assert (NaN (2, 2, "like", speye (2)), sparse ([NaN, NaN; NaN, NaN]))
+
+%!error NaN (3, 'like', int8 (1))
+
+%!error NaN (3, "int8")
+%!error NaN (2, 3, "int8")
+%!error NaN (3, 2, "int8")
+%!error NaN (3, 4, 5, "int8")
+%!error <input .* floating> NaN (3, 3, "like", true)
+%!error <input .* floating> NaN (2, "like", uint8 (1))
 */
 
 DEFUN (e, args, ,
@@ -4856,11 +5026,12 @@
 
 DEFUN (NA, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {} NA
-@deftypefnx {} {} NA (@var{n})
-@deftypefnx {} {} NA (@var{n}, @var{m})
-@deftypefnx {} {} NA (@var{n}, @var{m}, @var{k}, @dots{})
-@deftypefnx {} {} NA (@dots{}, @var{class})
+@deftypefn  {} {@var{val} =} NA
+@deftypefnx {} {@var{val} =} NA (@var{n})
+@deftypefnx {} {@var{val} =} NA (@var{n}, @var{m})
+@deftypefnx {} {@var{val} =} NA (@var{n}, @var{m}, @var{k}, @dots{})
+@deftypefnx {} {@var{val} =} NA (@dots{}, "@var{like}", @var{var}))
+@deftypefnx {} {@var{val} =} NA (@dots{}, @var{class})
 Return a scalar, matrix, or N-dimensional array whose elements are all equal
 to the special constant used to designate missing values.
 
@@ -4876,6 +5047,9 @@
 taken as the number of rows and columns and any further arguments specify
 additional matrix dimensions.
 
+If a variable @var{var} is specified after @qcode{"like"}, the output @var{val}
+will have the same data type, complexity, and sparsity as @var{var}.
+
 The optional argument @var{class} specifies the return type and may be
 either @qcode{"double"} or @qcode{"single"}.
 @seealso{isna}
@@ -4892,9 +5066,10 @@
 
 DEFUN (false, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {} false (@var{x})
-@deftypefnx {} {} false (@var{n}, @var{m})
-@deftypefnx {} {} false (@var{n}, @var{m}, @var{k}, @dots{})
+@deftypefn  {} {@var{val} =} false (@var{x})
+@deftypefnx {} {@var{val} =} false (@var{n}, @var{m})
+@deftypefnx {} {@var{val} =} false (@var{n}, @var{m}, @var{k}, @dots{})
+@deftypefnx {} {@var{val} =} false (@dots{}, "@var{like}", @var{var}))
 Return a matrix or N-dimensional array whose elements are all logical 0.
 
 If invoked with a single scalar integer argument, return a square
@@ -4902,17 +5077,31 @@
 
 If invoked with two or more scalar integer arguments, or a vector of integer
 values, return an array with given dimensions.
+
+If a logical variable @var{var} is specified after @qcode{"like"}, the output
+@var{val} will have the same sparsity as @var{var}.
 @seealso{true}
 @end deftypefn */)
 {
   return fill_matrix (args, false, "false");
 }
 
+/*
+%!assert (false (2, 3), logical (zeros (2, 3)))
+%!assert (false (2, 3, "logical"), logical (zeros (2, 3)))
+%!assert (false (2, 1, "like", true), [false; false])
+%!assert (false (2, 1, "like", sparse (true)), sparse ([false; false]))
+
+%!error false (2, 3, "double")
+%!error <input .* logical> false (2, 1, "like", sparse (1))
+*/
+
 DEFUN (true, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {} true (@var{x})
-@deftypefnx {} {} true (@var{n}, @var{m})
-@deftypefnx {} {} true (@var{n}, @var{m}, @var{k}, @dots{})
+@deftypefn  {} {@var{val} =} true (@var{x})
+@deftypefnx {} {@var{val} =} true (@var{n}, @var{m})
+@deftypefnx {} {@var{val} =} true (@var{n}, @var{m}, @var{k}, @dots{})
+@deftypefnx {} {@var{val} =} true (@dots{}, "@var{like}", @var{var}))
 Return a matrix or N-dimensional array whose elements are all logical 1.
 
 If invoked with a single scalar integer argument, return a square
@@ -4920,12 +5109,25 @@
 
 If invoked with two or more scalar integer arguments, or a vector of integer
 values, return an array with given dimensions.
+
+If a logical variable @var{var} is specified after @qcode{"like"}, the output
+@var{val} will have the same sparsity as @var{var}.
 @seealso{false}
 @end deftypefn */)
 {
   return fill_matrix (args, true, "true");
 }
 
+/*
+%!assert (true (2, 3), logical (ones (2, 3)))
+%!assert (true (2, 3, "logical"), logical (ones (2, 3)))
+%!assert (true (2, 1, "like", false), [true; true])
+%!assert (true (2, 1, "like", sparse (true)), sparse ([true; true]))
+
+%!error true (2, 3, "double")
+%!error <input .* logical> true (2, 1, "like", double (1))
+*/
+
 template <typename MT>
 octave_value
 identity_matrix (int nr, int nc)
@@ -5931,7 +6133,7 @@
   if (args.length () != 1)
     print_usage ();
 
-  return do_unary_op (op, args(0));
+  return octave::unary_op (op, args(0));
 }
 
 DEFUN (not, args, ,
@@ -6037,7 +6239,7 @@
   if (args.length () != 2)
     print_usage ();
 
-  return do_binary_op (op, args(0), args(1));
+  return octave::binary_op (op, args(0), args(1));
 }
 
 static octave_value
@@ -6053,10 +6255,10 @@
   octave_value retval;
 
   if (nargin == 2)
-    retval = do_binary_op (op, args(0), args(1));
+    retval = octave::binary_op (op, args(0), args(1));
   else
     {
-      retval = do_binary_op (op, args(0), args(1));
+      retval = octave::binary_op (op, args(0), args(1));
 
       for (int i = 2; i < nargin; i++)
         retval.assign (aop, args(i));
@@ -6156,7 +6358,7 @@
 @deftypefn {} {} mldivide (@var{x}, @var{y})
 Return the matrix left division of @var{x} and @var{y}.
 
-This function and @w{@tcode{@var{x} @xbackslashchar{} @var{y}}} are equivalent.
+This function and @w{@tcode{@var{x} @backslashchar{} @var{y}}} are equivalent.
 @seealso{mrdivide, ldivide, rdivide}
 @end deftypefn */)
 {
@@ -6283,7 +6485,7 @@
 @deftypefn {} {} ldivide (@var{x}, @var{y})
 Return the element-by-element left division of @var{x} and @var{y}.
 
-This function and @w{@tcode{@var{x} .@xbackslashchar{} @var{y}}} are
+This function and @w{@tcode{@var{x} .@backslashchar{} @var{y}}} are
 equivalent.
 @seealso{rdivide, mldivide, times, plus}
 @end deftypefn */)
@@ -6351,8 +6553,9 @@
   if (nargin < 2 || nargin > 3)
     print_usage ();
 
-  return (nargin == 2 ? do_colon_op (args(0), args(1))
-                      : do_colon_op (args(0), args(1), args(2)));
+  return (nargin == 2
+          ? octave::colon_op (args(0), args(1))
+          : octave::colon_op (args(0), args(1), args(2)));
 }
 
 static double tic_toc_timestamp = -1.0;
@@ -6471,7 +6674,7 @@
     }
 
   if (start_time < 0)
-    error ("toc called before timer set");
+    error ("toc: function called before timer initialization with tic()");
 
   octave::sys::time now;
 
@@ -6655,7 +6858,7 @@
       // NOTE: Can not change this to ovl() call because arg.sort changes sidx
       //       and objects are declared const in ovl prototype.
       retval(0) = arg.sort (sidx, dim, smode);
-      retval(1) = idx_vector (sidx, dv(dim));  // No checking, extent is known.
+      retval(1) = octave::idx_vector (sidx, dv(dim));  // No checking, extent is known.
     }
   else
     retval = ovl (arg.sort (dim, smode));
@@ -7081,7 +7284,7 @@
 
   try
     {
-      idx_vector n = args(1).index_vector ();
+      octave::idx_vector n = args(1).index_vector ();
 
       switch (argx.builtin_type ())
         {
@@ -7122,9 +7325,9 @@
             err_wrong_type_arg ("nth_element", argx);
         }
     }
-  catch (const octave::index_exception& e)
-    {
-      error ("nth_element: invalid index %s", e.what ());
+  catch (const octave::index_exception& ie)
+    {
+      error ("nth_element: invalid index %s", ie.what ());
     }
 
   return retval;
@@ -7147,7 +7350,7 @@
 
 template <typename NDT>
 static NDT
-do_accumarray_sum (const idx_vector& idx, const NDT& vals,
+do_accumarray_sum (const octave::idx_vector& idx, const NDT& vals,
                    octave_idx_type n = -1)
 {
   typedef typename NDT::element_type T;
@@ -7186,7 +7389,7 @@
 
   try
     {
-      idx_vector idx = args(0).index_vector ();
+      octave::idx_vector idx = args(0).index_vector ();
       octave_idx_type n = -1;
       if (nargin == 3)
         n = args(2).idx_type_value (true);
@@ -7195,8 +7398,8 @@
 
       if (vals.is_range ())
         {
-          Range r = vals.range_value ();
-          if (r.inc () == 0)
+          octave::range<double> r = vals.range_value ();
+          if (r.increment () == 0)
             vals = r.base ();
         }
 
@@ -7221,9 +7424,9 @@
       else
         err_wrong_type_arg ("accumarray", vals);
     }
-  catch (const octave::index_exception& e)
-    {
-      error ("__accumarray_sum__: invalid index %s", e.what ());
+  catch (const octave::index_exception& ie)
+    {
+      error ("__accumarray_sum__: invalid index %s", ie.what ());
     }
 
   return retval;
@@ -7231,7 +7434,7 @@
 
 template <typename NDT>
 static NDT
-do_accumarray_minmax (const idx_vector& idx, const NDT& vals,
+do_accumarray_minmax (const octave::idx_vector& idx, const NDT& vals,
                       octave_idx_type n, bool ismin,
                       const typename NDT::element_type& zero_val)
 {
@@ -7244,7 +7447,7 @@
   NDT retval (dim_vector (n, 1), zero_val);
 
   // Pick minimizer or maximizer.
-  void (MArray<T>::*op) (const idx_vector&, const MArray<T>&)
+  void (MArray<T>::*op) (const octave::idx_vector&, const MArray<T>&)
     = ismin ? (&MArray<T>::idx_min) : (&MArray<T>::idx_max);
 
   octave_idx_type l = idx.length (n);
@@ -7274,7 +7477,7 @@
 
   try
     {
-      idx_vector idx = args(0).index_vector ();
+      octave::idx_vector idx = args(0).index_vector ();
       octave_idx_type n = -1;
       if (nargin == 4)
         n = args(3).idx_type_value (true);
@@ -7332,9 +7535,9 @@
           err_wrong_type_arg ("accumarray", vals);
         }
     }
-  catch (const octave::index_exception& e)
-    {
-      error ("do_accumarray_minmax_fun: invalid index %s", e.what ());
+  catch (const octave::index_exception& ie)
+    {
+      error ("do_accumarray_minmax_fun: invalid index %s", ie.what ());
     }
 
   return retval;
@@ -7360,7 +7563,7 @@
 
 template <typename NDT>
 static NDT
-do_accumdim_sum (const idx_vector& idx, const NDT& vals,
+do_accumdim_sum (const octave::idx_vector& idx, const NDT& vals,
                  int dim = -1, octave_idx_type n = -1)
 {
   typedef typename NDT::element_type T;
@@ -7407,7 +7610,7 @@
 
   try
     {
-      idx_vector idx = args(0).index_vector ();
+      octave::idx_vector idx = args(0).index_vector ();
       int dim = -1;
       if (nargin >= 3)
         dim = args(2).int_value () - 1;
@@ -7439,9 +7642,9 @@
       else
         err_wrong_type_arg ("accumdim", vals);
     }
-  catch (const octave::index_exception& e)
-    {
-      error ("__accumdim_sum__: invalid index %s", e.what ());
+  catch (const octave::index_exception& ie)
+    {
+      error ("__accumdim_sum__: invalid index %s", ie.what ());
     }
 
   return retval;
@@ -7629,7 +7832,7 @@
       octave_idx_type k = retval.columns ();
       while (order > 0 && k > 0)
         {
-          idx_vector col1 (':'), col2 (':'), sl1 (1, k), sl2 (0, k-1);
+          octave::idx_vector col1 (':'), col2 (':'), sl1 (1, k), sl2 (0, k-1);
           retval = SparseT (retval.index (col1, sl1))
                    - SparseT (retval.index (col2, sl2));
           assert (retval.columns () == k-1);
@@ -7642,7 +7845,7 @@
       octave_idx_type k = retval.rows ();
       while (order > 0 && k > 0)
         {
-          idx_vector col1 (':'), col2 (':'), sl1 (1, k), sl2 (0, k-1);
+          octave::idx_vector col1 (':'), col2 (':'), sl1 (1, k), sl2 (0, k-1);
           retval = SparseT (retval.index (sl1, col1))
                    - SparseT (retval.index (sl2, col2));
           assert (retval.rows () == k-1);
@@ -7941,7 +8144,7 @@
 Encode a double matrix or array @var{x} into the base64 format string
 @var{s}.
 
-@seealso{base64_decode}
+@seealso{base64_decode, matlab.net.base64decode, matlab.net.base64encode}
 @end deftypefn */)
 {
   if (args.length () != 1)
@@ -8049,7 +8252,7 @@
 
 The optional input parameter @var{dims} should be a vector containing the
 dimensions of the decoded array.
-@seealso{base64_encode}
+@seealso{base64_encode, matlab.net.base64decode, matlab.net.base64encode}
 @end deftypefn */)
 {
   int nargin = args.length ();
@@ -8095,3 +8298,57 @@
 %!error <input was not valid base64> base64_decode ("AQ=")
 %!error <incorrect input size> base64_decode ("AQ==")
 */
+
+DEFUN (__base64_decode_bytes__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{x} =} base64_decode_bytes (@var{s})
+@deftypefnx {} {@var{x} =} base64_decode_bytes (@var{s}, @var{dims})
+Decode the uint8 matrix or array @var{x} from the base64 encoded string
+@var{s}.
+
+The optional input parameter @var{dims} should be a vector containing the
+dimensions of the decoded array.
+@seealso{base64_decode}
+@end deftypefn */)
+{
+  int nargin = args.length ();
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+
+  std::string str = args(0).string_value ();
+
+  intNDArray<octave_uint8> retval = octave::base64_decode_bytes (str);
+
+  if (nargin == 2)
+    {
+      dim_vector dims;
+
+      const Array<octave_idx_type> size
+        = args(1).octave_idx_type_vector_value ();
+
+      dims = dim_vector::alloc (size.numel ());
+      for (octave_idx_type i = 0; i < size.numel (); i++)
+        dims(i) = size(i);
+
+      retval = retval.reshape (dims);
+    }
+
+  return ovl (retval);
+}
+
+/*
+%!assert (__base64_decode_bytes__ (base64_encode (uint8 (1))), uint8 (1))
+
+%!test
+%! in   = uint8 (rand (10)*255);
+%! outv = __base64_decode_bytes__ (base64_encode (in));
+%! outm = __base64_decode_bytes__ (base64_encode (in), size (in));
+%! assert (outv, in(:).');
+%! assert (outm, in);
+
+%!error __base64_decode_bytes__ ()
+%!error __base64_decode_bytes__ (1,2,3)
+%!error __base64_decode_bytes__ (1, "this is not a valid set of dimensions")
+%!error <input was not valid base64> __base64_decode_bytes__ (1)
+*/
--- a/libinterp/corefcn/debug.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/debug.cc	Sun May 16 09:44:35 2021 +0200
@@ -60,22 +60,14 @@
 #include "variables.h"
 
 static octave_value
-intmap_to_ov (const octave::bp_table::intmap& line)
+bp_lines_to_ov (const octave::bp_table::bp_lines& lines)
 {
   int idx = 0;
 
-  NDArray retval (dim_vector (1, line.size ()));
-
-  for (std::size_t i = 0; i < line.size (); i++)
-    {
-      octave::bp_table::const_intmap_iterator p = line.find (i);
+  NDArray retval (dim_vector (1, lines.size ()));
 
-      if (p != line.end ())
-        {
-          int lineno = p->second;
-          retval(idx++) = lineno;
-        }
-    }
+  for (const auto& lineno : lines)
+    retval(idx++) = lineno;
 
   retval.resize (dim_vector (1, idx));
 
@@ -173,10 +165,10 @@
 @seealso{dbclear, dbstatus, dbstep, debug_on_error, debug_on_warning, debug_on_interrupt}
 @end deftypefn */)
 {
-  octave::bp_table::intmap retmap;
+  octave::bp_table::bp_lines retmap;
   std::string symbol_name = "";  // stays empty for "dbstop if error" etc
   std::string class_name = "";
-  octave::bp_table::intmap lines;
+  octave::bp_table::bp_lines lines;
   std::string condition = "";
   octave_value retval;
 
@@ -191,13 +183,13 @@
                                      class_name, lines, condition);
 
       if (lines.size () == 0)
-        lines[0] = 1;
+        lines.insert (1);
 
       if (symbol_name != "")
         {
-          retmap = bptab.add_breakpoint (symbol_name, class_name,
-                                         lines, condition);
-          retval = intmap_to_ov (retmap);
+          retmap = bptab.add_breakpoints_in_function (symbol_name, class_name,
+                                                      lines, condition);
+          retval = bp_lines_to_ov (retmap);
         }
     }
   else if (args.length () != 1)
@@ -222,10 +214,7 @@
                   && bkpt.cell_value () (0).isstruct ())
                 mv = bkpt.cell_value () (0).map_value ();
               else
-                {
-                  error ("dbstop: invalid 'bkpt' field");
-                  mv = octave_map ();
-                }
+                error ("dbstop: invalid 'bkpt' field");
             }
         }
       if (mv.isempty ())
@@ -235,7 +224,6 @@
       else if (! mv.isfield ("name") || ! mv.isfield ("line"))
         {
           error ("dbstop: Cell array must contain fields 'name' and 'line'");
-          retval = octave_value (0);
         }
       else
         {
@@ -246,11 +234,12 @@
           std::string unconditional = "";
           for (octave_idx_type i = 0; i < line.numel (); i++)
             {
-              lines [0] = line(i).double_value ();
-              bptab.add_breakpoint (name(i).string_value (), "", lines,
-                                    (use_cond
-                                     ? cond(i).string_value ()
-                                     : unconditional));
+              lines.insert (line(i).int_value ());
+              bptab.add_breakpoints_in_function (name(i).string_value (),
+                                                 "", lines,
+                                                 (use_cond
+                                                  ? cond(i).string_value ()
+                                                  : unconditional));
             }
           retval = octave_value (line.numel ());
         }
@@ -293,7 +282,7 @@
 
 @item event
 An event such as @code{error}, @code{interrupt}, or @code{warning}
-(@pxref{XREFdbstop,,dbstop} for details).
+(@pxref{XREFdbstop,,@code{dbstop}} for details).
 @end table
 
 When called without a line number specification all breakpoints in the named
@@ -308,7 +297,7 @@
 {
   std::string symbol_name = "";  // stays empty for "dbclear if error" etc
   std::string class_name = "";
-  octave::bp_table::intmap lines;
+  octave::bp_table::bp_lines lines;
   std::string dummy;             // "if" condition -- only used for dbstop
 
   int nargin = args.length ();
@@ -317,7 +306,8 @@
 
   octave::bp_table& bptab = tw.get_bp_table ();
 
-  bptab.parse_dbfunction_params ("dbclear", args, symbol_name, class_name, lines, dummy);
+  bptab.parse_dbfunction_params ("dbclear", args, symbol_name, class_name,
+                                 lines, dummy);
 
   if (nargin == 1 && symbol_name == "all")
     {
@@ -327,7 +317,7 @@
   else
     {
       if (symbol_name != "")
-        bptab.remove_breakpoint (symbol_name, lines);
+        bptab.remove_breakpoints_from_function (symbol_name, lines);
     }
 
   // If we remove a breakpoint, we also need to reset debug_mode.
@@ -838,8 +828,6 @@
 
   octave_value_list retval;
 
-  octave::unwind_protect frame;
-
   octave_idx_type curr_frame = -1;
 
   octave_idx_type nskip = 0;
@@ -865,7 +853,7 @@
           else
             n = arg.int_value ();
 
-          if (n <= 0)
+          if (n < 0)
             error ("dbstack: N must be a non-negative integer");
         }
 
@@ -966,8 +954,8 @@
 Although accepted, the argument @var{-completenames} is silently ignored.
 Octave always returns absolute filenames.
 
-The arguments @var{n} and @var{-completenames} can be both specified in any
-order.
+The arguments @var{n} and @var{-completenames} can both be specified and may
+appear in any order.
 
 The optional return argument @var{stack} is a struct array with the
 following fields:
@@ -985,11 +973,6 @@
 @item column
 The column number of the line where the breakpoint begins.
 
-@item scope
-Undocumented.
-
-@item context
-Undocumented.
 @end table
 
 The return argument @var{idx} specifies which element of the @var{stack}
--- a/libinterp/corefcn/defaults.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/defaults.cc	Sun May 16 09:44:35 2021 +0200
@@ -507,3 +507,40 @@
 %!assert (ischar (OCTAVE_VERSION ()))
 %!error OCTAVE_VERSION (1)
 */
+
+DEFUN (user_config_dir, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {cfg_dir = } user_config_dir ()
+Return the (platform-specific) directory for user configuration.
+@seealso{user_data_dir}
+@end deftypefn */)
+{
+  if (args.length () != 0)
+    print_usage ();
+
+  return ovl (octave::sys::env::get_user_config_directory ());
+}
+
+/*
+%!assert (ischar (user_config_dir ()))
+%!error user_config_dir (1)
+*/
+
+DEFUN (user_data_dir, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {data_dir = } user_data_dir ()
+Return the (platform-specific) directory for user data.
+@seealso{user_config_dir}
+@end deftypefn */)
+{
+  if (args.length () != 0)
+    print_usage ();
+
+  return ovl (octave::sys::env::get_user_data_directory ());
+}
+
+/*
+%!assert (ischar (user_data_dir ()))
+%!error user_data_dir (1)
+*/
+
--- a/libinterp/corefcn/dirfns.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/dirfns.cc	Sun May 16 09:44:35 2021 +0200
@@ -224,7 +224,7 @@
     }
 }
 
-DEFMETHODX ("rmdir", Frmdir, interp, args, ,
+DEFMETHODX ("rmdir", Frmdir, interp, args, nargout,
             doc: /* -*- texinfo -*-
 @deftypefn  {} {} rmdir @var{dir}
 @deftypefnx {} {} rmdir (@var{dir}, "s")
@@ -250,6 +250,7 @@
   std::string dirname = args(0).xstring_value ("rmdir: DIR must be a string");
 
   std::string fulldir = octave::sys::file_ops::tilde_expand (dirname);
+  octave_value_list retval;
   int status = -1;
   std::string msg;
 
@@ -287,20 +288,30 @@
 
   evmgr.file_renamed (status >= 0);
 
-  if (status < 0)
-    return ovl (false, msg, "rmdir");
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("rmdir: operation failed: %s", msg.c_str ());
+    }
   else
-    return ovl (true, "", "");
+    {
+      if (status < 0)
+        retval = ovl (0.0, msg, "rmdir");
+      else
+        retval = ovl (1.0, "", "");
+    }
+
+  return retval;
 }
 
-DEFUNX ("link", Flink, args, ,
+DEFUNX ("link", Flink, args, nargout,
         doc: /* -*- texinfo -*-
 @deftypefn  {} {} link @var{old} @var{new}
-@deftypefnx {} {[@var{err}, @var{msg}] =} link (@var{old}, @var{new})
+@deftypefnx {} {[@var{status}, @var{msg}] =} link (@var{old}, @var{new})
 Create a new link (also known as a hard link) to an existing file.
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.
-Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
 error message.
 @seealso{symlink, unlink, readlink, lstat}
 @end deftypefn */)
@@ -314,24 +325,35 @@
   from = octave::sys::file_ops::tilde_expand (from);
   to = octave::sys::file_ops::tilde_expand (to);
 
+  octave_value_list retval;
   std::string msg;
 
   int status = octave::sys::link (from, to, msg);
 
-  if (status < 0)
-    return ovl (-1.0, msg);
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("link: operation failed: %s", msg.c_str ());
+    }
   else
-    return ovl (status, "");
+    {
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
+    }
+
+  return retval;
 }
 
-DEFUNX ("symlink", Fsymlink, args, ,
+DEFUNX ("symlink", Fsymlink, args, nargout,
         doc: /* -*- texinfo -*-
 @deftypefn  {} {} symlink @var{old} @var{new}
-@deftypefnx {} {[@var{err}, @var{msg}] =} symlink (@var{old}, @var{new})
+@deftypefnx {} {[@var{status}, @var{msg}] =} symlink (@var{old}, @var{new})
 Create a symbolic link @var{new} which contains the string @var{old}.
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.
-Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
 error message.
 @seealso{link, unlink, readlink, lstat}
 @end deftypefn */)
@@ -345,14 +367,25 @@
   from = octave::sys::file_ops::tilde_expand (from);
   to = octave::sys::file_ops::tilde_expand (to);
 
+  octave_value_list retval;
   std::string msg;
 
   int status = octave::sys::symlink (from, to, msg);
 
-  if (status < 0)
-    return ovl (-1.0, msg);
+  if (nargout == 0)
+    {
+      if (status < 0)
+        error ("symlink: operation failed: %s", msg.c_str ());
+    }
   else
-    return ovl (status, "");
+    {
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
+    }
+
+  return retval;
 }
 
 DEFUNX ("readlink", Freadlink, args, ,
@@ -385,14 +418,14 @@
     return ovl (result, status, "");
 }
 
-DEFMETHODX ("rename", Frename, interp, args, ,
+DEFMETHODX ("rename", Frename, interp, args, nargout,
             doc: /* -*- texinfo -*-
 @deftypefn  {} {} rename @var{old} @var{new}
-@deftypefnx {} {[@var{err}, @var{msg}] =} rename (@var{old}, @var{new})
+@deftypefnx {} {[@var{status}, @var{msg}] =} rename (@var{old}, @var{new})
 Change the name of file @var{old} to @var{new}.
 
-If successful, @var{err} is 0 and @var{msg} is an empty string.
-Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent
+If successful, @var{status} is 0 and @var{msg} is an empty string.
+Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent
 error message.
 @seealso{movefile, copyfile, ls, dir}
 @end deftypefn */)
@@ -406,6 +439,7 @@
   from = octave::sys::file_ops::tilde_expand (from);
   to = octave::sys::file_ops::tilde_expand (to);
 
+  octave_value_list retval;
   std::string msg;
 
   octave::event_manager& evmgr = interp.get_event_manager ();
@@ -414,16 +448,22 @@
 
   int status = octave::sys::rename (from, to, msg);
 
-  if (status < 0)
+  evmgr.file_renamed (status >= 0);
+
+  if (nargout == 0)
     {
-      evmgr.file_renamed (false);
-      return ovl (-1.0, msg);
+      if (status < 0)
+        error ("rename: operation failed: %s", msg.c_str ());
     }
   else
     {
-      evmgr.file_renamed (true);
-      return ovl (status, "");
+      if (status < 0)
+        retval = ovl (-1.0, msg);
+      else
+        retval = ovl (0.0, "");
     }
+
+  return retval;
 }
 
 DEFUN (glob, args, ,
@@ -474,13 +514,18 @@
         [2,1] = file2
       @}
 @end example
+
+Note: On Windows, patterns that contain non-ASCII characters are not
+supported.
+
 @seealso{ls, dir, readdir, what}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  string_vector pat = args(0).xstring_vector_value ("glob: PATTERN must be a string");
+  string_vector pat
+    = args(0).xstring_vector_value ("glob: PATTERN must be a string");
 
   glob_match pattern (octave::sys::file_ops::tilde_expand (pat));
 
@@ -556,10 +601,10 @@
 
 /*
 %!test
-%! tmpdir = tempname;
+%! tmpdir = tempname ();
 %! filename = {"file1", "file2", "file3", "myfile1", "myfile1b"};
 %! if (mkdir (tmpdir))
-%!   cwd = pwd;
+%!   cwd = pwd ();
 %!   cd (tmpdir);
 %!   if (strcmp (canonicalize_file_name (pwd), canonicalize_file_name (tmpdir)))
 %!     a = 0;
@@ -567,8 +612,8 @@
 %!       save (filename{n}, "a");
 %!     endfor
 %!   else
-%!     rmdir (tmpdir);
-%!     error ("Couldn't change to temporary dir");
+%!     sts = rmdir (tmpdir);
+%!     error ("Couldn't change to temporary directory");
 %!   endif
 %! else
 %!   error ("Couldn't create temporary directory");
@@ -580,7 +625,7 @@
 %!   delete (filename{n});
 %! endfor
 %! cd (cwd);
-%! rmdir (tmpdir);
+%! sts = rmdir (tmpdir);
 %! assert (result1, {"file1"; "myfile1"});
 %! assert (result2, {"myfile1"});
 %! assert (result3, {"file1"; "file2"});
@@ -656,9 +701,7 @@
 @seealso{filesep}
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin > 0)
+  if (args.length () > 0)
     print_usage ();
 
   return ovl (octave::directory_path::path_sep_str ());
--- a/libinterp/corefcn/dlmread.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/dlmread.cc	Sun May 16 09:44:35 2021 +0200
@@ -305,6 +305,32 @@
   bool sep_is_wspace = (sep.find_first_of (" \t") != std::string::npos);
   bool auto_sep_is_wspace = false;
 
+  if (r0 == 0)
+    {
+      // Peek into stream and potentially strip Byte Order Mark (BOM)
+      const char BOM[3] = {'\xEF', '\xBB', '\xBF'};
+      char buf[3];
+      int i_bom;
+      bool found_bom = true;
+      for (i_bom = 0; i_bom < 3; i_bom++)
+        {
+          char ch_p = input->peek ();
+          if (ch_p == BOM[i_bom])
+            buf[i_bom] = input->get ();
+          else
+            {
+              found_bom = false;
+              break;
+            }
+        }
+      // Put back read characters if it wasn't a BOM
+      if (! found_bom)
+        {
+          for (int i_ret = i_bom-1; i_ret >= 0; i_ret--)
+            input->putback (buf[i_ret]);
+        }
+    }
+
   std::string line;
 
   // Skip the r0 leading lines
@@ -443,7 +469,7 @@
           tmp_stream.str (str);
           tmp_stream.clear ();
 
-          double x = octave_read_double (tmp_stream);
+          double x = octave::read_value<double> (tmp_stream);
           if (tmp_stream)
             {
               if (tmp_stream.eof ())
@@ -485,7 +511,7 @@
                     }
                   else
                     {
-                      double y = octave_read_double (tmp_stream);
+                      double y = octave::read_value<double> (tmp_stream);
 
                       if (! iscmplx && y != 0.0)
                         {
@@ -502,7 +528,7 @@
             }
           else
             {
-              // octave_read_double() parsing failed
+              // octave::read_value<double>() parsing failed
               j++;  // Leave data initialized to empty_value
             }
 
@@ -584,7 +610,7 @@
 %!   unlink (file);
 %! end_unwind_protect
 
-%!xtest <47413>
+%!test <47413>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! if (! ismac ()), return; endif
 %! file = tempname ();
@@ -641,7 +667,7 @@
 %!   unlink (file);
 %! end_unwind_protect
 
-%!xtest <47413>
+%!test <47413>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! if (! ismac ()), return; endif
 %! file = tempname ();
@@ -713,4 +739,18 @@
 %!   unlink (file);
 %! end_unwind_protect
 
+## Verify UTF-8 Byte Order Mark does not cause problems with reading
+%!test <*58813>
+%! file = tempname ();
+%! unwind_protect
+%!   fid = fopen (file, "wt");
+%!   fwrite (fid, char ([0xEF, 0xBB, 0xBF]));  # UTF-8 BOM
+%!   fwrite (fid, "1,2\n3,4");
+%!   fclose (fid);
+%!
+%!   assert (dlmread (file), [1, 2; 3, 4]);
+%! unwind_protect_cleanup
+%!   unlink (file);
+%! end_unwind_protect
+
 */
--- a/libinterp/corefcn/dmperm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/dmperm.cc	Sun May 16 09:44:35 2021 +0200
@@ -103,10 +103,9 @@
     {
       CXSPARSE_NAME (d) *dm = CXSPARSE_NAME(_dmperm) (&csm, 0);
 
-      //retval(5) = put_int (dm->rr, 5);
-      //retval(4) = put_int (dm->cc, 5);
       retval = ovl (put_int (dm->p, nr), put_int (dm->q, nc),
-                    put_int (dm->r, dm->nb+1), put_int (dm->s, dm->nb+1));
+                    put_int (dm->r, dm->nb+1), put_int (dm->s, dm->nb+1),
+                    put_int (dm->cc, 5), put_int (dm->rr, 5));
 
       CXSPARSE_NAME (_dfree) (dm);
     }
@@ -116,23 +115,68 @@
 
 #endif
 
+// NOTE: the docstring for dmperm is adapted from the text found in the
+// file cs_dmperm.m that is distributed with the CSparse portion of the
+// SuiteSparse library, version 5.6.0.  CSparse is distributed under the
+// terms of the LGPL v2.1 or any later version.
+
 DEFUN (dmperm, args, nargout,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{p} =} dmperm (@var{S})
-@deftypefnx {} {[@var{p}, @var{q}, @var{r}, @var{S}] =} dmperm (@var{S})
+@deftypefn  {} {@var{p} =} dmperm (@var{A})
+@deftypefnx {} {[@var{p}, @var{q}, @var{r}, @var{s}, @var{cc}, @var{rr}] =} dmperm (@var{A})
 
 @cindex @nospell{Dulmage-Mendelsohn} decomposition
 Perform a @nospell{Dulmage-Mendelsohn} permutation of the sparse matrix
-@var{S}.
+@var{A}.
+
+With a single output argument @code{dmperm}, return a maximum matching @var{p}
+such that @code{p(j) = i} if column @var{j} is matched to row @var{i}, or 0 if
+column @var{j} is unmatched.  If @var{A} is square and full structural rank,
+@var{p} is a row permutation and @code{A(p,:)} has a zero-free diagonal.  The
+structural rank of @var{A} is @code{sprank(A) = sum(p>0)}.
+
+Called with two or more output arguments, return the
+@nospell{Dulmage-Mendelsohn} decomposition of @var{A}.  @var{p} and @var{q} are
+permutation vectors.  @var{cc} and @var{rr} are vectors of length 5.
+@code{c = A(p,q)} is split into a 4-by-4 set of coarse blocks:
+
+@example
+@group
+   A11 A12 A13 A14
+    0  0   A23 A24
+    0  0    0  A34
+    0  0    0  A44
+@end group
+@end example
 
-With a single output argument @code{dmperm} performs the row permutations
-@var{p} such that @code{@var{S}(@var{p},:)} has no zero elements on the
-diagonal.
+@noindent
+where @code{A12}, @code{A23}, and @code{A34} are square with zero-free
+diagonals.  The columns of @code{A11} are the unmatched columns, and the rows
+of @code{A44} are the unmatched rows.  Any of these blocks can be empty.  In
+the "coarse" decomposition, the (i,j)-th block is
+@code{C(rr(i):rr(i+1)-1,cc(j):cc(j+1)-1)}.  In terms of a linear system,
+@code{[A11 A12]} is the underdetermined part of the system (it is always
+rectangular and with more columns and rows, or 0-by-0), @code{A23} is the
+well-determined part of the system (it is always square), and
+@code{[A34 ; A44]} is the over-determined part of the system (it is always
+rectangular with more rows than columns, or 0-by-0).
 
-Called with two or more output arguments, returns the row and column
-permutations, such that @code{@var{S}(@var{p}, @var{q})} is in block
-triangular form.  The values of @var{r} and @var{S} define the boundaries
-of the blocks.  If @var{S} is square then @code{@var{r} == @var{S}}.
+The structural rank of @var{A} is @code{sprank (A) = rr(4)-1}, which is an
+upper bound on the numerical rank of @var{A}.
+@code{sprank(A) = rank(full(sprand(A)))} with probability 1 in exact
+arithmetic.
+
+The @code{A23} submatrix is further subdivided into block upper triangular form
+via the "fine" decomposition (the strongly-connected components of @code{A23}).
+If @var{A} is square and structurally non-singular, @code{A23} is the entire
+matrix.
+
+@code{C(r(i):r(i+1)-1,s(j):s(j+1)-1)} is the (i,j)-th block of the fine
+decomposition.  The (1,1) block is the rectangular block @code{[A11 A12]},
+unless this block is 0-by-0.  The (b,b) block is the rectangular block
+@code{[A34 ; A44]}, unless this block is 0-by-0, where @code{b = length(r)-1}.
+All other blocks of the form @code{C(r(i):r(i+1)-1,s(i):s(i+1)-1)} are diagonal
+blocks of @code{A23}, and are square with a zero-free diagonal.
 
 The method used is described in: @nospell{A. Pothen & C.-J. Fan.}
 @cite{Computing the Block Triangular Form of a Sparse Matrix}.
--- a/libinterp/corefcn/dot.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/dot.cc	Sun May 16 09:44:35 2021 +0200
@@ -190,7 +190,7 @@
       // exceed intmax.
       octave_value_list tmp;
       tmp(1) = dim + 1;
-      tmp(0) = do_binary_op (octave_value::op_el_mul, argx, argy);
+      tmp(0) = octave::binary_op (octave_value::op_el_mul, argx, argy);
 
       tmp = Fsum (tmp, 1);
       if (! tmp.empty ())
--- a/libinterp/corefcn/dynamic-ld.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/dynamic-ld.cc	Sun May 16 09:44:35 2021 +0200
@@ -152,11 +152,7 @@
   {
     octave_function *retval = nullptr;
 
-    unwind_protect frame;
-
-    frame.protect_var (m_doing_load);
-
-    m_doing_load = true;
+    unwind_protect_var<bool> restore_var (m_doing_load, true);
 
     dynamic_library oct_file = m_loaded_shlibs.find_file (file_name);
 
@@ -199,18 +195,42 @@
     return retval;
   }
 
+  void *
+  dynamic_loader::try_load_mex (dynamic_library& mex_file,
+                                const std::string& fcn_name, bool& have_fmex)
+  {
+    // FCN_NAME is not used here, the mangler functions always return
+    // some form of "mexFunction".
+
+    have_fmex = false;
+
+    void *function = mex_file.search (fcn_name, mex_mangler);
+
+    if (! function)
+      {
+        // FIXME: Can we determine this C mangling scheme
+        //        automatically at run time or configure time?
+
+        function = mex_file.search (fcn_name, mex_uscore_mangler);
+
+        if (! function)
+          {
+            function = mex_file.search (fcn_name, mex_f77_mangler);
+
+            if (function)
+              have_fmex = true;
+          }
+      }
+
+    return function;
+  }
+
   octave_function *
   dynamic_loader::load_mex (const std::string& fcn_name,
                             const std::string& file_name,
                             bool /*relative*/)
   {
-    octave_function *retval = nullptr;
-
-    unwind_protect frame;
-
-    frame.protect_var (m_doing_load);
-
-    m_doing_load = true;
+    unwind_protect_var<bool> restore_var (m_doing_load, true);
 
     dynamic_library mex_file = m_loaded_shlibs.find_file (file_name);
 
@@ -230,29 +250,17 @@
 
     bool have_fmex = false;
 
-    void *function = mex_file.search (fcn_name, mex_mangler);
-
-    if (! function)
-      {
-        // FIXME: Can we determine this C mangling scheme
-        //        automatically at run time or configure time?
-        function = mex_file.search (fcn_name, mex_uscore_mangler);
-
-        if (! function)
-          {
-            function = mex_file.search (fcn_name, mex_f77_mangler);
-
-            if (function)
-              have_fmex = true;
-          }
-      }
+    void *function = try_load_mex (mex_file, fcn_name, have_fmex);
 
     if (! function)
       error ("failed to install .mex file function '%s'", fcn_name.c_str ());
 
-    retval = new octave_mex_function (function, have_fmex, mex_file, fcn_name);
+    void *symbol = mex_file.search ("__mx_has_interleaved_complex__");
 
-    return retval;
+    bool interleaved = symbol != nullptr;
+
+    return new octave_mex_function (function, interleaved, have_fmex,
+                                    mex_file, fcn_name);
   }
 
   bool
--- a/libinterp/corefcn/dynamic-ld.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/dynamic-ld.h	Sun May 16 09:44:35 2021 +0200
@@ -128,6 +128,9 @@
     static std::string mex_uscore_mangler (const std::string& name);
 
     static std::string mex_f77_mangler (const std::string& name);
+
+    static void * try_load_mex (dynamic_library& mex_file,
+                                const std::string& fcn_name, bool& have_fmex);
   };
 }
 
--- a/libinterp/corefcn/eig.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/eig.cc	Sun May 16 09:44:35 2021 +0200
@@ -532,22 +532,22 @@
 ## column vector if 1 output is specified
 %!function test_shapes (args)
 %!  d = eig (args{:});
-%!  assert (isvector(d))
+%!  assert (isvector (d))
 %!  d2 = eig (args{:}, "vector");
-%!  assert (isvector(d2))
+%!  assert (isvector (d2))
 %!  [v, d3] = eig (args{:});
-%!  assert (isdiag(d3))
+%!  assert (isdiag (d3))
 %!  d4 = eig (args{:}, "matrix");
-%!  assert (isdiag(d4))
+%!  assert (isdiag (d4))
 %!  [v, d5, w] = eig (args{:});
-%!  assert (isdiag(d5))
+%!  assert (isdiag (d5))
 %!  d6 = eig (args{:}, "matrix");
-%!  assert (isdiag(d6))
+%!  assert (isdiag (d6))
 %!  assert (d, d2)
 %!  assert (d3, d4)
 %!  assert (d5, d6)
-%!  assert (d, diag(d3))
-%!  assert (d, diag(d5))
+%!  assert (d, diag (d3))
+%!  assert (d, diag (d5))
 %!endfunction
 
 %!function shapes_AEP (A)
--- a/libinterp/corefcn/ellipj.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ellipj.cc	Sun May 16 09:44:35 2021 +0200
@@ -338,7 +338,7 @@
 ## tests taken from inst/test_sncndn.m
 
 %!test
-%! k = (tan(pi/8.))^2;  m = k*k;
+%! k = (tan (pi/8))^2;  m = k*k;
 %! SN = [
 %! -1. + I * 0. ,  -0.8392965923 + 0. * I
 %! -1. + I * 0.2 ,  -0.8559363407 + 0.108250955 * I
@@ -729,13 +729,13 @@
 %! assert ([sn,cn,dn], res1, 10*eps);
 
 %!test
-%! u2 = log(2); m2 = 1;
+%! u2 = log (2); m2 = 1;
 %! res2 = [ 3/5, 4/5, 4/5 ];
 %! [sn,cn,dn] = ellipj (u2,m2);
 %! assert ([sn,cn,dn], res2, 10*eps);
 
 %!test
-%! u3 = log(2)*1i; m3 = 0;
+%! u3 = log (2)*1i; m3 = 0;
 %! res3 = [3i/4,5/4,1];
 %! [sn,cn,dn] = ellipj (u3,m3);
 %! assert ([sn,cn,dn], res3, 10*eps);
@@ -747,7 +747,7 @@
 %! assert ([sn,cn,dn], res4, 1e-10);
 
 %!test
-%! u5 = -0.2 + 0.4i; m5 = tan(pi/8)^4;
+%! u5 = -0.2 + 0.4i; m5 = tan (pi/8)^4;
 %! res5 = [ -0.2152524522 + 0.402598347i, ...
 %!           1.059453907  + 0.08179712295i, ...
 %!           1.001705496  + 0.00254669712i ];
@@ -755,7 +755,7 @@
 %! assert ([sn,cn,dn], res5, 1e-9);
 
 %!test
-%! u6 = 0.2 + 0.6i; m6 = tan(pi/8)^4;
+%! u6 = 0.2 + 0.6i; m6 = tan (pi/8)^4;
 %! res6 = [ 0.2369100139 + 0.624633635i, ...
 %!          1.16200643   - 0.1273503824i, ...
 %!          1.004913944  - 0.004334880912i ];
--- a/libinterp/corefcn/environment.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/environment.cc	Sun May 16 09:44:35 2021 +0200
@@ -186,7 +186,7 @@
 %! EDITOR (orig_val);
 %! assert (EDITOR (), orig_val);
 
-%!error (EDITOR (1, 2))
+%!error EDITOR (1, 2)
 */
 
 DEFMETHOD (EXEC_PATH, interp, args, nargout,
@@ -223,7 +223,7 @@
 %! EXEC_PATH (orig_val);
 %! assert (EXEC_PATH (), orig_val);
 
-%!error (EXEC_PATH (1, 2))
+%!error EXEC_PATH (1, 2)
 */
 
 DEFMETHOD (IMAGE_PATH, interp, args, nargout,
@@ -255,5 +255,5 @@
 %! IMAGE_PATH (orig_val);
 %! assert (IMAGE_PATH (), orig_val);
 
-%!error (IMAGE_PATH (1, 2))
+%!error IMAGE_PATH (1, 2)
 */
--- a/libinterp/corefcn/error.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/error.cc	Sun May 16 09:44:35 2021 +0200
@@ -43,6 +43,7 @@
 #include "builtin-defun-decls.h"
 #include "defun.h"
 #include "error.h"
+#include "event-manager.h"
 #include "input.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
@@ -72,12 +73,12 @@
 
 OCTAVE_NORETURN
 static void
-error_1 (octave::execution_exception& e, const char *id, const char *fmt,
+error_1 (octave::execution_exception& ee, const char *id, const char *fmt,
          va_list args)
 {
   octave::error_system& es = octave::__get_error_system__ ("error_1");
 
-  es.error_1 (e, id, fmt, args);
+  es.error_1 (ee, id, fmt, args);
 }
 
 OCTAVE_NORETURN
@@ -368,7 +369,7 @@
   static const octave_fields bt_fields (bt_fieldnames);
 
   octave_map
-  error_system::make_stack_map (const std::list<octave::frame_info>& frames)
+  error_system::make_stack_map (const std::list<frame_info>& frames)
   {
     std::size_t nframes = frames.size ();
 
@@ -404,10 +405,10 @@
     return retval;
   }
 
-  std::list<octave::frame_info>
+  std::list<frame_info>
   error_system::make_stack_frame_list (const octave_map& stack)
   {
-    std::list<octave::frame_info> frames;
+    std::list<frame_info> frames;
 
     Cell file = stack.contents ("file");
     Cell name = stack.contents ("name");
@@ -423,11 +424,11 @@
     octave_idx_type nel = name.numel ();
 
     for (octave_idx_type i = 0; i < nel; i++)
-      frames.push_back (octave::frame_info (file(i).string_value (),
-                                            name(i).string_value (),
-                                            line(i).int_value (),
-                                            (have_column
-                                             ? column(i).int_value () : -1)));
+      frames.push_back (frame_info (file(i).string_value (),
+                                    name(i).string_value (),
+                                    line(i).int_value (),
+                                    (have_column
+                                     ? column(i).int_value () : -1)));
 
     return frames;
   }
@@ -571,22 +572,19 @@
          || application::forced_interactive ())
         && debug_on_warning () && in_user_code && bptab.debug_on_warn (id))
       {
-        unwind_protect frame;
-
-        frame.protect_var (m_debug_on_warning);
-        m_debug_on_warning = false;
+        unwind_protect_var<bool> restore_var (m_debug_on_warning, false);
 
         tw.enter_debugger ();
       }
   }
 
-  void error_system::error_1 (execution_exception& e, const char *id,
+  void error_system::error_1 (execution_exception& ee, const char *id,
                               const char *fmt, va_list args)
   {
-    e.set_identifier (id);
-    e.set_message (format_message (fmt, args));
+    ee.set_identifier (id);
+    ee.set_message (format_message (fmt, args));
 
-    throw_error (e);
+    throw_error (ee);
   }
 
   void error_system::error_1 (const char *id, const char *fmt,
@@ -619,7 +617,7 @@
   {
     std::list<frame_info> stack_info;
 
-    execution_exception e ("error", id, msg, stack_info);
+    execution_exception ee ("error", id, msg, stack_info);
 
     if (! stack.isempty ()
         && ! (stack.contains ("file") && stack.contains ("name")
@@ -627,9 +625,9 @@
       error ("rethrow: STACK struct must contain the fields 'file', 'name', and 'line'");
 
     if (! stack.isempty ())
-      e.set_stack_info (make_stack_frame_list (stack));
+      ee.set_stack_info (make_stack_frame_list (stack));
 
-    throw_error (e);
+    throw_error (ee);
   }
 
   void error_system::vpanic (const char *fmt, va_list args)
@@ -751,9 +749,13 @@
       panic_impossible ();
 
     if (nel > 1)
-      os << "\n\n";
+      {
+        os << "\n";
+        os << "Non-default warning states are:\n\n";
+        os << "  State  Warning ID\n";
+      }
 
-    // The state for all is always supposed to be first in the list.
+    // The state for "all" is always supposed to be first in the list.
 
     for (octave_idx_type i = 1; i < nel; i++)
       {
@@ -896,25 +898,41 @@
     throw ex;
   }
 
-  void error_system::save_exception (const execution_exception& e)
+  void error_system::save_exception (const execution_exception& ee)
   {
-    last_error_id (e.identifier ());
-    std::string message = e.message ();
+    last_error_id (ee.identifier ());
+    std::string message = ee.message ();
     std::string xmsg
       = (message.size () > 0 && message.back () == '\n'
          ? message.substr (0, message.size () - 1) : message);
     last_error_message (xmsg);
-    last_error_stack (make_stack_map (e.stack_info ()));
+    last_error_stack (make_stack_map (ee.stack_info ()));
   }
 
-  void error_system::display_exception (const execution_exception& e,
+  // DEPRECATED in Octave 7.
+  void error_system::display_exception (const execution_exception& ee,
                                         std::ostream& os) const
   {
     if (m_beep_on_error)
       os << "\a";
 
-    e.display (octave_diary);
-    e.display (os);
+    ee.display (octave_diary);
+    ee.display (os);
+  }
+
+  void error_system::display_exception (const execution_exception& ee) const
+  {
+    // FIXME: How should we handle beep_on_error?
+
+    ee.display (octave_diary);
+
+    // FIXME: Handle display using an event manager message so that the
+    // GUI or other client can receive error messages without needing to
+    // capture them from std::cerr or some other stream.
+
+    event_manager& evmgr = m_interpreter.get_event_manager ();
+
+    evmgr.display_exception (ee, m_beep_on_error);
   }
 }
 
@@ -974,17 +992,17 @@
 }
 
 void
-verror (octave::execution_exception& e, const char *fmt, va_list args)
+verror (octave::execution_exception& ee, const char *fmt, va_list args)
 {
-  error_1 (e, "", fmt, args);
+  error_1 (ee, "", fmt, args);
 }
 
 void
-error (octave::execution_exception& e, const char *fmt, ...)
+error (octave::execution_exception& ee, const char *fmt, ...)
 {
   va_list args;
   va_start (args, fmt);
-  verror (e, fmt, args);
+  verror (ee, fmt, args);
   va_end (args);
 }
 
@@ -1239,11 +1257,11 @@
 which will only stop execution if an error has been found.
 
 Implementation Note: For compatibility with @sc{matlab}, escape
-sequences in @var{template} (e.g., @qcode{"@xbackslashchar{}n"} =>
+sequences in @var{template} (e.g., @qcode{"@backslashchar{}n"} =>
 newline) are processed regardless of whether @var{template} has been defined
 with single quotes, as long as there are two or more input arguments.  To
 disable escape sequence expansion use a second backslash before the sequence
-(e.g., @qcode{"@xbackslashchar{}@xbackslashchar{}n"}) or use the
+(e.g., @qcode{"@backslashchar{}@backslashchar{}n"}) or use the
 @code{regexptranslate} function.
 @seealso{warning, lasterror}
 @end deftypefn */)
@@ -1377,7 +1395,7 @@
 The optional warning identifier @var{id} allows users to enable or disable
 warnings tagged by this identifier.  A message identifier is a string of the
 form @qcode{"NAMESPACE:WARNING-NAME"}.  Octave's own warnings use the
-@qcode{"Octave"} namespace (@pxref{XREFwarning_ids,,warning_ids}).  For
+@qcode{"Octave"} namespace (@pxref{XREFwarning_ids,,@code{warning_ids}}).  For
 example:
 
 @example
@@ -1452,11 +1470,11 @@
 @qcode{"off"}.
 
 Implementation Note: For compatibility with @sc{matlab}, escape sequences in
-@var{template} (e.g., @qcode{"@xbackslashchar{}n"} => newline) are processed
+@var{template} (e.g., @qcode{"@backslashchar{}n"} => newline) are processed
 regardless of whether @var{template} has been defined with single quotes, as
 long as there are two or more input arguments.  To disable escape sequence
 expansion use a second backslash before the sequence (e.g.,
-@qcode{"@xbackslashchar{}@xbackslashchar{}n"}) or use the
+@qcode{"@backslashchar{}@backslashchar{}n"}) or use the
 @code{regexptranslate} function.
 @seealso{warning_ids, lastwarn, error}
 @end deftypefn */)
@@ -1506,7 +1524,6 @@
                   octave_value curr_state = val.contents ("state");
 
                   // FIXME: this might be better with a dictionary object.
-
                   octave::tree_evaluator& tw = interp.get_evaluator ();
 
                   octave_value curr_warning_states
@@ -1560,39 +1577,28 @@
 
                   tw.set_auto_fcn_var (octave::stack_frame::SAVED_WARNING_STATES, m);
 
-                  // Now ignore the "local" argument and continue to
-                  // handle the current setting.
+                  // Now ignore the "local" argument,
+                  // and continue to handle the current setting.
                   nargin--;
                 }
             }
 
-          if (nargin >= 2 && arg2_lc == "all")
+          if ((nargin == 1
+               && (arg1 == "on" || arg1 == "off" || arg1 == "error"))
+              || (nargin >= 2 && arg2_lc == "all"))
             {
-              // If "all" is explicitly given as ID.
+              // If "all" is given implicitly or explicitly as ID.
+              if (arg1 == "error")
+                error (R"(warning: cannot specify "all" warning ID with state "error")");
 
               octave_map tmp;
-              int is_error = (arg1 == "error");
 
-              Cell id (1, 1 + 2*is_error);
-              Cell st (1, 1 + 2*is_error);
+              Cell id (1, 1);
+              Cell st (1, 1);
 
               id(0) = "all";
               st(0) = arg1;
 
-              // Since internal Octave functions are not compatible,
-              // and "all"=="error" causes any "on" to throw an error,
-              // turning all warnings into errors should disable
-              // Octave:language-extension.
-
-              if (is_error)
-                {
-                  id(1) = "Octave:language-extension";
-                  st(1) = "off";
-
-                  id(2) = "Octave:single-quote-string";
-                  st(2) = "off";
-                }
-
               tmp.assign ("identifier", id);
               tmp.assign ("state", st);
 
@@ -1648,25 +1654,63 @@
       else if (arg1 == "query")
         {
           if (arg2_lc == "all")
-            retval = es.warning_options ();
+            {
+              if (nargout > 0)
+                retval = es.warning_options ();
+              else
+                es.display_warning_options (octave_stdout);
+            }
           else if (arg2_lc == "backtrace" || arg2_lc == "debug"
                    || arg2_lc == "verbose" || arg2_lc == "quiet")
             {
-              octave_scalar_map tmp;
-              tmp.assign ("identifier", arg2_lc);
-              if (arg2_lc == "backtrace")
-                tmp.assign ("state", es.backtrace_on_warning () ? "on" : "off");
-              else if (arg2_lc == "debug")
-                tmp.assign ("state", es.debug_on_warning () ? "on" : "off");
-              else if (arg2_lc == "verbose")
-                tmp.assign ("state", es.verbose_warning () ? "on" : "off");
+              if (nargout > 0)
+                {
+                  octave_scalar_map tmp;
+                  tmp.assign ("identifier", arg2_lc);
+                  if (arg2_lc == "backtrace")
+                    tmp.assign ("state", es.backtrace_on_warning () ? "on" : "off");
+                  else if (arg2_lc == "debug")
+                    tmp.assign ("state", es.debug_on_warning () ? "on" : "off");
+                  else if (arg2_lc == "verbose")
+                    tmp.assign ("state", es.verbose_warning () ? "on" : "off");
+                  else
+                    tmp.assign ("state", es.quiet_warning () ? "on" : "off");
+
+                  retval = tmp;
+                }
               else
-                tmp.assign ("state", es.quiet_warning () ? "on" : "off");
-
-              retval = tmp;
+                {
+                  if (arg2_lc == "backtrace")
+                    octave_stdout << R"("backtrace" warning state is ")" <<
+                                  (es.backtrace_on_warning () ? "on" : "off") <<
+                                  "\"\n";
+                  else if (arg2_lc == "debug")
+                    octave_stdout << R"("debug" warning state is ")" <<
+                                  (es.debug_on_warning () ? "on" : "off") <<
+                                  "\"\n";
+                  else if (arg2_lc == "verbose")
+                    octave_stdout << R"("verbose" warning state is ")" <<
+                                  (es.verbose_warning () ? "on" : "off") <<
+                                  "\"\n";
+                  else
+                    octave_stdout << R"("quiet" warning state is ")" <<
+                                  (es.quiet_warning () ? "on" : "off") <<
+                                  "\"\n";
+                }
             }
           else
-            retval = es.warning_query (arg2);
+            {
+              if (nargout > 0)
+                retval = es.warning_query (arg2);
+              else
+                {
+                  octave_scalar_map tmp = es.warning_query (arg2);
+
+                  octave_stdout << '"' << arg2 << R"(" warning state is ")" <<
+                                   tmp.getfield ("state").string_value () <<
+                                   "\"\n";
+                }
+            }
 
           done = true;
         }
@@ -1749,9 +1793,6 @@
 }
 
 /*
-%!test <*45753>
-%! warning ("error");
-%! assert (! isempty (help ("warning")));
 
 %!test <*51997>
 %! id = "Octave:logical-conversion";
@@ -1774,6 +1815,8 @@
 %! idx = strcmp ({warnst.identifier}, "Octave:test-57290-ID");
 %! assert (warnst(idx).state, "off");
 
+%!error <cannot specify "all" warning ID> warning ("error")
+
 */
 
 octave_value_list
--- a/libinterp/corefcn/error.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/error.h	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
   {
   public:
 
-    error_system (interpreter& interp);
+    OCTINTERP_API error_system (interpreter& interp);
 
     error_system (const error_system&) = delete;
 
@@ -56,7 +56,8 @@
 
     ~error_system (void) = default;
 
-    octave_value debug_on_error (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    debug_on_error (const octave_value_list& args, int nargout);
 
     void set_debug_on_error (bool flag) { m_debug_on_error = flag; }
 
@@ -69,7 +70,8 @@
       return val;
     }
 
-    octave_value debug_on_caught (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    debug_on_caught (const octave_value_list& args, int nargout);
 
     void set_debug_on_caught (bool flag) { m_debug_on_caught = flag; }
 
@@ -82,7 +84,8 @@
       return val;
     }
 
-    octave_value debug_on_warning (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    debug_on_warning (const octave_value_list& args, int nargout);
 
     void set_debug_on_warning (bool flag) { m_debug_on_warning = flag; }
 
@@ -95,12 +98,18 @@
       return val;
     }
 
-    octave_value discard_warning_messages (const octave_value_list& args,
-                                           int nargout);
+    OCTINTERP_API octave_value
+    discard_warning_messages (const octave_value_list& args, int nargout);
 
-    void set_discard_warning_messages (bool flag) { m_discard_warning_messages = flag; }
+    void set_discard_warning_messages (bool flag)
+    {
+      m_discard_warning_messages = flag;
+    }
 
-    bool discard_warning_messages (void) const { return m_discard_warning_messages; }
+    bool discard_warning_messages (void) const
+    {
+      return m_discard_warning_messages;
+    }
 
     bool discard_warning_messages (bool flag)
     {
@@ -109,7 +118,8 @@
       return val;
     }
 
-    octave_value beep_on_error (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    beep_on_error (const octave_value_list& args, int nargout);
 
     void set_beep_on_error (bool flag) { m_beep_on_error = flag; }
 
@@ -122,7 +132,8 @@
       return val;
     }
 
-    octave_value backtrace_on_warning (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    backtrace_on_warning (const octave_value_list& args, int nargout);
 
     void set_backtrace_on_warning (bool flag) { m_backtrace_on_warning = flag; }
 
@@ -135,7 +146,8 @@
       return val;
     }
 
-    octave_value verbose_warning (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    verbose_warning (const octave_value_list& args, int nargout);
 
     void set_verbose_warning (bool flag) { m_verbose_warning = flag; }
 
@@ -148,7 +160,8 @@
       return val;
     }
 
-    octave_value quiet_warning (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    quiet_warning (const octave_value_list& args, int nargout);
 
     void set_quiet_warning (bool flag) { m_quiet_warning = flag; }
 
@@ -172,9 +185,13 @@
       return val;
     }
 
-    octave_value last_error_message (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    last_error_message (const octave_value_list& args, int nargout);
 
-    void set_last_error_message (const std::string& val) { m_last_error_message = val; }
+    void set_last_error_message (const std::string& val)
+    {
+      m_last_error_message = val;
+    }
 
     std::string last_error_message (void) const { return m_last_error_message; }
 
@@ -185,7 +202,8 @@
       return val;
     }
 
-    octave_value last_warning_message (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    last_warning_message (const octave_value_list& args, int nargout);
 
     void set_last_warning_message (const std::string& val) { m_last_warning_message = val; }
 
@@ -198,7 +216,8 @@
       return val;
     }
 
-    octave_value last_warning_id (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    last_warning_id (const octave_value_list& args, int nargout);
 
     void set_last_warning_id (const std::string& val) { m_last_warning_id = val; }
 
@@ -211,7 +230,8 @@
       return val;
     }
 
-    octave_value last_error_id (const octave_value_list& args, int nargout);
+    OCTINTERP_API octave_value
+    last_error_id (const octave_value_list& args, int nargout);
 
     void set_last_error_id (const std::string& val) { m_last_error_id = val; }
 
@@ -238,78 +258,87 @@
       return val;
     }
 
-    static octave_map
-    make_stack_map (const std::list<octave::frame_info>& frames);
+    static OCTINTERP_API octave_map
+    make_stack_map (const std::list<frame_info>& frames);
 
-    static std::list<octave::frame_info>
+    static OCTINTERP_API std::list<frame_info>
     make_stack_frame_list (const octave_map& stack);
 
     //! For given warning ID, return 0 if warnings are disabled, 1 if
     //! enabled, and 2 if the given ID should be an error instead of a
     //! warning.
 
-    int warning_enabled (const std::string& id);
+    OCTINTERP_API int warning_enabled (const std::string& id);
 
-    void verror (bool save_last_error, std::ostream& os, const char *name,
-                 const char *id, const char *fmt, va_list args,
-                 bool with_cfn = false);
+    OCTINTERP_API void
+    verror (bool save_last_error, std::ostream& os, const char *name,
+            const char *id, const char *fmt, va_list args,
+            bool with_cfn = false);
 
-    void vwarning (const char *name, const char *id, const char *fmt,
-                   va_list args);
+    OCTINTERP_API void
+    vwarning (const char *name, const char *id, const char *fmt,
+              va_list args);
 
     OCTAVE_NORETURN
-    void error_1 (execution_exception& e, const char *id, const char *fmt,
-                  va_list args);
+    OCTINTERP_API void
+    error_1 (execution_exception& ee, const char *id, const char *fmt,
+             va_list args);
 
     OCTAVE_NORETURN
-    void error_1 (const char *id, const char *fmt, va_list args);
+    OCTINTERP_API void error_1 (const char *id, const char *fmt, va_list args);
 
     OCTAVE_NORETURN
-    void vusage (const char *id, const char *fmt, va_list args);
+    OCTINTERP_API void vusage (const char *id, const char *fmt, va_list args);
 
-    void vwarning (const char *id, const char *fmt, va_list args);
+    OCTINTERP_API void vwarning (const char *id, const char *fmt, va_list args);
 
     OCTAVE_NORETURN
-    void rethrow_error (const std::string& id, const std::string& msg,
-                        const octave_map& stack);
+    OCTINTERP_API void
+    rethrow_error (const std::string& id, const std::string& msg,
+                   const octave_map& stack);
 
     OCTAVE_NORETURN
-    void vpanic (const char *fmt, va_list args);
+    OCTINTERP_API void vpanic (const char *fmt, va_list args);
 
     OCTAVE_NORETURN
-    void panic (const char *fmt, ...);
+    OCTINTERP_API void panic (const char *fmt, ...);
 
-    octave_scalar_map warning_query (const std::string& id_arg);
+    OCTINTERP_API octave_scalar_map warning_query (const std::string& id_arg);
 
-    std::string default_warning_state (void);
+    OCTINTERP_API std::string default_warning_state (void);
 
-    void display_warning_options (std::ostream& os);
+    OCTINTERP_API void display_warning_options (std::ostream& os);
 
-    void set_warning_option (const std::string& state, const std::string& id);
-
-    void disable_warning (const std::string& id);
+    OCTINTERP_API void
+    set_warning_option (const std::string& state, const std::string& id);
 
-    void initialize_default_warning_state (void);
+    OCTINTERP_API void disable_warning (const std::string& id);
 
-    void interpreter_try (octave::unwind_protect& frame);
+    OCTINTERP_API void initialize_default_warning_state (void);
+
+    OCTINTERP_API void interpreter_try (unwind_protect& frame);
 
     // Throw execution_exception or, if debug_on_error is TRUE, enter
     // debugger.  If stack_info is empty, use current call stack.
 
     OCTAVE_NORETURN
-    void throw_error (const std::string& err_type,
-                      const std::string& id,
-                      const std::string& message,
-                      const std::list<frame_info>& stack_info
-                        = std::list<frame_info> ());
+    OCTINTERP_API void
+    throw_error (const std::string& err_type,
+                 const std::string& id,
+                 const std::string& message,
+                 const std::list<frame_info>& stack_info
+                 = std::list<frame_info> ());
 
     OCTAVE_NORETURN
-    void throw_error (execution_exception& e);
+    OCTINTERP_API void throw_error (execution_exception& ee);
+
+    OCTINTERP_API void save_exception (const execution_exception& ee);
 
-    void save_exception (const execution_exception& e);
+    OCTAVE_DEPRECATED (7, "second argument is no longer accepted")
+    OCTINTERP_API void display_exception (const execution_exception& ee,
+                                          std::ostream& os) const;
 
-    void display_exception (const execution_exception& e,
-                            std::ostream& os) const;
+    OCTINTERP_API void display_exception (const execution_exception& ee) const;
 
   private:
 
--- a/libinterp/corefcn/errwarn.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/errwarn.cc	Sun May 16 09:44:35 2021 +0200
@@ -151,121 +151,121 @@
 void
 err_user_supplied_eval (const char *name)
 {
-  octave::execution_exception e;
+  octave::execution_exception ee;
 
-  err_user_supplied_eval (e, name);
+  err_user_supplied_eval (ee, name);
 }
 
 void
-err_user_supplied_eval (octave::execution_exception& e, const char *name)
+err_user_supplied_eval (octave::execution_exception& ee, const char *name)
 {
-  error (e, "%s: evaluation of user-supplied function failed", name);
+  error (ee, "%s: evaluation of user-supplied function failed", name);
 }
 
 void
 err_wrong_type_arg (const char *name, const char *s)
 {
-  octave::execution_exception e;
+  octave::execution_exception ee;
 
-  err_wrong_type_arg (e, name, s);
+  err_wrong_type_arg (ee, name, s);
 }
 
 void
-err_wrong_type_arg (octave::execution_exception& e,
+err_wrong_type_arg (octave::execution_exception& ee,
                     const char *name, const char *s)
 {
-  error (e, "%s: wrong type argument '%s'", name, s);
+  error (ee, "%s: wrong type argument '%s'", name, s);
 }
 
 void
 err_wrong_type_arg (const char *name, const std::string& s)
 {
-  octave::execution_exception e;
+  octave::execution_exception ee;
 
-  err_wrong_type_arg (e, name, s.c_str ());
+  err_wrong_type_arg (ee, name, s.c_str ());
 }
 
 void
-err_wrong_type_arg (octave::execution_exception& e,
+err_wrong_type_arg (octave::execution_exception& ee,
                     const char *name, const std::string& s)
 {
-  err_wrong_type_arg (e, name, s.c_str ());
+  err_wrong_type_arg (ee, name, s.c_str ());
 }
 
 void
 err_wrong_type_arg (const char *name, const octave_value& tc)
 {
-  octave::execution_exception e;
+  octave::execution_exception ee;
 
-  err_wrong_type_arg (e, name, tc);
+  err_wrong_type_arg (ee, name, tc);
 }
 
 void
-err_wrong_type_arg (octave::execution_exception& e,
+err_wrong_type_arg (octave::execution_exception& ee,
                     const char *name, const octave_value& tc)
 {
   std::string type = tc.type_name ();
 
-  err_wrong_type_arg (e, name, type);
+  err_wrong_type_arg (ee, name, type);
 }
 
 void
 err_wrong_type_arg (const std::string& name, const octave_value& tc)
 {
-  octave::execution_exception e;
+  octave::execution_exception ee;
 
-  err_wrong_type_arg (e, name, tc);
+  err_wrong_type_arg (ee, name, tc);
 }
 
 void
-err_wrong_type_arg (octave::execution_exception& e,
+err_wrong_type_arg (octave::execution_exception& ee,
                     const std::string& name, const octave_value& tc)
 {
-  err_wrong_type_arg (e, name.c_str (), tc);
+  err_wrong_type_arg (ee, name.c_str (), tc);
 }
 
 void
 err_wrong_type_arg (const char *s)
 {
-  octave::execution_exception e;
+  octave::execution_exception ee;
 
-  err_wrong_type_arg (e, s);
+  err_wrong_type_arg (ee, s);
 }
 
 void
-err_wrong_type_arg (octave::execution_exception& e, const char *s)
+err_wrong_type_arg (octave::execution_exception& ee, const char *s)
 {
-  error (e, "wrong type argument '%s'", s);
+  error (ee, "wrong type argument '%s'", s);
 }
 
 void
 err_wrong_type_arg (const std::string& s)
 {
-  octave::execution_exception e;
+  octave::execution_exception ee;
 
-  err_wrong_type_arg (e, s);
+  err_wrong_type_arg (ee, s);
 }
 
 void
-err_wrong_type_arg (octave::execution_exception& e, const std::string& s)
+err_wrong_type_arg (octave::execution_exception& ee, const std::string& s)
 {
-  err_wrong_type_arg (e, s.c_str ());
+  err_wrong_type_arg (ee, s.c_str ());
 }
 
 void
 err_wrong_type_arg (const octave_value& tc)
 {
-  octave::execution_exception e;
+  octave::execution_exception ee;
 
-  err_wrong_type_arg (e, tc);
+  err_wrong_type_arg (ee, tc);
 }
 
 void
-err_wrong_type_arg (octave::execution_exception& e, const octave_value& tc)
+err_wrong_type_arg (octave::execution_exception& ee, const octave_value& tc)
 {
   std::string type = tc.type_name ();
 
-  err_wrong_type_arg (e, type);
+  err_wrong_type_arg (ee, type);
 }
 
 void
--- a/libinterp/corefcn/errwarn.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/errwarn.h	Sun May 16 09:44:35 2021 +0200
@@ -42,150 +42,150 @@
 // Alphabetized list of common errors and warnings.
 ////////////////////////////////////////////////////////////////////////////////
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_2_or_3_dim_plot (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_data_conversion (const char *from, const char *to);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_disabled_feature (const std::string& fcn, const std::string& feature,
                       const std::string& pkg = "Octave");
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_indexed_cs_list (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_invalid_conversion (const std::string& from, const std::string& to);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_invalid_inquiry_subscript (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_invalid_structure_assignment (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_nonbraced_cs_list_assignment (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_nonconformant (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_nonconformant (octave_idx_type r1, octave_idx_type c1,
                    octave_idx_type r2, octave_idx_type c2);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_not_implemented (const char *);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_range_invalid (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_square_matrix_required (const char *fcn, const char *name);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_string_invalid (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_unrecognized_data_fmt (const char *name);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_unrecognized_float_fmt (void);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_user_returned_invalid (const char *name);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_user_supplied_eval (const char *name);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
-err_user_supplied_eval (octave::execution_exception& e, const char *name);
+OCTAVE_NORETURN extern OCTINTERP_API void
+err_user_supplied_eval (octave::execution_exception& ee, const char *name);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg (const char *name, const char *s);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
-err_wrong_type_arg (octave::execution_exception& e, const char *name,
+OCTAVE_NORETURN extern OCTINTERP_API void
+err_wrong_type_arg (octave::execution_exception& ee, const char *name,
                     const char *s);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg (const char *name, const std::string& s);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
-err_wrong_type_arg (octave::execution_exception& e, const char *name,
+OCTAVE_NORETURN extern OCTINTERP_API void
+err_wrong_type_arg (octave::execution_exception& ee, const char *name,
                     const std::string& s);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg (const char *name, const octave_value& tc);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
-err_wrong_type_arg (octave::execution_exception& e, const char *name,
+OCTAVE_NORETURN extern OCTINTERP_API void
+err_wrong_type_arg (octave::execution_exception& ee, const char *name,
                     const octave_value& tc);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg (const std::string& name, const octave_value& tc);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
-err_wrong_type_arg (octave::execution_exception& e, const std::string& name,
+OCTAVE_NORETURN extern OCTINTERP_API void
+err_wrong_type_arg (octave::execution_exception& ee, const std::string& name,
                     const octave_value& tc);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg (const char *s);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
-err_wrong_type_arg (octave::execution_exception& e, const char *s);
+OCTAVE_NORETURN extern OCTINTERP_API void
+err_wrong_type_arg (octave::execution_exception& ee, const char *s);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg (const std::string& s);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
-err_wrong_type_arg (octave::execution_exception& e, const std::string& s);
+OCTAVE_NORETURN extern OCTINTERP_API void
+err_wrong_type_arg (octave::execution_exception& ee, const std::string& s);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg (const octave_value& tc);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
-err_wrong_type_arg (octave::execution_exception& e, const octave_value& tc);
+OCTAVE_NORETURN extern OCTINTERP_API void
+err_wrong_type_arg (octave::execution_exception& ee, const octave_value& tc);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg_for_binary_op (const octave_value& op);
 
-OCTAVE_NORETURN OCTINTERP_API extern void
+OCTAVE_NORETURN extern OCTINTERP_API void
 err_wrong_type_arg_for_unary_op (const octave_value& op);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_array_as_logical (const dim_vector& dv);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_complex_cmp (void);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_data_file_in_path (const std::string& fcn, const std::string& file);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_disabled_feature (const std::string& fcn, const std::string& feature,
                        const std::string& pkg = "Octave");
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_empty_arg (const char *name);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_empty_index (const std::string& type_name);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_implicit_conversion (const char *id, const char *from, const char *to);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_implicit_conversion (const std::string& id, const std::string& from,
                           const std::string& to);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_invalid_value_specified (const char *name);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_logical_conversion (void);
 
-OCTINTERP_API extern void
+extern OCTINTERP_API void
 warn_wrong_type_arg (const char *name, const octave_value& tc);
 
 #if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
--- a/libinterp/corefcn/event-manager.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/event-manager.cc	Sun May 16 09:44:35 2021 +0200
@@ -27,8 +27,11 @@
 #  include "config.h"
 #endif
 
+#include <iostream>
+
 #include "builtin-defun-decls.h"
 #include "cmd-edit.h"
+#include "cmd-hist.h"
 #include "defun.h"
 #include "event-manager.h"
 #include "interpreter.h"
@@ -39,6 +42,8 @@
 #include "pager.h"
 #include "syminfo.h"
 
+#include "quit.h"
+
 namespace octave
 {
   static int readline_event_hook (void)
@@ -50,11 +55,22 @@
     return 0;
   }
 
+  void interpreter_events::display_exception (const execution_exception& ee,
+                                              bool beep)
+  {
+    if (beep)
+      std::cerr << "\a";
+
+    ee.display (std::cerr);
+  }
+
   event_manager::event_manager (interpreter& interp)
-    : m_interpreter (interp), instance (nullptr),
+    : m_interpreter (interp), instance (new interpreter_events ()),
+      m_qt_event_handlers (),
       event_queue_mutex (new mutex ()), gui_event_queue (),
-      debugging (false), link_enabled (false)
+      debugging (false), link_enabled (true)
   {
+    push_event_queue ();
     command_editor::add_event_hook (readline_event_hook);
   }
 
@@ -98,10 +114,10 @@
           disable ();
 
         event_queue_mutex->lock ();
+        std::shared_ptr<event_queue> evq = gui_event_queue.top ();
+        event_queue_mutex->unlock ();
 
-        gui_event_queue.run ();
-
-        event_queue_mutex->unlock ();
+        evq->run ();
       }
   }
 
@@ -110,10 +126,49 @@
     if (enabled ())
       {
         event_queue_mutex->lock ();
+        std::shared_ptr<event_queue> evq = gui_event_queue.top ();
+        event_queue_mutex->unlock ();
 
-        gui_event_queue.discard ();
+        evq->discard ();
+      }
+  }
+
+  void event_manager::push_event_queue (void)
+  {
+    std::shared_ptr<event_queue> evq (new event_queue ());
+    gui_event_queue.push (evq);
+  }
 
-        event_queue_mutex->unlock ();
+  void event_manager::pop_event_queue (void)
+  {
+    // FIXME: Should we worry about the possibility of events remaining
+    // in the queue when we pop back to the previous queue?  If so, then
+    // we will probably want to push them on to the front of the
+    // previous queue so they will be executed before any other events
+    // that were in the previous queue.  This case could happen if
+    // graphics callback functions were added to the event queue during a
+    // debug session just after a dbcont command was added but before it
+    // executed and brought us here, for example.
+
+    std::shared_ptr<event_queue> evq = gui_event_queue.top ();
+    gui_event_queue.pop ();
+  }
+
+  void event_manager::post_event (const fcn_callback& fcn)
+  {
+    if (enabled ())
+      {
+        std::shared_ptr<event_queue> evq = gui_event_queue.top ();
+        evq->add (fcn);
+      }
+  }
+
+  void event_manager::post_event (const meth_callback& meth)
+  {
+    if (enabled ())
+      {
+        std::shared_ptr<event_queue> evq = gui_event_queue.top ();
+        evq->add (std::bind (meth, std::ref (m_interpreter)));
       }
   }
 
@@ -129,6 +184,40 @@
   }
 }
 
+// FIXME: Should the following function be __event_manager_desktop__
+// with the desktop function implemented in a .m file, similar to the
+// way the UI* functions work?
+
+DEFMETHOD (desktop, interp, , ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} desktop ()
+If running in command-line mode, start the GUI desktop.
+@end deftypefn */)
+{
+  if (interp.experimental_terminal_widget ())
+    {
+      if (! octave::application::is_gui_running ())
+        {
+          // FIXME: Currently, the following action is queued and
+          // executed in a Qt event loop and we return immediately to
+          // the command prompt where additional commands may be
+          // executed.  Is that what should happen?  Or should we be
+          // waiting until the GUI exits to return to the command
+          // prompt, similar to the way the UI* functions work?
+
+          octave::event_manager& evmgr = interp.get_event_manager ();
+
+          evmgr.start_gui ();
+        }
+      else
+        warning ("GUI desktop is already running");
+    }
+  else
+    error ("desktop function requires new experimental terminal widget");
+
+  return ovl ();
+}
+
 DEFMETHOD (__event_manager_enabled__, interp, , ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {} __event_manager_enabled__ ()
@@ -506,19 +595,14 @@
 
   std::string name = args(0).string_value ();
 
-  if (! (Fisguirunning ())(0).is_true ())
-    warning ("openvar: GUI is not running, can't start Variable Editor");
-  else
-    {
-      octave_value val = interp.varval (name);
+  octave_value val = interp.varval (name);
 
-      if (val.is_undefined ())
-        error ("openvar: '%s' is not a variable", name.c_str ());
+  if (val.is_undefined ())
+    error ("openvar: '%s' is not a variable", name.c_str ());
 
-      octave::event_manager& evmgr = interp.get_event_manager ();
+  octave::event_manager& evmgr = interp.get_event_manager ();
 
-      evmgr.edit_variable (name, val);
-    }
+  evmgr.edit_variable (name, val);
 
   return ovl ();
 }
@@ -529,9 +613,41 @@
 %!error <NAME must be a string> openvar (1:10)
 */
 
-DEFMETHOD (__event_manager_show_doc__, interp, args, ,
+DEFMETHOD (__event_manager_show_documentation__, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __event_manager_show_documentation__ (@var{filename})
+Undocumented internal function.
+@end deftypefn */)
+{
+  std::string file;
+
+  if (args.length () >= 1)
+    file = args(0).string_value();
+
+  octave::event_manager& evmgr = interp.get_event_manager ();
+
+  return ovl (evmgr.show_documentation (file));
+}
+
+DEFMETHOD (__event_manager_register_documentation__, interp, args, ,
            doc: /* -*- texinfo -*-
-@deftypefn {} {} __event_manager_show_doc__ (@var{filename})
+@deftypefn {} {} __event_manager_register_documentation__ (@var{filename})
+Undocumented internal function.
+@end deftypefn */)
+{
+  std::string file;
+
+  if (args.length () >= 1)
+    file = args(0).string_value();
+
+  octave::event_manager& evmgr = interp.get_event_manager ();
+
+  return ovl (evmgr.register_documentation (file));
+}
+
+DEFMETHOD (__event_manager_unregister_documentation__, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __event_manager_unregister_documentation__ (@var{filename})
 Undocumented internal function.
 @end deftypefn */)
 {
@@ -542,39 +658,91 @@
 
   octave::event_manager& evmgr = interp.get_event_manager ();
 
-  return ovl (evmgr.show_doc (file));
+  return ovl (evmgr.unregister_documentation (file));
+}
+
+DEFMETHOD (__event_manager_show_file_browser__, interp, , ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __event_manager_show_file_browser__ ()
+Undocumented internal function.
+@end deftypefn */)
+{
+  octave::event_manager& evmgr = interp.get_event_manager ();
+
+  evmgr.show_file_browser ();
+
+  return ovl ();
 }
 
-DEFMETHOD (__event_manager_register_doc__, interp, args, ,
+DEFMETHOD (__event_manager_show_command_history__, interp, , ,
            doc: /* -*- texinfo -*-
-@deftypefn {} {} __event_manager_register_doc__ (@var{filename})
+@deftypefn {} {} __event_manager_show_command_history__ ()
+Undocumented internal function.
+@end deftypefn */)
+{
+  octave::event_manager& evmgr = interp.get_event_manager ();
+
+  evmgr.show_command_history ();
+
+  return ovl ();
+}
+
+DEFMETHOD (__event_manager_show_workspace__, interp, , ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __event_manager_show_workspace__ ()
 Undocumented internal function.
 @end deftypefn */)
 {
-  std::string file;
+  octave::event_manager& evmgr = interp.get_event_manager ();
+
+  evmgr.show_workspace ();
+
+  return ovl ();
+}
 
-  if (args.length () >= 1)
-    file = args(0).string_value();
+DEFMETHOD (__event_manager_gui_status_update__, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __event_manager_gui_status_update__ (@var{feature}, @var{status})
+Internal function for updating the status of some features in the GUI.
+@end deftypefn */)
+{
+  // This is currently a stub and should only be activated some
+  // interpreter action only implemented in m-files requires to update
+  // a status indicator in the gui. BUT: This internal function can
+  // be activated by the user leading to gui indicators not reflecting
+  // the real state of the related feature.
+  return ovl ();
+
+  std::string feature;
+  std::string status;
+
+  if (! (Fisguirunning ())(0).is_true ())
+    return ovl ();
+
+  if (args.length () < 2)
+    error ("__event_manager_gui_status_update__: two parameters required");
+  if (! (args(0).is_string ()))
+    error ("__event_manager_gui_status_update__: FEATURE must be a string");
+  if (! (args(1).is_string ()))
+    error ("__event_manager_gui_status_update__: STATUS must be a string");
+
+  feature = args(0).string_value ();
+  status = args(1).string_value ();
 
   octave::event_manager& evmgr = interp.get_event_manager ();
 
-  return ovl (evmgr.register_doc (file));
+  return ovl (evmgr.gui_status_update (feature, status));
 }
 
-DEFMETHOD (__event_manager_unregister_doc__, interp, args, ,
+DEFMETHOD (__event_manager_update_gui_lexer__, interp, , ,
            doc: /* -*- texinfo -*-
-@deftypefn {} {} __event_manager_unregister_doc__ (@var{filename})
+@deftypefn {} {} __event_manager_update_gui_lexer__ ()
 Undocumented internal function.
 @end deftypefn */)
 {
-  std::string file;
-
-  if (args.length () >= 1)
-    file = args(0).string_value();
-
   octave::event_manager& evmgr = interp.get_event_manager ();
 
-  return ovl (evmgr.unregister_doc (file));
+  return ovl (evmgr.update_gui_lexer ());
 }
 
 DEFMETHOD (__event_manager_copy_image_to_clipboard__, interp, args, ,
--- a/libinterp/corefcn/event-manager.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/event-manager.h	Sun May 16 09:44:35 2021 +0200
@@ -31,6 +31,7 @@
 #include <functional>
 #include <list>
 #include <memory>
+#include <stack>
 #include <string>
 
 #include "oct-mutex.h"
@@ -44,8 +45,9 @@
 namespace octave
 {
   typedef std::function<void (void)> fcn_callback;
-  typedef std::function<void (octave::interpreter&)> meth_callback;
+  typedef std::function<void (interpreter&)> meth_callback;
 
+  class execution_exception;
   class symbol_info_list;
 
   // The methods in this class provide a way to pass signals to the GUI
@@ -73,7 +75,7 @@
   // FIXME: audit this list of functions and determine whether they are
   // all necessary and whether there might be better names for them.
 
-  class interpreter_events
+  class OCTINTERP_API interpreter_events
   {
   public:
 
@@ -85,6 +87,17 @@
 
     virtual ~interpreter_events (void) = default;
 
+    // Note: START_GUI and CLOSE_GUI currently only work with the new
+    // experimental terminal widget.
+
+    // Set GUI_APP to true when starting Octave as a gui application
+    // (invoked with the --gui option) and false when starting the GUI
+    // from the Octave prompt when Octave is already running as a
+    // command line application.
+
+    virtual void start_gui (bool /*gui_app*/ = false) { }
+    virtual void close_gui (void) { }
+
     // Dialogs.
 
     typedef std::list<std::pair<std::string, std::string>> filter_list;
@@ -135,7 +148,16 @@
 
     virtual void apply_preferences (void) { }
 
-    virtual void show_doc (const std::string& /*file*/) { }
+    virtual bool show_documentation (const std::string& /*file*/)
+    {
+      return false;
+    }
+
+    virtual void show_file_browser (void) { }
+
+    virtual void show_command_history (void) { }
+
+    virtual void show_workspace (void) { }
 
     virtual bool edit_file (const std::string& /*file*/) { return false; }
 
@@ -147,7 +169,7 @@
     // confirmation before another action.  Could these be reformulated
     // using the question_dialog action?
 
-    virtual bool confirm_shutdown (void) { return false; }
+    virtual bool confirm_shutdown (void) { return true; }
 
     virtual bool prompt_new_edit_file (const std::string& /*file*/)
     {
@@ -191,9 +213,18 @@
     virtual void
     execute_command_in_terminal (const std::string& /*command*/) { }
 
-    virtual void register_doc (const std::string& /*file*/) { }
+    virtual void register_documentation (const std::string& /*file*/) { }
+
+    virtual void unregister_documentation (const std::string& /*file*/) { }
+
+    virtual void interpreter_output (const std::string& /*msg*/) { }
 
-    virtual void unregister_doc (const std::string& /*file*/) { }
+    virtual void display_exception (const execution_exception& ee, bool beep);
+
+    virtual void gui_status_update (const std::string& /*feature*/,
+                                    const std::string& /*status*/) { }
+
+    virtual void update_gui_lexer (void) { }
 
     // Notifications of events in the interpreter that a GUI will
     // normally wish to respond to.
@@ -208,12 +239,14 @@
 
     virtual void
     set_workspace (bool /*top_level*/, bool /*debug*/,
-                   const octave::symbol_info_list& /*syminfo*/,
+                   const symbol_info_list& /*syminfo*/,
                    bool /*update_variable_editor*/)
     { }
 
     virtual void clear_workspace (void) { }
 
+    virtual void update_prompt (const std::string& /*prompt*/) { }
+
     virtual void set_history (const string_vector& /*hist*/) { }
 
     virtual void append_history (const std::string& /*hist_entry*/) { }
@@ -239,6 +272,8 @@
     update_breakpoint (bool /*insert*/, const std::string& /*file*/,
                        int /*line*/, const std::string& /*cond*/)
     { }
+
+    virtual void interpreter_interrupted (void) { }
   };
 
   //! Provides threadsafe access to octave.
@@ -250,7 +285,7 @@
   {
   public:
 
-    event_manager (interpreter& interp);
+    OCTINTERP_API event_manager (interpreter& interp);
 
     // No copying!
 
@@ -265,9 +300,10 @@
     // class interpreter_events, or nullptr to disconnect and delete the
     // previous link.
 
-    void connect_link (const std::shared_ptr<interpreter_events>& obj);
+    OCTINTERP_API void
+    connect_link (const std::shared_ptr<interpreter_events>& obj);
 
-    bool enable (void);
+    OCTINTERP_API bool enable (void);
 
     bool disable (void)
     {
@@ -281,29 +317,36 @@
       return link_enabled;
     }
 
+    // Make the Qt actions available for others.  This is a temporary
+    // solution to allow Qt actions like opening the documentation
+    // browser when the primary interpreter_events object is not the one
+    // defined for the Qt GUI.
+    void
+    install_qt_event_handlers (const std::shared_ptr<interpreter_events>& obj)
+    {
+      m_qt_event_handlers = obj;
+    }
+
+    std::shared_ptr<interpreter_events>
+    qt_event_handlers (void) const { return m_qt_event_handlers; }
+
     // If disable is TRUE, then no additional events will be processed
     // other than exit.
 
-    void process_events (bool disable = false);
+    OCTINTERP_API void process_events (bool disable = false);
 
-    void discard_events (void);
+    OCTINTERP_API void discard_events (void);
 
     // The post_event and post_exception functions provide a thread-safe
     // way for the GUI to queue interpreter functions for execution.
     // The queued functions are executed when the interpreter is
     // otherwise idle.
 
-    void post_event (const fcn_callback& fcn)
-    {
-      if (enabled ())
-        gui_event_queue.add (fcn);
-    }
+    void push_event_queue (void);
+    void pop_event_queue (void);
 
-    void post_event (const meth_callback& meth)
-    {
-      if (enabled ())
-        gui_event_queue.add (std::bind (meth, std::ref (m_interpreter)));
-    }
+    OCTINTERP_API void post_event (const fcn_callback& fcn);
+    OCTINTERP_API void post_event (const meth_callback& meth);
 
     // The following functions correspond to the virtual fuunctions in
     // the interpreter_events class.  They provide a way for the
@@ -314,6 +357,22 @@
     // Please keep this list of declarations in the same order as the
     // ones above in the interpreter_events class.
 
+
+    // Note: START_GUI and CLOSE_GUI currently only work with the new
+    // experimental terminal object.
+
+    void start_gui (bool gui_app = false)
+    {
+      if (enabled ())
+        instance->start_gui (gui_app);
+    }
+
+    void close_gui (void)
+    {
+      if (enabled ())
+        instance->close_gui ();
+    }
+
     typedef std::list<std::pair<std::string, std::string>> filter_list;
 
     std::list<std::string>
@@ -369,7 +428,7 @@
 
     void update_path_dialog (void)
     {
-      if (octave::application::is_gui_running () && enabled ())
+      if (application::is_gui_running () && enabled ())
         instance->update_path_dialog ();
     }
 
@@ -395,15 +454,27 @@
         return false;
     }
 
-    bool show_doc (const std::string& file)
+    bool show_documentation (const std::string& file)
+    {
+      return enabled () ? instance->show_documentation (file) : false;
+    }
+
+    void show_file_browser (void)
     {
       if (enabled ())
-        {
-          instance->show_doc (file);
-          return true;
-        }
-      else
-        return false;
+        instance->show_file_browser ();
+    }
+
+    void show_command_history (void)
+    {
+      if (enabled ())
+        instance->show_command_history ();
+    }
+
+    void show_workspace (void)
+    {
+      if (enabled ())
+        instance->show_workspace ();
     }
 
     bool edit_file (const std::string& file)
@@ -475,27 +546,70 @@
         instance->execute_command_in_terminal (command);
     }
 
-    bool register_doc (const std::string& file)
+    bool register_documentation (const std::string& file)
     {
       if (enabled ())
         {
-          instance->register_doc (file);
+          instance->register_documentation (file);
+          return true;
+        }
+      else
+        return false;
+    }
+
+    bool unregister_documentation (const std::string& file)
+    {
+      if (enabled ())
+        {
+          instance->unregister_documentation (file);
           return true;
         }
       else
         return false;
     }
 
-    bool unregister_doc (const std::string& file)
+    bool interpreter_output (const std::string& msg)
     {
       if (enabled ())
         {
-          instance->unregister_doc (file);
+          instance->interpreter_output (msg);
+          return true;
+        }
+      else
+        return false;
+    }
+
+    bool display_exception (const execution_exception& ee, bool beep = false)
+    {
+      if (enabled ())
+        {
+          instance->display_exception (ee, beep);
           return true;
         }
       else
         return false;
+    }
 
+    bool gui_status_update (const std::string& feature, const std::string& status)
+    {
+      if (enabled ())
+        {
+          instance->gui_status_update (feature, status);
+          return true;
+        }
+      else
+        return false;
+    }
+
+    bool update_gui_lexer (void)
+    {
+      if (enabled ())
+        {
+          instance->update_gui_lexer ();
+          return true;
+        }
+      else
+        return false;
     }
 
     void directory_changed (const std::string& dir)
@@ -507,19 +621,19 @@
     // Methods for removing/renaming files which might be open in editor
     void file_remove (const std::string& old_name, const std::string& new_name)
     {
-      if (octave::application::is_gui_running () && enabled ())
+      if (application::is_gui_running () && enabled ())
         instance->file_remove (old_name, new_name);
     }
 
     void file_renamed (bool load_new)
     {
-      if (octave::application::is_gui_running () && enabled ())
+      if (application::is_gui_running () && enabled ())
         instance->file_renamed (load_new);
     }
 
-    void set_workspace (void);
+    OCTINTERP_API void set_workspace (void);
 
-    void set_workspace (bool top_level, const octave::symbol_info_list& syminfo,
+    void set_workspace (bool top_level, const symbol_info_list& syminfo,
                         bool update_variable_editor = true)
     {
       if (enabled ())
@@ -533,6 +647,12 @@
         instance->clear_workspace ();
     }
 
+    void update_prompt (const std::string& prompt)
+    {
+      if (enabled ())
+        instance->update_prompt (prompt);
+    }
+
     void set_history (const string_vector& hist)
     {
       if (enabled ())
@@ -597,6 +717,12 @@
         instance->update_breakpoint (insert, file, line, cond);
     }
 
+    void interpreter_interrupted (void)
+    {
+      if (enabled ())
+        instance->interpreter_interrupted ();
+    }
+
   private:
 
     interpreter& m_interpreter;
@@ -606,13 +732,24 @@
 
     std::shared_ptr<interpreter_events> instance;
 
+    std::shared_ptr<interpreter_events> m_qt_event_handlers;
+
   protected:
 
     // Semaphore to lock access to the event queue.
-    octave::mutex *event_queue_mutex;
+    mutex *event_queue_mutex;
 
-    // Event Queue.
-    octave::event_queue gui_event_queue;
+    // Event Queue.  We use a stack so that we can handle evaluation in
+    // the debugger when we are executing in server mode.  In server
+    // mode, code is evaluated from inside the event queue.  So when the
+    // evaluator reaches a breakpoint, the queue is already locked and
+    // executing an event function.  We can't just add a new command to the
+    // existing queue, so we need another one that can process new
+    // events generated at the debug prompt.  When execution continues
+    // (dbcont or dbstep, for example) we pop the queue and return to
+    // the previous point of execution.
+
+    std::stack<std::shared_ptr <event_queue>> gui_event_queue;
 
     bool debugging;
     bool link_enabled;
--- a/libinterp/corefcn/fcn-info.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/fcn-info.cc	Sun May 16 09:44:35 2021 +0200
@@ -86,7 +86,7 @@
 
     tmpfcn->mark_as_private_function (class_name);
 
-    private_functions[octave::sys::canonicalize_file_name (dir_name)] = ov_fcn;
+    private_functions[sys::canonicalize_file_name (dir_name)] = ov_fcn;
 
     return ov_fcn;
   }
@@ -409,21 +409,59 @@
   // would not check for it when finding symbol definitions.
 
   static inline bool
-  load_out_of_date_fcn (const std::string& ff, const std::string& dir_name,
+  load_out_of_date_fcn (const std::string& file_name,
+                        const std::string& dir_name_arg,
                         octave_value& function,
                         const std::string& dispatch_type = "",
                         const std::string& package_name = "")
   {
     bool retval = false;
 
+    std::string dir_name = dir_name_arg;
+
+    if (dir_name.empty ())
+      {
+        std::size_t pos = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
+
+        dir_name = file_name.substr (0, pos);
+      }
+
+    // FIXME: do the following job of determining private status and
+    // class membership in a separate function?
+
+    std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
+
+    bool is_private_fcn
+      = pos != std::string::npos && dir_name.substr (pos+1) == "private";
+
+    if (is_private_fcn)
+      dir_name = dir_name.substr (0, pos);
+
+    std::string class_name;
+
+    pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
+
+    if (pos != std::string::npos)
+      {
+        std::string tmp = dir_name.substr (pos+1);
+
+        if (tmp[0] == '@')
+          class_name = tmp.substr (1);
+      }
+
     octave_value ov_fcn
-      = load_fcn_from_file (ff, dir_name, dispatch_type,
+      = load_fcn_from_file (file_name, dir_name, dispatch_type,
                             package_name);
 
     if (ov_fcn.is_defined ())
       {
         retval = true;
 
+        octave_function *fcn = ov_fcn.function_value ();
+
+        if (is_private_fcn)
+          fcn->mark_as_private_function (class_name);
+
         function = ov_fcn;
       }
     else
@@ -613,8 +651,8 @@
                         bp_table& bptab
                           = __get_bp_table__ ("out_of_date_check");
 
-                        bptab.remove_all_breakpoints_in_file (canonical_nm,
-                                                              true);
+                        bptab.remove_all_breakpoints_from_function (canonical_nm,
+                                                                    true);
                       }
                   }
               }
@@ -1185,7 +1223,7 @@
 %! ignore_function_time_stamp (old_state);
 
 ## Test input validation
-%!error (ignore_function_time_stamp ("all", "all"))
-%!error (ignore_function_time_stamp ("UNKNOWN_VALUE"))
-%!error (ignore_function_time_stamp (42))
+%!error ignore_function_time_stamp ("all", "all")
+%!error ignore_function_time_stamp ("UNKNOWN_VALUE")
+%!error ignore_function_time_stamp (42)
 */
--- a/libinterp/corefcn/fft.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/fft.cc	Sun May 16 09:44:35 2021 +0200
@@ -110,10 +110,10 @@
     {
       octave_value_list idx (ndims);
       for (octave_idx_type i = 0; i < ndims; i++)
-        idx(i) = idx_vector::colon;
-      idx(dim) = idx_vector (static_cast<octave_idx_type> (0));
+        idx(i) = octave::idx_vector::colon;
+      idx(dim) = octave::idx_vector (static_cast<octave_idx_type> (0));
 
-      return arg.do_index_op (idx);
+      return arg.index_op (idx);
     }
 
   if (arg.is_single_type ())
@@ -187,7 +187,7 @@
 %!testif HAVE_FFTW
 %! assert (fft (eye (2,2,"single")), single ([1,1; 1,-1]))
 
-%!error (fft ())
+%!error fft ()
 */
 
 
--- a/libinterp/corefcn/file-io.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/file-io.cc	Sun May 16 09:44:35 2021 +0200
@@ -273,7 +273,8 @@
 
 If there are no more characters to read, @code{fgetl} returns @minus{}1.
 
-To read a line and return the terminating newline see @code{fgets}.
+To read a line and return the terminating newline,
+@pxref{XREFfgets,,@code{fgets}}.
 @seealso{fgets, fscanf, fread, fopen}
 @end deftypefn */)
 {
@@ -315,7 +316,8 @@
 
 If there are no more characters to read, @code{fgets} returns @minus{}1.
 
-To read a line and discard the terminating newline see @code{fgetl}.
+To read a line and discard the terminating newline,
+@pxref{XREFfgetl,,@code{fgetl}}.
 @seealso{fputs, fgetl, fscanf, fread, fopen}
 @end deftypefn */)
 {
@@ -832,7 +834,7 @@
 The optional output returns the number of bytes written to the file.
 
 Implementation Note: For compatibility with @sc{matlab}, escape sequences in
-the template string (e.g., @qcode{"@xbackslashchar{}n"} => newline) are
+the template string (e.g., @qcode{"@backslashchar{}n"} => newline) are
 expanded even when the template string is defined with single quotes.
 @seealso{fputs, fdisp, fwrite, fscanf, printf, sprintf, fopen}
 @end deftypefn */)
@@ -855,7 +857,7 @@
 @end ifclear
 
 Implementation Note: For compatibility with @sc{matlab}, escape sequences in
-the template string (e.g., @qcode{"@xbackslashchar{}n"} => newline) are
+the template string (e.g., @qcode{"@backslashchar{}n"} => newline) are
 expanded even when the template string is defined with single quotes.
 @seealso{fprintf, sprintf, scanf}
 @end deftypefn */)
@@ -932,7 +934,7 @@
 string, automatically sized to hold all of the items converted.
 
 Implementation Note: For compatibility with @sc{matlab}, escape sequences in
-the template string (e.g., @qcode{"@xbackslashchar{}n"} => newline) are
+the template string (e.g., @qcode{"@backslashchar{}n"} => newline) are
 expanded even when the template string is defined with single quotes.
 @seealso{printf, fprintf, sscanf}
 @end deftypefn */)
@@ -1444,12 +1446,12 @@
 @item @qcode{"EndOfLine"}
 @var{value} can be either an empty or one character specifying the
 end-of-line character, or the pair
-@qcode{"@xbackslashchar{}r@xbackslashchar{}n"} (CRLF).
+@qcode{"@backslashchar{}r@backslashchar{}n"} (CRLF).
 In the latter case, any of
-@qcode{"@xbackslashchar{}r"}, @qcode{"@xbackslashchar{}n"} or
-@qcode{"@xbackslashchar{}r@xbackslashchar{}n"} is counted as a (single)
+@qcode{"@backslashchar{}r"}, @qcode{"@backslashchar{}n"} or
+@qcode{"@backslashchar{}r@backslashchar{}n"} is counted as a (single)
 newline.  If no value is given,
-@qcode{"@xbackslashchar{}r@xbackslashchar{}n"} is used.
+@qcode{"@backslashchar{}r@backslashchar{}n"} is used.
 @c If set to "" (empty string) EOLs are ignored as delimiters and added
 @c to whitespace.
 
@@ -1487,7 +1489,7 @@
 @c Note: the next line specifically has a newline which generates a space
 @c       in the output of qcode, but keeps the next line < 80 characters.
 @qcode{"
-@xbackslashchar{}b@xbackslashchar{}r@xbackslashchar{}n@xbackslashchar{}t"}
+@backslashchar{}b@backslashchar{}r@backslashchar{}n@backslashchar{}t"}
 (note the space).  Unless whitespace is set to @qcode{""} (empty) AND at
 least one @qcode{"%s"} format conversion specifier is supplied, a space is
 always part of whitespace.
@@ -1641,8 +1643,10 @@
 %! c = textscan (str, "%4f %f", "delimiter", ";", "collectOutput", 1);
 %! assert (c, {[12, 34; 1234, 56789; 7, NaN]});
 
+## FIXME: Not Matlab compatible.  Matlab prioritizes precision over field width
+## so "12.234e+2", when read with "%10.2f %f", yields "12.23" and "4e+2".
 ## Ignore trailing delimiter, but use leading one
-%!test
+%!#test
 %! str = "12.234e+2,34, \n12345.789-9876j,78\n,10|3";
 %! c = textscan (str, "%10.2f %f", "delimiter", ",", "collectOutput", 1,
 %!                    "expChars", "e|");
@@ -2285,7 +2289,46 @@
 %! obs = textscan (str, "%q", "delimiter", ",");
 %! assert (obs, { { "a,b"; "c" } });
 
+%!test <*58008>
+%! txt = sprintf ('literal_other_1_1;literal_other_1_2\nliteral_other_2_1;literal_other_2_2\nliteral_other_3_1;literal_other_3_2');
+%! nm1 = textscan (txt, 'literal%s literal%s', 'Delimiter', ';');
+%! assert (nm1{1}, {"_other_1_1" ; "_other_2_1" ; "_other_3_1"});
+%! assert (nm1{2}, {"_other_1_2" ; "_other_2_2" ; "_other_3_2"});
+%! nm2 = textscan (txt, 'literal%s;literal%s', 'Delimiter', ';');
+%! assert (nm1, nm2);
+
+%!test <*57612>
+%! str = sprintf (['101,' '\n' '201,']);
+%! C = textscan (str, '%s%q', 'Delimiter', ',');
+%! assert (size (C), [1, 2]);
+%! assert (C{1}, { "101"; "201" });
+%! assert (C{2}, { ""; "" });
+
+%!test <*57612>
+%! str = sprintf (['101,' '\n' '201,']);
+%! C = textscan (str, '%s%f', 'Delimiter', ',');
+%! assert (size (C), [1, 2]);
+%! assert (C{1}, { "101"; "201" });
+%! assert (C{2}, [ NaN; NaN ]);
+
+%!test <*57612>
+%! str = sprintf (['101,' '\n' '201,']);
+%! C = textscan (str, '%s%d', 'Delimiter', ',');
+%! assert (size (C), [1, 2]);
+%! assert (C{1}, { "101"; "201" });
+%! assert (C{2}, int32 ([ 0; 0 ]));
+
+%!test <*51093>
+%! str = sprintf ('a\t\tb\tc');
+%! C = textscan (str, '%s', 'Delimiter', '\t', 'MultipleDelimsAsOne', false);
+%! assert (C{1}, {'a'; ''; 'b'; 'c'});
+
+%!test <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
@@ -2341,9 +2384,9 @@
       oct_data_conv::string_to_data_type (prec, block_size,
                                           input_type, output_type);
     }
-  catch (octave::execution_exception& e)
+  catch (octave::execution_exception& ee)
     {
-      error (e, "fread: invalid PRECISION specified");
+      error (ee, "fread: invalid PRECISION specified");
     }
 
   int skip = 0;
@@ -2352,9 +2395,9 @@
     {
       skip = skip_arg.int_value (true);
     }
-  catch (octave::execution_exception& e)
+  catch (octave::execution_exception& ee)
     {
-      error (e, "fread: SKIP must be an integer");
+      error (ee, "fread: SKIP must be an integer");
     }
 
   std::string arch = arch_arg.xstring_value ("fread: ARCH architecture type must be a string");
@@ -2577,9 +2620,9 @@
     {
       oct_data_conv::string_to_data_type (prec, block_size, output_type);
     }
-  catch (octave::execution_exception& e)
+  catch (octave::execution_exception& ee)
     {
-      error (e, "fwrite: invalid PRECISION specified");
+      error (ee, "fwrite: invalid PRECISION specified");
     }
 
   int skip = 0;
@@ -2588,9 +2631,9 @@
     {
       skip = skip_arg.int_value (true);
     }
-  catch (octave::execution_exception& e)
+  catch (octave::execution_exception& ee)
     {
-      error (e, "fwrite: SKIP must be an integer");
+      error (ee, "fwrite: SKIP must be an integer");
     }
 
   std::string arch = arch_arg.xstring_value ("fwrite: ARCH architecture type must be a string");
@@ -2824,7 +2867,7 @@
 Programming Note: Because the named file is not opened by @code{tempname},
 it is possible, though relatively unlikely, that it will not be available
 by the time your program attempts to open it.  If this is a concern,
-see @code{tmpfile}.
+@pxref{XREFtmpfile,,@code{tmpfile}}.
 @seealso{mkstemp, tempdir, P_tmpdir, tmpfile}
 @end deftypefn */)
 {
@@ -2890,7 +2933,7 @@
 %!   assert (tmpdir, tmp_tmpdir);
 %!   assert (tmpfname (1:4), "file");
 %! unwind_protect_cleanup
-%!   rmdir (tmp_tmpdir);
+%!   sts = rmdir (tmp_tmpdir);
 %!   for i = 1:numel (envvar)
 %!     if (isempty (envdir{i}))
 %!       unsetenv (envvar{i});
--- a/libinterp/corefcn/filter.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/filter.cc	Sun May 16 09:44:35 2021 +0200
@@ -605,7 +605,7 @@
 %!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]), [2 2])
 %!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]'), [2 2])
 %!assert (filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]), [5 7; 6 10; 14 18])
-%!error (filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]'))
+%!error filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]')
 %!assert (filter ([1, 3, 2], [1], [1 2; 3 4; 5 6], [1 0 0; 1 0 0], 2), [2 6; 3 13; 5 21])
 
 ## Test of DIM parameter
--- a/libinterp/corefcn/find.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/find.cc	Sun May 16 09:44:35 2021 +0200
@@ -58,7 +58,7 @@
     {
     default:
     case 3:
-      retval(2) = Array<T> (nda.index (idx_vector (idx)));
+      retval(2) = Array<T> (nda.index (octave::idx_vector (idx)));
       OCTAVE_FALLTHROUGH;
 
     case 2:
@@ -72,13 +72,13 @@
             idx.xelem (i) %= nr;
           }
         iext = -1;
-        retval(1) = idx_vector (jdx, -1);
+        retval(1) = octave::idx_vector (jdx, -1);
       }
       OCTAVE_FALLTHROUGH;
 
     case 1:
     case 0:
-      retval(0) = idx_vector (idx, iext);
+      retval(0) = octave::idx_vector (idx, iext);
       break;
     }
 
--- a/libinterp/corefcn/ft-text-renderer.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ft-text-renderer.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,6 +62,7 @@
 #include "file-ops.h"
 #include "oct-env.h"
 #include "pr-output.h"
+#include "sysdep.h"
 #include "text-renderer.h"
 
 namespace octave
@@ -387,7 +388,8 @@
         ::warning ("unable to find default font files");
       else
         {
-          if (FT_New_Face (library, file.c_str (), 0, &retval))
+          std::string ascii_file = sys::get_ASCII_filename (file);
+          if (FT_New_Face (library, ascii_file.c_str (), 0, &retval))
             ::warning ("ft_manager: unable to load font: %s", file.c_str ());
 #if defined (HAVE_FT_REFERENCE_FACE)
           else
@@ -448,14 +450,6 @@
       MODE_RENDER = 1
     };
 
-    enum
-    {
-      ROTATION_0   = 0,
-      ROTATION_90  = 1,
-      ROTATION_180 = 2,
-      ROTATION_270 = 3
-    };
-
   public:
 
     ft_text_renderer (void)
@@ -526,8 +520,6 @@
 
   private:
 
-    int rotation_to_mode (double rotation) const;
-
     // Class to hold information about fonts and a strong
     // reference to the font objects loaded by FreeType.
 
@@ -980,9 +972,10 @@
 
     m_strlist = std::list<text_renderer::string> ();
 
-    unwind_protect frame;
-    frame.protect_var (m_do_strlist);
-    frame.protect_var (m_strlist);
+    unwind_protect_var<bool> restore_var1 (m_do_strlist);
+    unwind_protect_var<std::list<text_renderer::string>>
+      restore_var2 (m_strlist);
+
     m_do_strlist = true;
 
     text_to_pixels (txt, pxls, box, ha, va, rot, interp, false);
@@ -1293,53 +1286,7 @@
       {
         elt->accept (*this);
 
-        switch (rotation)
-          {
-          case ROTATION_0:
-            break;
-
-          case ROTATION_90:
-            {
-              Array<octave_idx_type> perm (dim_vector (3, 1));
-              perm(0) = 0;
-              perm(1) = 2;
-              perm(2) = 1;
-              pixels = pixels.permute (perm);
-
-              Array<idx_vector> idx (dim_vector (3, 1));
-              idx(0) = idx_vector (':');
-              idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1);
-              idx(2) = idx_vector (':');
-              pixels = uint8NDArray (pixels.index (idx));
-            }
-            break;
-
-          case ROTATION_180:
-            {
-              Array<idx_vector> idx (dim_vector (3, 1));
-              idx(0) = idx_vector (':');
-              idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1);
-              idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1);
-              pixels = uint8NDArray (pixels.index (idx));
-            }
-            break;
-
-          case ROTATION_270:
-            {
-              Array<octave_idx_type> perm (dim_vector (3, 1));
-              perm(0) = 0;
-              perm(1) = 2;
-              perm(2) = 1;
-              pixels = pixels.permute (perm);
-
-              Array<idx_vector> idx (dim_vector (3, 1));
-              idx(0) = idx_vector (':');
-              idx(1) = idx_vector (':');
-              idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1);
-              pixels = uint8NDArray (pixels.index (idx));
-            }
-            break;
-          }
+        rotate_pixels (pixels, rotation);
       }
 
     return pixels;
@@ -1387,27 +1334,6 @@
     return extent;
   }
 
-  int
-  ft_text_renderer::rotation_to_mode (double rotation) const
-  {
-    // Clip rotation to range [0, 360]
-    while (rotation < 0)
-      rotation += 360.0;
-    while (rotation > 360.0)
-      rotation -= 360.0;
-
-    if (rotation == 0.0)
-      return ROTATION_0;
-    else if (rotation == 90.0)
-      return ROTATION_90;
-    else if (rotation == 180.0)
-      return ROTATION_180;
-    else if (rotation == 270.0)
-      return ROTATION_270;
-    else
-      return ROTATION_0;
-  }
-
   void
   ft_text_renderer::text_to_pixels (const std::string& txt,
                                     uint8NDArray& pxls, Matrix& box,
@@ -1426,65 +1352,9 @@
     if (pxls.isempty ())
       return;  // nothing to render
 
-    switch (halign)
-      {
-      case 1:
-        box(0) = -box(2)/2;
-        break;
-
-      case 2:
-        box(0) = -box(2);
-        break;
-
-      default:
-        box(0) = 0;
-        break;
-      }
-
-    switch (valign)
-      {
-      case 1:
-        box(1) = -box(3)/2;
-        break;
-
-      case 2:
-        box(1) = -box(3);
-        break;
-
-      case 3:
-        break;
-
-      case 4:
-        box(1) = -box(3)-box(1);
-        break;
-
-      default:
-        box(1) = 0;
-        break;
-      }
-
-    if (handle_rotation)
-      {
-        switch (rot_mode)
-          {
-          case ROTATION_90:
-            std::swap (box(0), box(1));
-            std::swap (box(2), box(3));
-            box(0) = -box(0)-box(2);
-            break;
-
-          case ROTATION_180:
-            box(0) = -box(0)-box(2);
-            box(1) = -box(1)-box(3);
-            break;
-
-          case ROTATION_270:
-            std::swap (box(0), box(1));
-            std::swap (box(2), box(3));
-            box(1) = -box(1)-box(3);
-            break;
-          }
-      }
+    // Move X0 and Y0 depending on alignments and eventually swap all values
+    // for text rotated 90° 180° or 270°
+    fix_bbox_anchor (box, halign, valign, rot_mode, handle_rotation);
   }
 
   ft_text_renderer::ft_font::ft_font (const ft_font& ft)
--- a/libinterp/corefcn/genprops.awk	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/genprops.awk	Sun May 16 09:44:35 2021 +0200
@@ -472,7 +472,6 @@
 
     for (i = 1; i <= idx; i++)
     {
-##    printf ("  insert_static_property (\"%s\", %s);\n", name[i], name[i]);
       if (ptype[i])
       {
         printf ("  %s.set_id (ID_%s);\n", name[i], toupper(name[i]));
--- a/libinterp/corefcn/gl-render.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/gl-render.cc	Sun May 16 09:44:35 2021 +0200
@@ -27,6 +27,8 @@
 #  include "config.h"
 #endif
 
+#include <limits>
+#include <memory>
 #include <sstream>
 
 #if defined (HAVE_WINDOWS_H)
@@ -36,7 +38,6 @@
 
 #include "lo-mappers.h"
 #include "oct-locbuf.h"
-#include "oct-refcount.h"
 
 #include "errwarn.h"
 #include "gl-render.h"
@@ -93,92 +94,84 @@
 #  define CALLBACK
 #endif
 
-  class
-  opengl_texture
+  class opengl_texture
   {
-  protected:
+  private:
+
     class texture_rep
     {
     public:
+
       texture_rep (opengl_functions& glfcns)
-        : m_glfcns (glfcns), id (), w (), h (), tw (), th (), tx (), ty (),
-          valid (false), count (1)
+        : m_glfcns (glfcns), m_id (), m_w (), m_h (), m_tw (), m_th (),
+          m_tx (), m_ty (), m_valid (false)
       { }
 
-      texture_rep (opengl_functions& glfcns, GLuint id_arg,
-                   int w_arg, int h_arg, int tw_arg, int th_arg)
-        : m_glfcns (glfcns), id (id_arg), w (w_arg), h (h_arg),
-          tw (tw_arg), th (th_arg), tx (double(w)/tw), ty (double(h)/th),
-          valid (true), count (1)
+      texture_rep (opengl_functions& glfcns, GLuint id, int w, int h,
+                   int tw, int th)
+        : m_glfcns (glfcns), m_id (id), m_w (w), m_h (h), m_tw (tw), m_th (th),
+          m_tx (double(m_w)/m_tw), m_ty (double(m_h)/m_th), m_valid (true)
       { }
 
       ~texture_rep (void)
       {
-        if (valid)
-          m_glfcns.glDeleteTextures (1, &id);
+        if (m_valid)
+          m_glfcns.glDeleteTextures (1, &m_id);
       }
 
       void bind (int mode) const
-      { if (valid) m_glfcns.glBindTexture (mode, id); }
+      {
+        if (m_valid)
+          m_glfcns.glBindTexture (mode, m_id);
+      }
 
       void tex_coord (double q, double r) const
-      { if (valid) m_glfcns.glTexCoord2d (q*tx, r*ty); }
+      {
+        if (m_valid)
+          m_glfcns.glTexCoord2d (q*m_tx, r*m_ty);
+      }
 
       opengl_functions& m_glfcns;
-      GLuint id;
-      int w, h;
-      int tw, th;
-      double tx, ty;
-      bool valid;
-      refcount<octave_idx_type> count;
+      GLuint m_id;
+      int m_w, m_h;
+      int m_tw, m_th;
+      double m_tx, m_ty;
+      bool m_valid;
     };
 
-    texture_rep *rep;
-
-  private:
-    opengl_texture (texture_rep *_rep) : rep (_rep) { }
-
   public:
+
     opengl_texture (opengl_functions& glfcns)
-      : rep (new texture_rep (glfcns)) { }
-
-    opengl_texture (const opengl_texture& tx)
-      : rep (tx.rep)
-    {
-      rep->count++;
-    }
-
-    ~opengl_texture (void)
-    {
-      if (--rep->count == 0)
-        delete rep;
-    }
-
-    opengl_texture& operator = (const opengl_texture& tx)
-    {
-      if (&tx != this)
-        {
-          if (--rep->count == 0)
-            delete rep;
-
-          rep = tx.rep;
-          rep->count++;
-        }
-
-      return *this;
-    }
+      : m_rep (new texture_rep (glfcns))
+    { }
+
+    opengl_texture (opengl_functions& glfcns, GLuint id, int w, int h,
+                    int tw, int th)
+      : m_rep (new texture_rep (glfcns, id, w, h, tw, th))
+    { }
+
+    opengl_texture (const opengl_texture&) = default;
+
+    ~opengl_texture (void) = default;
+
+    opengl_texture& operator = (const opengl_texture&) = default;
 
     static opengl_texture create (opengl_functions& glfcns,
                                   const octave_value& data);
 
-    void bind (int mode = GL_TEXTURE_2D) const
-    { rep->bind (mode); }
-
-    void tex_coord (double q, double r) const
-    { rep->tex_coord (q, r); }
-
-    bool is_valid (void) const
-    { return rep->valid; }
+    void bind (int mode = GL_TEXTURE_2D) const { m_rep->bind (mode); }
+
+    void tex_coord (double q, double r) const { m_rep->tex_coord (q, r); }
+
+    bool is_valid (void) const { return m_rep->m_valid; }
+
+  private:
+
+    opengl_texture (const std::shared_ptr<texture_rep>& new_rep)
+      : m_rep (new_rep)
+    { }
+
+    std::shared_ptr<texture_rep> m_rep;
   };
 
   opengl_texture
@@ -189,7 +182,7 @@
     dim_vector dv (data.dims ());
 
     // Expect RGB data
-    if (dv.ndims () == 3 && dv(2) == 3)
+    if (dv.ndims () == 3 && (dv(2) == 3 || dv(2) == 4))
       {
         // FIXME: dim_vectors hold octave_idx_type values.
         //        Should we check for dimensions larger than intmax?
@@ -281,7 +274,7 @@
             glfcns.glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
                                  GL_RGB, GL_UNSIGNED_SHORT, a);
           }
-        else if (data.is_uint8_type ())
+        else if (data.is_uint8_type () && dv(2) == 3)
           {
             const uint8NDArray xdata = data.uint8_array_value ();
 
@@ -300,6 +293,26 @@
             glfcns.glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
                                  GL_RGB, GL_UNSIGNED_BYTE, a);
           }
+        else if (data.is_uint8_type () && dv(2) == 4)
+          {
+            const uint8NDArray xdata = data.uint8_array_value ();
+
+            OCTAVE_LOCAL_BUFFER (GLubyte, a, (4*tw*th));
+
+            for (int i = 0; i < h; i++)
+              {
+                for (int j = 0, idx = i*tw*4; j < w; j++, idx += 4)
+                  {
+                    a[idx]   = xdata(i,j,0);
+                    a[idx+1] = xdata(i,j,1);
+                    a[idx+2] = xdata(i,j,2);
+                    a[idx+3] = xdata(i,j,3);
+                  }
+              }
+
+            glfcns.glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0,
+                                 GL_RGBA, GL_UNSIGNED_BYTE, a);
+          }
         else
           {
             ok = false;
@@ -314,7 +327,7 @@
             if (glfcns.glGetError () != GL_NO_ERROR)
               warning ("opengl_texture::create: OpenGL error while generating texture data");
             else
-              retval = opengl_texture (new texture_rep (glfcns, id, w, h, tw, th));
+              retval = opengl_texture (glfcns, id, w, h, tw, th);
           }
       }
     else
@@ -427,87 +440,69 @@
     bool fill;
   };
 
-  class
-  vertex_data
+  class vertex_data
   {
   public:
+
     class vertex_data_rep
     {
     public:
-      Matrix coords;
-      Matrix color;
-      Matrix vertex_normal;
-      Matrix face_normal;
-      double alpha;
-      float ambient;
-      float diffuse;
-      float specular;
-      float specular_exp;
-      float specular_color_refl;
-
-      // reference counter
-      refcount<octave_idx_type> count;
 
       vertex_data_rep (void)
-        : coords (), color (), vertex_normal (), face_normal (), alpha (),
-          ambient (), diffuse (), specular (), specular_exp (),
-          specular_color_refl (), count (1) { }
+        : m_coords (), m_color (), m_vertex_normal (), m_face_normal (),
+          m_alpha (), m_ambient (), m_diffuse (), m_specular (),
+          m_specular_exp (), m_specular_color_refl ()
+      { }
 
       vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& vn,
                        const Matrix& fn, double a, float as, float ds, float ss,
                        float se, float scr)
-        : coords (c), color (col), vertex_normal (vn), face_normal (fn),
-          alpha (a), ambient (as), diffuse (ds), specular (ss),
-          specular_exp (se), specular_color_refl (scr), count (1) { }
+        : m_coords (c), m_color (col), m_vertex_normal (vn),
+          m_face_normal (fn), m_alpha (a), m_ambient (as), m_diffuse (ds),
+          m_specular (ss), m_specular_exp (se), m_specular_color_refl (scr)
+      { }
+
+      Matrix m_coords;
+      Matrix m_color;
+      Matrix m_vertex_normal;
+      Matrix m_face_normal;
+      double m_alpha;
+      float m_ambient;
+      float m_diffuse;
+      float m_specular;
+      float m_specular_exp;
+      float m_specular_color_refl;
     };
 
-  private:
-    vertex_data_rep *rep;
-
-    vertex_data_rep * nil_rep (void) const
-    {
-      static vertex_data_rep *nr = new vertex_data_rep ();
-
-      return nr;
-    }
-
   public:
-    vertex_data (void) : rep (nil_rep ())
-    { rep->count++; }
-
-    vertex_data (const vertex_data& v) : rep (v.rep)
-    { rep->count++; }
+
+    // Required to instantiate std::list<vertex_data> objects.
+    vertex_data (void) : m_rep (nil_rep ()) { }
 
     vertex_data (const Matrix& c, const Matrix& col, const Matrix& vn,
                  const Matrix& fn, double a, float as, float ds, float ss,
                  float se, float scr)
-      : rep (new vertex_data_rep (c, col, vn, fn, a, as, ds, ss, se, scr))
+      : m_rep (new vertex_data_rep (c, col, vn, fn, a, as, ds, ss, se, scr))
     { }
 
-    vertex_data (vertex_data_rep *new_rep)
-      : rep (new_rep) { }
-
-    ~vertex_data (void)
-    {
-      if (--rep->count == 0)
-        delete rep;
-    }
-
-    vertex_data& operator = (const vertex_data& v)
+    vertex_data (const vertex_data&) = default;
+
+    ~vertex_data (void) = default;
+
+    vertex_data& operator = (const vertex_data&) = default;
+
+    vertex_data_rep * get_rep (void) const { return m_rep.get (); }
+
+  private:
+
+    static std::shared_ptr<vertex_data_rep> nil_rep (void)
     {
-      if (&v != this)
-        {
-          if (--rep->count == 0)
-            delete rep;
-
-          rep = v.rep;
-          rep->count++;
-        }
-
-      return *this;
+      static std::shared_ptr<vertex_data_rep> nr (new vertex_data_rep ());
+
+      return nr;
     }
 
-    vertex_data_rep * get_rep (void) const { return rep; }
+    std::shared_ptr<vertex_data_rep> m_rep;
   };
 
   class
@@ -555,18 +550,18 @@
 
       vertex_data::vertex_data_rep *v
         = reinterpret_cast<vertex_data::vertex_data_rep *> (data);
-      //printf ("patch_tessellator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2));
+      //printf ("patch_tessellator::vertex (%g, %g, %g)\n", v->m_coords(0), v->m_coords(1), v->m_coords(2));
 
       // NOTE: OpenGL can re-order vertices.  For "flat" coloring of FaceColor
       // the first vertex must be identified in the draw_patch routine.
 
       if (color_mode == INTERP || (color_mode == FLAT && ! is_filled ()))
         {
-          Matrix col = v->color;
+          Matrix col = v->m_color;
 
           if (col.numel () == 3)
             {
-              glfcns.glColor4d (col(0), col(1), col(2), v->alpha);
+              glfcns.glColor4d (col(0), col(1), col(2), v->m_alpha);
               if (light_mode > 0)
                 {
                   // edge lighting only uses ambient light
@@ -574,36 +569,35 @@
 
                   if (face_lighting)
                     for (int k = 0; k < 3; k++)
-                      buf[k] = v->specular * (v->specular_color_refl +
-                                              (1 - v->specular_color_refl) * col(k));
+                      buf[k] = (v->m_specular
+                                * (v->m_specular_color_refl +
+                                   (1 - v->m_specular_color_refl) * col(k)));
                   glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
 
                   if (face_lighting)
                     for (int k = 0; k < 3; k++)
-                      buf[k] = (v->diffuse * col(k));
+                      buf[k] = (v->m_diffuse * col(k));
                   glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, buf);
 
                   for (int k = 0; k < 3; k++)
-                    buf[k] = (v->ambient * col(k));
+                    buf[k] = (v->m_ambient * col(k));
                   glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
                 }
             }
         }
 
       if (light_mode == FLAT && first)
-        glfcns.glNormal3dv (v->face_normal.data ());
+        glfcns.glNormal3dv (v->m_face_normal.data ());
       else if (light_mode == GOURAUD)
-        glfcns.glNormal3dv (v->vertex_normal.data ());
-
-      glfcns.glVertex3dv (v->coords.data ());
+        glfcns.glNormal3dv (v->m_vertex_normal.data ());
+
+      glfcns.glVertex3dv (v->m_coords.data ());
 
       first = false;
     }
 
     void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], void **out_data)
     {
-      //printf ("patch_tessellator::combine\n");
-
       vertex_data::vertex_data_rep *v[4];
       int vmax = 4;
 
@@ -625,34 +619,34 @@
       vv(1) = xyz[1];
       vv(2) = xyz[2];
 
-      if (v[0]->color.numel ())
+      if (v[0]->m_color.numel ())
         {
           cc.resize (1, 3, 0.0);
           for (int ic = 0; ic < 3; ic++)
             for (int iv = 0; iv < vmax; iv++)
-              cc(ic) += (w[iv] * v[iv]->color (ic));
+              cc(ic) += (w[iv] * v[iv]->m_color (ic));
         }
 
-      if (v[0]->vertex_normal.numel () > 0)
+      if (v[0]->m_vertex_normal.numel () > 0)
         {
           for (int in = 0; in < 3; in++)
             for (int iv = 0; iv < vmax; iv++)
-              vnn(in) += (w[iv] * v[iv]->vertex_normal (in));
+              vnn(in) += (w[iv] * v[iv]->m_vertex_normal (in));
         }
 
-      if (v[0]->face_normal.numel () > 0)
+      if (v[0]->m_face_normal.numel () > 0)
         {
           for (int in = 0; in < 3; in++)
             for (int iv = 0; iv < vmax; iv++)
-              fnn(in) += (w[iv] * v[iv]->face_normal (in));
+              fnn(in) += (w[iv] * v[iv]->m_face_normal (in));
         }
 
       for (int iv = 0; iv < vmax; iv++)
-        aa += (w[iv] * v[iv]->alpha);
-
-      vertex_data new_v (vv, cc, vnn, fnn, aa, v[0]->ambient, v[0]->diffuse,
-                         v[0]->specular, v[0]->specular_exp,
-                         v[0]->specular_color_refl);
+        aa += (w[iv] * v[iv]->m_alpha);
+
+      vertex_data new_v (vv, cc, vnn, fnn, aa, v[0]->m_ambient, v[0]->m_diffuse,
+                         v[0]->m_specular, v[0]->m_specular_exp,
+                         v[0]->m_specular_color_refl);
       tmp_vdata.push_back (new_v);
 
       *out_data = new_v.get_rep ();
@@ -734,6 +728,8 @@
       draw_surface (dynamic_cast<const surface::properties&> (props));
     else if (go.isa ("patch"))
       draw_patch (dynamic_cast<const patch::properties&> (props));
+    else if (go.isa ("scatter"))
+      draw_scatter (dynamic_cast<const scatter::properties&> (props));
     else if (go.isa ("light"))
       draw_light (dynamic_cast<const light::properties&> (props));
     else if (go.isa ("hggroup"))
@@ -1277,8 +1273,21 @@
 
     Matrix x_zlim = props.get_transform_zlim ();
 
-    xZ1 = std::max (-1e6, x_zlim(0)-(x_zlim(1)-x_zlim(0))*100.0);
-    xZ2 = std::min (1e6, x_zlim(1)+(x_zlim(1)-x_zlim(0))*100.0);
+    // Expand the distance between the clipping planes symmetrically by
+    // an arbitrary factor (see bug #54551).
+    const double expansion_fac = 100.0;
+    // Also make sure that the distance between the clipping planes
+    // differs in single precision (see bug #58956).  This factor is also
+    // arbitrary.  Different values (>2) might also work.
+    const double single_prec_fac = 10.0;
+
+    double avgZ = x_zlim(0) / 2.0 + x_zlim(1) / 2.0;
+    double span
+      = std::max (expansion_fac * (x_zlim(1)-x_zlim(0)),
+                  single_prec_fac * std::abs (avgZ)
+                  * std::numeric_limits<float>::epsilon ());
+    xZ1 = avgZ - span;
+    xZ2 = avgZ + span;
 
     Matrix x_mat1 = props.get_opengl_matrix_1 ();
     Matrix x_mat2 = props.get_opengl_matrix_2 ();
@@ -3424,7 +3433,7 @@
                         vertex_data::vertex_data_rep *vv
                           = vdata[i+j*fr].get_rep ();
 
-                        tess.add_vertex (vv->coords.fortran_vec (), vv);
+                        tess.add_vertex (vv->m_coords.fortran_vec (), vv);
                       }
 
                     if (count_f(i) > 0)
@@ -3434,7 +3443,7 @@
                         if (fc_mode == FLAT)
                           {
                             // For "flat" shading, use color of 1st vertex.
-                            Matrix col = vv->color;
+                            Matrix col = vv->m_color;
 
                             if (col.numel () == 3)
                               {
@@ -3444,24 +3453,24 @@
                                     float cb[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
 
                                     for (int k = 0; k < 3; k++)
-                                      cb[k] = (vv->ambient * col(k));
+                                      cb[k] = (vv->m_ambient * col(k));
                                     m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
 
                                     for (int k = 0; k < 3; k++)
-                                      cb[k] = (vv->diffuse * col(k));
+                                      cb[k] = (vv->m_diffuse * col(k));
                                     m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
 
                                     for (int k = 0; k < 3; k++)
-                                      cb[k] = vv->specular *
-                                              (vv->specular_color_refl
-                                               + (1-vv->specular_color_refl) *
+                                      cb[k] = vv->m_specular *
+                                              (vv->m_specular_color_refl
+                                               + (1-vv->m_specular_color_refl) *
                                               col(k));
                                     m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
                                   }
                               }
                           }
 
-                        tess.add_vertex (vv->coords.fortran_vec (), vv);
+                        tess.add_vertex (vv->m_coords.fortran_vec (), vv);
                       }
 
                     tess.end_contour ();
@@ -3538,7 +3547,7 @@
                           {
                             vertex_data::vertex_data_rep *vv
                               = vdata[i+j*fr].get_rep ();
-                            const Matrix m = vv->coords;
+                            const Matrix m = vv->m_coords;
                             if (! flag)
                               {
                                 flag = true;
@@ -3546,7 +3555,7 @@
                               }
                             if (ec_mode != UNIFORM)
                               {
-                                Matrix col = vv->color;
+                                Matrix col = vv->m_color;
 
                                 if (col.numel () == 3)
                                   m_glfcns.glColor3dv (col.data ());
@@ -3566,10 +3575,10 @@
                       {
                         vertex_data::vertex_data_rep *vv
                           = vdata[i+j*fr].get_rep ();
-                        const Matrix m = vv->coords;
+                        const Matrix m = vv->m_coords;
                         if (ec_mode != UNIFORM)
                           {
-                            Matrix col = vv->color;
+                            Matrix col = vv->m_color;
 
                             if (col.numel () == 3)
                               m_glfcns.glColor3dv (col.data ());
@@ -3589,7 +3598,7 @@
                       {
                         vertex_data::vertex_data_rep *vv
                           = vdata[i+j*fr].get_rep ();
-                        tess.add_vertex (vv->coords.fortran_vec (), vv);
+                        tess.add_vertex (vv->m_coords.fortran_vec (), vv);
                       }
 
                     tess.end_contour ();
@@ -3695,6 +3704,116 @@
   }
 
   void
+  opengl_renderer::draw_scatter (const scatter::properties& props)
+  {
+#if defined (HAVE_OPENGL)
+
+    // Do not render if the scatter object has incoherent data
+    std::string msg;
+    if (props.has_bad_data (msg))
+      {
+        warning ("opengl_renderer: %s.  Not rendering.", msg.c_str ());
+        return;
+      }
+
+    bool draw_all = selecting;
+
+    if (draw_all || (! props.marker_is ("none")
+                     && ! (props.markeredgecolor_is ("none")
+                           && props.markerfacecolor_is ("none"))))
+      {
+        bool do_edge = draw_all || ! props.markeredgecolor_is ("none");
+        bool do_face = draw_all || ! props.markerfacecolor_is ("none");
+
+        const Matrix x = props.get_xdata ().matrix_value ();
+        const Matrix y = props.get_ydata ().matrix_value ();
+        const Matrix z = props.get_zdata ().matrix_value ();
+        const Matrix c = props.get_color_data ().matrix_value ();
+        const Matrix s = props.get_sizedata ().matrix_value ();
+
+        int np = x.rows ();
+        bool has_z = ! z.isempty ();
+
+        // If markeredgecolor is "flat", mecolor is empty
+        Matrix mecolor = (draw_all ? Matrix (1, 3, 0.0) :
+                          props.get_markeredgecolor_rgb ());
+        Matrix mfcolor = (draw_all ? Matrix (1, 3, 0.0) :
+                          props.get_markerfacecolor_rgb ());
+        const double mea = props.get_markeredgealpha ();
+        const double mfa = props.get_markerfacealpha ();
+
+        if (props.markerfacecolor_is ("auto"))
+          {
+            gh_manager& gh_mgr
+              = __get_gh_manager__ ("opengl_renderer::draw_scatter");
+            graphics_object go = gh_mgr.get_object (props.get___myhandle__ ());
+            graphics_object ax = go.get_ancestor ("axes");
+            const axes::properties& ax_props
+              = dynamic_cast<const axes::properties&> (ax.get_properties ());
+
+            mfcolor = ax_props.get_color ().matrix_value ();
+          }
+
+        init_marker (props.get_marker (), std::sqrt (s(0)),
+                     props.get_linewidth ());
+
+        uint8_t clip_mask = (props.is_clipping () ? 0x7F : 0x40);
+        uint8_t clip_ok = 0x40;
+
+        Matrix cc;
+        if (! c.isempty ())
+          {
+            if (c.rows () == 1)
+              cc = c;
+            else
+              {
+                cc.resize (1, 3);
+                cc(0) = c(0,0);
+                cc(1) = c(0,1);
+                cc(2) = c(0,2);
+              }
+          }
+
+        for (int i = 0; i < np; i++)
+          {
+            if ((clip_code (x(i), y(i), (has_z ? z(i) : 0.0)) & clip_mask)
+                 != clip_ok)
+              continue;
+
+            if (c.rows () > 1)
+              {
+                cc(0) = c(i,0);
+                cc(1) = c(i,1);
+                cc(2) = c(i,2);
+              }
+
+            Matrix lc = (do_edge ? (mecolor.isempty () ? cc : mecolor)
+                                 : Matrix ());
+            Matrix fc = (do_face ? (mfcolor.isempty () ? cc : mfcolor)
+                                 : Matrix ());
+
+            if (s.numel () > 1)
+              change_marker (props.get_marker (), std::sqrt (s(i)));
+
+            draw_marker (x(i), y(i), (has_z ? z(i) : 0.0), lc, fc, mea, mfa);
+          }
+
+        end_marker ();
+      }
+
+#else
+
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
   opengl_renderer::draw_light (const light::properties& props)
   {
 #if defined (HAVE_OPENGL)
@@ -3738,6 +3857,52 @@
   }
 
   void
+  opengl_renderer::set_ortho_coordinates (void)
+  {
+#if defined (HAVE_OPENGL)
+
+    m_glfcns.glMatrixMode (GL_PROJECTION);
+    m_glfcns.glPushMatrix ();
+    m_glfcns.glLoadIdentity ();
+
+    Matrix vp = get_viewport_scaled ();
+    m_glfcns.glOrtho (0, vp(2), vp(3), 0, xZ1, xZ2);
+    m_glfcns.glMatrixMode (GL_MODELVIEW);
+    m_glfcns.glPushMatrix ();
+    m_glfcns.glLoadIdentity ();
+
+#else
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
+  opengl_renderer::restore_previous_coordinates (void)
+  {
+#if defined (HAVE_OPENGL)
+
+    // Restore previous coordinate system
+    m_glfcns.glMatrixMode (GL_MODELVIEW);
+    m_glfcns.glPopMatrix();
+    m_glfcns.glMatrixMode (GL_PROJECTION);
+    m_glfcns.glPopMatrix();
+
+#else
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
   opengl_renderer::draw_text (const text::properties& props)
   {
 #if defined (HAVE_OPENGL)
@@ -3747,31 +3912,22 @@
 
     Matrix pos = xform.scale (props.get_data_position ());
 
-    // Handle clipping manually when drawing text background
+    // Handle clipping manually when drawing text in ortho coordinates
     if (! props.is_clipping ()
         || (clip_code (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0) == 0x40))
       {
         set_clipping (false);
+
         draw_text_background (props);
+
+        set_font (props);
+
+        render_text (props.get_pixels (), props.get_extent_matrix (),
+                     pos(0), pos(1), pos(2), props.get_rotation ());
+
         set_clipping (props.is_clipping ());
       }
 
-    set_font (props);
-
-    const Matrix bbox = props.get_extent_matrix ();
-
-    bool blend = m_glfcns.glIsEnabled (GL_BLEND);
-
-    m_glfcns.glEnable (GL_BLEND);
-    m_glfcns.glEnable (GL_ALPHA_TEST);
-    m_glfcns.glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0);
-    m_glfcns.glBitmap (0, 0, 0, 0, bbox(0), bbox(1), nullptr);
-    m_glfcns.glDrawPixels (bbox(2), bbox(3), GL_RGBA, GL_UNSIGNED_BYTE,
-                           props.get_pixels ().data ());
-    m_glfcns.glDisable (GL_ALPHA_TEST);
-    if (! blend)
-      m_glfcns.glDisable (GL_BLEND);
-
 #else
 
     octave_unused_parameter (props);
@@ -3786,7 +3942,7 @@
 
   void
   opengl_renderer::draw_text_background (const text::properties& props,
-                                         bool do_rotate)
+                                         bool /*do_rotate*/)
   {
 #if defined (HAVE_OPENGL)
 
@@ -3801,15 +3957,7 @@
                                                       pos(2), true);
 
     // Save current transform matrices and set orthogonal window coordinates
-    m_glfcns.glMatrixMode (GL_PROJECTION);
-    m_glfcns.glPushMatrix ();
-    m_glfcns.glLoadIdentity ();
-
-    Matrix vp = get_viewport_scaled ();
-    m_glfcns.glOrtho (0, vp(2), vp(3), 0, xZ1, xZ2);
-    m_glfcns.glMatrixMode (GL_MODELVIEW);
-    m_glfcns.glPushMatrix ();
-    m_glfcns.glLoadIdentity ();
+    set_ortho_coordinates ();
 
     // Translate coordinates so that the text anchor is (0,0)
     m_glfcns.glTranslated (pixpos(0), pixpos(1), -pixpos(2));
@@ -3818,9 +3966,7 @@
     //        Handle others here.
     double rotation = props.get_rotation ();
 
-    if (do_rotate && rotation != 0.0 && rotation != 90.0
-        && rotation != 180.0 && rotation != 270.0)
-      m_glfcns.glRotated (-rotation, 0.0, 0.0, 1.0);
+    m_glfcns.glRotated (-rotation, 0.0, 0.0, 1.0);
 
     double m = points_to_pixels (props.get_margin ());
     const Matrix bbox = props.get_extent_matrix ();
@@ -3866,15 +4012,11 @@
         set_linestyle ("-");
       }
 
-    // Restore previous coordinate system
-    m_glfcns.glPopMatrix();
-    m_glfcns.glMatrixMode (GL_PROJECTION);
-    m_glfcns.glPopMatrix();
+    restore_previous_coordinates ();
 
 #else
 
     octave_unused_parameter (props);
-    octave_unused_parameter (do_rotate);
 
     // This shouldn't happen because construction of opengl_renderer
     // objects is supposed to be impossible if OpenGL is not available.
@@ -3890,12 +4032,34 @@
 #if defined (HAVE_OPENGL)
 
     octave_value cdata = props.get_color_data ();
+    Matrix x = props.get_xdata ().matrix_value ();
+    Matrix y = props.get_ydata ().matrix_value ();
+
+    draw_texture_image (cdata, x, y);
+
+#else
+
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
+  opengl_renderer::draw_texture_image (const octave_value cdata, Matrix x,
+                                       Matrix y, bool ortho)
+  {
+#if defined (HAVE_OPENGL)
+
     dim_vector dv (cdata.dims ());
     int h = dv(0);
     int w = dv(1);
     double x0, x1, y0, y1;
 
-    Matrix x = props.get_xdata ().matrix_value ();
     double dx = 1.0;
     if (w > 1)
       dx = (x(1) - x(0)) / (w - 1);
@@ -3903,7 +4067,6 @@
     x0 = x(0)-dx/2;
     x1 = x(1)+dx/2;
 
-    Matrix y = props.get_ydata ().matrix_value ();
     double dy = 1.0;
     if (h > 1)
       dy = (y(1) - y(0)) / (h - 1);
@@ -3912,7 +4075,7 @@
     y1 = y(1)+dy/2;
 
     // Expect RGB data
-    if (dv.ndims () == 3 && dv(2) == 3)
+    if (dv.ndims () == 3 && (dv(2) == 3 || dv(2) == 4))
       {
         opengl_texture tex  = opengl_texture::create (m_glfcns, cdata);
         if (tex.is_valid ())
@@ -3924,16 +4087,28 @@
             m_glfcns.glBegin (GL_QUADS);
 
             tex.tex_coord (0.0, 0.0);
-            m_glfcns.glVertex3d (x0, y0, 0.0);
+            if (ortho)
+              m_glfcns.glVertex2d (x0, y0);
+            else
+              m_glfcns.glVertex3d (x0, y0, 0.0);
 
             tex.tex_coord (1.0, 0.0);
-            m_glfcns.glVertex3d (x1, y0, 0.0);
+            if (ortho)
+              m_glfcns.glVertex2d (x1, y0);
+            else
+              m_glfcns.glVertex3d (x1, y0, 0.0);
 
             tex.tex_coord (1.0, 1.0);
-            m_glfcns.glVertex3d (x1, y1, 0.0);
+            if (ortho)
+              m_glfcns.glVertex2d (x1, y1);
+            else
+              m_glfcns.glVertex3d (x1, y1, 0.0);
 
             tex.tex_coord (0.0, 1.0);
-            m_glfcns.glVertex3d (x0, y1, 0.0);
+            if (ortho)
+              m_glfcns.glVertex2d (x0, y1);
+            else
+              m_glfcns.glVertex3d (x0, y1, 0.0);
 
             m_glfcns.glEnd ();
             m_glfcns.glDisable (GL_TEXTURE_2D);
@@ -3944,7 +4119,10 @@
 
 #else
 
-    octave_unused_parameter (props);
+    octave_unused_parameter (cdata);
+    octave_unused_parameter (x);
+    octave_unused_parameter (y);
+    octave_unused_parameter (ortho);
 
     // This shouldn't happen because construction of opengl_renderer
     // objects is supposed to be impossible if OpenGL is not available.
@@ -4275,6 +4453,27 @@
   }
 
   void
+  opengl_renderer::change_marker (const std::string& m, double size)
+  {
+#if defined (HAVE_OPENGL)
+
+    marker_id = make_marker_list (m, size, false);
+    filled_marker_id = make_marker_list (m, size, true);
+
+#else
+
+    octave_unused_parameter (m);
+    octave_unused_parameter (size);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
   opengl_renderer::end_marker (void)
   {
 #if defined (HAVE_OPENGL)
@@ -4300,7 +4499,8 @@
 
   void
   opengl_renderer::draw_marker (double x, double y, double z,
-                                const Matrix& lc, const Matrix& fc)
+                                const Matrix& lc, const Matrix& fc,
+                                const double la, const double fa)
   {
 #if defined (HAVE_OPENGL)
 
@@ -4311,12 +4511,12 @@
 
     if (filled_marker_id > 0 && fc.numel () > 0)
       {
-        m_glfcns.glColor3dv (fc.data ());
+        m_glfcns.glColor4d (fc(0), fc(1), fc(2), fa);
         set_polygon_offset (true, -1.0);
         m_glfcns.glCallList (filled_marker_id);
         if (lc.numel () > 0)
           {
-            m_glfcns.glColor3dv (lc.data ());
+            m_glfcns.glColor4d (lc(0), lc(1), lc(2), la);
             m_glfcns.glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
             m_glfcns.glEdgeFlag (GL_TRUE);
             set_polygon_offset (true, -2.0);
@@ -4327,7 +4527,7 @@
       }
     else if (marker_id > 0 && lc.numel () > 0)
       {
-        m_glfcns.glColor3dv (lc.data ());
+        m_glfcns.glColor4d (lc(0), lc(1), lc(2), la);
         m_glfcns.glCallList (marker_id);
       }
 
@@ -4338,6 +4538,8 @@
     octave_unused_parameter (z);
     octave_unused_parameter (lc);
     octave_unused_parameter (fc);
+    octave_unused_parameter (la);
+    octave_unused_parameter (fa);
 
     // This shouldn't happen because construction of opengl_renderer
     // objects is supposed to be impossible if OpenGL is not available.
@@ -4670,18 +4872,7 @@
         uint8NDArray pixels;
         text_to_pixels (txt, pixels, bbox, halign, valign, rotation);
 
-        bool blend = m_glfcns.glIsEnabled (GL_BLEND);
-
-        m_glfcns.glEnable (GL_BLEND);
-        m_glfcns.glEnable (GL_ALPHA_TEST);
-        m_glfcns.glRasterPos3d (x, y, z);
-        m_glfcns.glBitmap(0, 0, 0, 0, bbox(0), bbox(1), nullptr);
-        m_glfcns.glDrawPixels (bbox(2), bbox(3),
-                               GL_RGBA, GL_UNSIGNED_BYTE, pixels.data ());
-        m_glfcns.glDisable (GL_ALPHA_TEST);
-
-        if (! blend)
-          m_glfcns.glDisable (GL_BLEND);
+        render_text (pixels, bbox, x, y, z, rotation);
       }
 
     return bbox;
@@ -4703,4 +4894,60 @@
 
 #endif
   }
+
+  void
+  opengl_renderer::render_text (uint8NDArray pixels, Matrix bbox,
+                                double x, double y, double z, double rotation)
+  {
+#if defined (HAVE_OPENGL)
+
+    // Transform data coordinates to screen pixel ortho coordinates
+    ColumnVector pixpos = get_transform ().transform (x, y, z, false);
+    Matrix xdata(1, 2, bbox(0) / m_devpixratio);
+    xdata(1) += (bbox(2) - 1) / m_devpixratio;
+    Matrix ydata(1, 2, -bbox(1) / m_devpixratio);
+    ydata(1) -= (bbox(3) - 1) / m_devpixratio;
+
+    bool blend = m_glfcns.glIsEnabled (GL_BLEND);
+    m_glfcns.glEnable (GL_BLEND);
+    m_glfcns.glEnable (GL_ALPHA_TEST);
+
+    set_ortho_coordinates ();
+
+    // Translate coordinates so that the text anchor is (0,0)
+    m_glfcns.glTranslated (pixpos(0), pixpos(1), -pixpos(2));
+
+    m_glfcns.glRotated (-rotation, 0.0, 0.0, 1.0);
+
+    // Permute pixels returned by freetype
+    Array<octave_idx_type> perm (dim_vector (3, 1));
+    perm(0) = 2;
+    perm(1) = 1;
+    perm(2) = 0;
+    draw_texture_image (pixels.permute (perm),
+                        xdata, ydata, true);
+
+    restore_previous_coordinates ();
+
+    m_glfcns.glDisable (GL_ALPHA_TEST);
+
+    if (! blend)
+      m_glfcns.glDisable (GL_BLEND);
+
+#else
+
+    octave_unused_parameter (pixels);
+    octave_unused_parameter (bbox);
+    octave_unused_parameter (x);
+    octave_unused_parameter (y);
+    octave_unused_parameter (z);
+    octave_unused_parameter (rotation);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
 }
--- a/libinterp/corefcn/gl-render.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/gl-render.h	Sun May 16 09:44:35 2021 +0200
@@ -81,6 +81,7 @@
     virtual void draw_line (const line::properties& props);
     virtual void draw_surface (const surface::properties& props);
     virtual void draw_patch (const patch::properties& props);
+    virtual void draw_scatter (const scatter::properties& props);
     virtual void draw_light (const light::properties& props);
     virtual void draw_hggroup (const hggroup::properties& props);
     virtual void draw_text (const text::properties& props);
@@ -115,9 +116,11 @@
     }
 
     virtual void init_marker (const std::string& m, double size, float width);
+    virtual void change_marker (const std::string& m, double size);
     virtual void end_marker (void);
     virtual void draw_marker (double x, double y, double z,
-                              const Matrix& lc, const Matrix& fc);
+                              const Matrix& lc, const Matrix& fc,
+                              const double la = 1.0, const double fa = 1.0);
 
     virtual void text_to_pixels (const std::string& txt,
                                  uint8NDArray& pixels,
@@ -181,8 +184,15 @@
               | (is_nan_or_inf (x, y, z) ? 0 : 1) << 6);
     }
 
+    void render_text (uint8NDArray pixels, Matrix bbox,
+                      double x, double y, double z, double rotation);
+
     void set_normal (int bfl_mode, const NDArray& n, int j, int i);
 
+    void set_ortho_coordinates (void);
+
+    void restore_previous_coordinates (void);
+
     double points_to_pixels (const double val) const;
 
     unsigned int make_marker_list (const std::string& m, double size,
@@ -201,6 +211,9 @@
     void draw_all_lights (const base_properties& props,
                           std::list<graphics_object>& obj_list);
 
+    void draw_texture_image (const octave_value cdata,
+                             Matrix x, Matrix y, bool ortho = false);
+
   protected:
 
     opengl_functions& m_glfcns;
--- a/libinterp/corefcn/gl2ps-print.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/gl2ps-print.cc	Sun May 16 09:44:35 2021 +0200
@@ -39,6 +39,7 @@
 
 #include <gl2ps.h>
 
+#include "file-ops.h"
 #include "lo-mappers.h"
 #include "oct-locbuf.h"
 #include "tmpfile-wrapper.h"
@@ -55,20 +56,6 @@
 
 namespace octave
 {
-  static void
-  safe_pclose (FILE *f)
-  {
-    if (f)
-      octave::pclose (f);
-  }
-
-  static void
-  safe_fclose (FILE *f)
-  {
-    if (f)
-      std::fclose (f);
-  }
-
   class
   OCTINTERP_API
   gl2ps_renderer : public opengl_renderer
@@ -77,8 +64,8 @@
 
     gl2ps_renderer (opengl_functions& glfcns, FILE *_fp,
                     const std::string& _term)
-      : opengl_renderer (glfcns), fp (_fp), term (_term),
-        fontsize (), fontname (), buffer_overflow (false)
+      : opengl_renderer (glfcns), fp (_fp), term (_term), fontsize (),
+        fontname (), buffer_overflow (false), m_svg_def_index (0)
     { }
 
     ~gl2ps_renderer (void) = default;
@@ -128,6 +115,13 @@
               && fa.double_value () < 1)
             retval = true;
         }
+      else if (go.isa ("scatter"))
+        {
+          octave_value fa = go.get ("markerfacealpha");
+          if (fa.is_scalar_type () && fa.is_double_type ()
+              && fa.double_value () < 1)
+            retval = true;
+        }
 
       return retval;
     }
@@ -272,7 +266,11 @@
                                Matrix box, double rotation,
                                std::list<text_renderer::string>& lst);
 
-    // Build an svg text element from a list of parsed strings.
+    // Build an svg text element from a list of parsed strings
+    std::string format_svg_element (std::string str, Matrix bbox,
+                                    double rotation, ColumnVector coord_pix,
+                                    Matrix color);
+
     std::string strlist_to_svg (double x, double y, double z, Matrix box,
                                 double rotation,
                                 std::list<text_renderer::string>& lst);
@@ -289,6 +287,7 @@
     double fontsize;
     std::string fontname;
     bool buffer_overflow;
+    std::size_t m_svg_def_index;
   };
 
   static bool
@@ -373,7 +372,7 @@
         if (! tmpf)
           error ("gl2ps_renderer::draw: couldn't open temporary file for printing");
 
-        frame.add_fcn (safe_fclose, tmpf);
+        frame.add ([=] () { std::fclose (tmpf); });
 
         // Reset buffsize, unless this is 2nd pass of a texstandalone print.
         if (term.find ("tex") == std::string::npos)
@@ -406,13 +405,17 @@
             else
               include_graph = old_print_cmd;
 
-            std::size_t n_begin = include_graph.find_first_not_of (" \"'");
+            std::size_t n_begin = include_graph.find_first_not_of (R"( "')");
 
             if (n_begin != std::string::npos)
               {
-                std::size_t n_end = include_graph.find_last_not_of (" \"'");
+                // Strip any quote characters characters around filename
+                std::size_t n_end = include_graph.find_last_not_of (R"( "')");
                 include_graph = include_graph.substr (n_begin,
                                                       n_end - n_begin + 1);
+                // Strip path from filename
+                n_begin = include_graph.find_last_of (sys::file_ops::dir_sep_chars ());
+                include_graph = include_graph.substr (n_begin + 1);
               }
             else
               include_graph = "foobar-inc";
@@ -489,8 +492,7 @@
                         error ("gl2ps_renderer::draw: internal pipe error");
                       }
                   }
-                else if (! header_found
-                         && term.find ("svg") != std::string::npos)
+                else if (term.find ("svg") != std::string::npos)
                   {
                     // FIXME: gl2ps uses pixel units for SVG format.
                     //        Modify resulting svg to use points instead.
@@ -498,7 +500,7 @@
                     //        make header_found true for SVG if gl2ps is fixed.
                     std::string srchstr (str);
                     std::size_t pos = srchstr.find ("px");
-                    if (pos != std::string::npos)
+                    if (! header_found && pos != std::string::npos)
                       {
                         header_found = true;
                         srchstr[pos+1] = 't';  // "px" -> "pt"
@@ -796,20 +798,134 @@
   }
 
   std::string
+  gl2ps_renderer::format_svg_element (std::string str, Matrix box,
+                                      double rotation, ColumnVector coord_pix,
+                                      Matrix color)
+  {
+    // Extract <defs> elements and change their id to avoid conflict with
+    // defs coming from another svg string
+    std::string::size_type n1 = str.find ("<defs>");
+    if (n1 == std::string::npos)
+      return std::string ();
+
+    std::string id, new_id;
+    n1 = str.find ("<path", ++n1);
+    std::string::size_type n2;
+
+    while (n1 != std::string::npos)
+      {
+        // Extract the identifier id='identifier'
+        n1 = str.find ("id='", n1) + 4;
+        n2 = str.find ("'", n1);
+        id = str.substr (n1, n2-n1);
+
+        new_id = std::to_string (m_svg_def_index) + "-" + id ;
+
+        str.replace (n1, n2-n1, new_id);
+
+        std::string::size_type n_ref = str.find ("#" + id);
+
+        while (n_ref != std::string::npos)
+          {
+            str.replace (n_ref + 1, id.length (), new_id);
+            n_ref = str.find ("#" + id);
+          }
+
+        n1 = str.find ("<path", n1);
+      }
+
+    m_svg_def_index++;
+
+    n1 = str.find ("<defs>");
+    n2 = str.find ("</defs>") + 7;
+
+    std::string defs = str.substr (n1, n2-n1);
+
+    // Extract the group containing the <use> elements and transform its
+    // coordinates using the bbox and coordinates info.
+
+    // Extract the original viewBox anchor
+    n1 = str.find ("viewBox='") + 9;
+    if (n1 == std::string::npos)
+      return std::string ();
+
+    n2 = str.find (" ", n1);
+    double original_x0 = std::stod (str.substr (n1, n2-n1));
+
+    n1 = n2+1;
+    n2 = str.find (" ", n1);
+    double original_y0 = std::stod (str.substr (n1, n2-n1));
+
+    // First look for local transform in the original svg
+    std::string orig_trans;
+    n1 = str.find ("<g id='page1' transform='");
+    if (n1 != std::string::npos)
+      {
+        n1 += 25;
+        n2 = str.find ("'", n1);
+        orig_trans = str.substr (n1, n2-n1);
+        n1 = n2 + 1;
+      }
+    else
+      {
+        n1 = str.find ("<g id='page1'");
+        n1 += 13;
+      }
+
+    n2 = str.find ("</g>", n1) + 4;
+
+    // The first applied transformation is the right-most
+    // 1* Apply original transform
+    std::string tform = orig_trans;
+
+    // 2* Move the anchor to the final position
+    tform = std::string ("translate")
+      + "(" + std::to_string (box(0) - original_x0 + coord_pix(0))
+      + "," + std::to_string (-(box(3) + box(1)) - original_y0 + coord_pix(1))
+      + ") " + tform;
+
+    // 3* Rotate around the final position
+    if (rotation != 0)
+      tform = std::string ("rotate")
+        + "(" + std::to_string (-rotation)
+        + "," + std::to_string (coord_pix(0))
+        + "," + std::to_string (coord_pix(1))
+        + ") " + tform;
+
+    // Fill color
+    std::string fill = "fill='rgb("
+      + std::to_string (static_cast<uint8_t> (color(0) * 255.0)) + ","
+      + std::to_string (static_cast<uint8_t> (color(1) * 255.0)) + ","
+      + std::to_string (static_cast<uint8_t> (color(2) * 255.0)) + ")' ";
+
+    std::string use_group = "<g "
+      + fill
+      + "transform='" + tform + "'"
+      + str.substr (n1, n2-n1);
+
+    return defs + "\n" + use_group;
+  }
+
+  std::string
   gl2ps_renderer::strlist_to_svg (double x, double y, double z,
                                   Matrix box, double rotation,
                                   std::list<text_renderer::string>& lst)
   {
+    //Use pixel coordinates to conform to gl2ps
+    ColumnVector coord_pix = get_transform ().transform (x, y, z, false);
+
     if (lst.empty ())
       return "";
 
-    //Use pixel coordinates to conform to gl2ps
-    ColumnVector coord_pix = get_transform ().transform (x, y, z, false);
+    // This may already be an svg image.
+    std::string svg = lst.front ().get_svg_element ();
+    if (! svg.empty ())
+      return format_svg_element (svg, box, rotation, coord_pix,
+                                 lst.front ().get_color ());
 
+    // Rotation and translation are applied to the whole group
     std::ostringstream os;
-    os << "<text xml:space=\"preserve\" ";
-
-    // Rotation and translation are applied to the whole text element
+    os << R"(<g xml:space="preserve" )";
     os << "transform=\""
        << "translate(" << coord_pix(0) + box(0) << "," << coord_pix(1) - box(1)
        << ") rotate(" << -rotation << "," << -box(0) << "," << box(1)
@@ -828,13 +944,13 @@
        << "font-size=\"" << size << "\">";
 
 
-    // build a tspan for each element in the strlist
+    // Build a text element for each element in the strlist
     for (p = lst.begin (); p != lst.end (); p++)
       {
-        os << "<tspan ";
+        os << "<text ";
 
         if (name.compare (p->get_family ()))
-          os << "font-family=\""  << p->get_family () << "\" ";
+          os << "font-family=\"" << p->get_family () << "\" ";
 
         if (weight.compare (p->get_weight ()))
           os << "font-weight=\"" << p->get_weight () << "\" ";
@@ -853,12 +969,12 @@
 
         // provide an x coordinate for each character in the string
         os << "x=\"";
-        std::vector<double> xdata =  p->get_xdata ();
+        std::vector<double> xdata = p->get_xdata ();
         for (auto q = xdata.begin (); q != xdata.end (); q++)
           os << (*q) << " ";
-        os << "\"";
+        os << '"';
 
-        os << ">";
+        os << '>';
 
         // translate unicode and special xml characters
         if (p->get_code ())
@@ -884,9 +1000,9 @@
                   os << chr.str ();
               }
           }
-        os << "</tspan>";
+        os << "</text>";
       }
-    os << "</text>";
+    os << "</g>";
 
     return os.str ();
   }
@@ -896,6 +1012,26 @@
                                  Matrix box, double rotation,
                                  std::list<text_renderer::string>& lst)
   {
+    if (lst.empty ())
+      return "";
+    else if (lst.size () == 1)
+      {
+        static bool warned = false;
+        // This may be an svg image, not handled in native eps format.
+        if (! lst.front ().get_svg_element ().empty ())
+          {
+            if (! warned)
+              {
+                warned = true;
+                warning_with_id ("Octave:print:unhandled-svg-content",
+                                 "print: unhandled LaTeX strings. "
+                                 "Use -svgconvert option or -d*latex* output "
+                                 "device.");
+              }
+            return "";
+          }
+      }
+
     // Translate and rotate coordinates in order to use bottom-left alignment
     fix_strlist_position (x, y, z, box, rotation, lst);
     Matrix prev_color (1, 3, -1);
@@ -1433,7 +1569,8 @@
         if (! fp)
           error (R"(print: failed to open pipe "%s")", stream.c_str ());
 
-        frame.add_fcn (safe_pclose, fp);
+        // Need octave:: qualifier here to avoid ambiguity.
+        frame.add ([=] () { octave::pclose (fp); });
       }
     else
       {
@@ -1444,7 +1581,7 @@
         if (! fp)
           error (R"(gl2ps_print: failed to create file "%s")", stream.c_str ());
 
-        frame.add_fcn (safe_fclose, fp);
+        frame.add ([=] () { std::fclose (fp); });
       }
 
     gl2ps_renderer rend (glfcns, fp, term);
--- a/libinterp/corefcn/graphics-toolkit.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/graphics-toolkit.cc	Sun May 16 09:44:35 2021 +0200
@@ -36,8 +36,7 @@
   void
   base_graphics_toolkit::update (const graphics_handle& h, int id)
   {
-    gh_manager& gh_mgr
-      = octave::__get_gh_manager__ ("base_graphics_toolkit::update");
+    gh_manager& gh_mgr = __get_gh_manager__ ("base_graphics_toolkit::update");
 
     graphics_object go = gh_mgr.get_object (h);
 
@@ -48,7 +47,7 @@
   base_graphics_toolkit::initialize (const graphics_handle& h)
   {
     gh_manager& gh_mgr
-      = octave::__get_gh_manager__ ("base_graphics_toolkit::initialize");
+      = __get_gh_manager__ ("base_graphics_toolkit::initialize");
 
     graphics_object go = gh_mgr.get_object (h);
 
@@ -59,7 +58,7 @@
   base_graphics_toolkit::finalize (const graphics_handle& h)
   {
     gh_manager& gh_mgr
-      = octave::__get_gh_manager__ ("base_graphics_toolkit::finalize");
+      = __get_gh_manager__ ("base_graphics_toolkit::finalize");
 
     graphics_object go = gh_mgr.get_object (h);
 
--- a/libinterp/corefcn/graphics.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/graphics.cc	Sun May 16 09:44:35 2021 +0200
@@ -1157,8 +1157,9 @@
                 {
                   pfx = name.substr (0, 7);
 
-                  if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
+                  if (pfx.compare ("surface") || pfx.compare ("scatter")
+                      || pfx.compare ("hggroup") || pfx.compare ("uipanel")
+                      || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len >= 9)
                     {
@@ -1226,6 +1227,8 @@
     go = new light (h, p);
   else if (type.compare ("patch"))
     go = new patch (h, p);
+  else if (type.compare ("scatter"))
+    go = new scatter (h, p);
   else if (type.compare ("surface"))
     go = new surface (h, p);
   else if (type.compare ("hggroup"))
@@ -1378,6 +1381,7 @@
 
   std::transform (str.begin (), str.end (), str.begin (), tolower);
 
+  // "blue" must precede black for Matlab compatibility
   if (str.compare (0, len, "blue", 0, len) == 0)
     tmp_rgb[2] = 1;
   else if (str.compare (0, len, "black", 0, len) == 0
@@ -1396,6 +1400,38 @@
   else if (str.compare (0, len, "white", 0, len) == 0
            || str.compare (0, len, "w", 0, len) == 0)
     tmp_rgb[0] = tmp_rgb[1] = tmp_rgb[2] = 1;
+  else if (str[0] == '#' && len == 7)
+    {
+      try
+        {
+          tmp_rgb[0] = static_cast<double> (stoi (str.substr (1,2), nullptr, 16))
+                       / 255.0;
+          tmp_rgb[1] = static_cast<double> (stoi (str.substr (3,2), nullptr, 16))
+                       / 255.0;
+          tmp_rgb[2] = static_cast<double> (stoi (str.substr (5,2), nullptr, 16))
+                       / 255.0;
+        }
+      catch (const octave::execution_exception&)
+        {
+          retval = false;
+        }
+    }
+  else if (str[0] == '#' && len == 4)
+    {
+      try
+        {
+          tmp_rgb[0] = static_cast<double> (stoi (str.substr (1,1), nullptr, 16))
+                       / 15.0;
+          tmp_rgb[1] = static_cast<double> (stoi (str.substr (2,1), nullptr, 16))
+                       / 15.0;
+          tmp_rgb[2] = static_cast<double> (stoi (str.substr (3,1), nullptr, 16))
+                       / 15.0;
+        }
+      catch (const octave::execution_exception&)
+        {
+          retval = false;
+        }
+    }
   else
     retval = false;
 
@@ -1448,9 +1484,9 @@
                   return true;
                 }
             }
-          catch (octave::execution_exception& e)
-            {
-              error (e, R"(invalid value for color property "%s" (value = %s))",
+          catch (octave::execution_exception& ee)
+            {
+              error (ee, R"(invalid value for color property "%s" (value = %s))",
                      get_name ().c_str (), s.c_str ());
             }
         }
@@ -1784,18 +1820,18 @@
 }
 
 /*
-## Test validation of uicontextmenu property
+## Test validation of contextmenu property
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   hax = axes ("parent", hf);
 %!   hpa = patch ("parent", hax);
 %!   try
-%!     set (hax, "uicontextmenu", hpa);
+%!     set (hax, "contextmenu", hpa);
 %!   catch
 %!     err = lasterr ();
 %!   end_try_catch
-%!   assert (err, 'set: invalid graphics object type for property "uicontextmenu"');
+%!   assert (err, 'set: invalid graphics object type for property "contextmenu"');
 %! unwind_protect_cleanup
 %!   delete (hf);
 %! end_unwind_protect
@@ -1940,12 +1976,11 @@
 void
 callback_property::execute (const octave_value& data) const
 {
-  octave::unwind_protect frame;
-
   // We are executing a callback function, so allow handles that have
   // their handlevisibility property set to "callback" to be visible.
 
-  frame.add_method (executing_callbacks, &callback_props::erase, this);
+  octave::unwind_action executing_callbacks_cleanup
+    ([=] () { executing_callbacks.erase (this); });
 
   if (! executing_callbacks.contains (this))
     {
@@ -2297,8 +2332,9 @@
                 {
                   pfx = name.substr (0, 7);
 
-                  if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
+                  if (pfx.compare ("surface") || pfx.compare ("scatter")
+                      || pfx.compare ("hggroup")|| pfx.compare ("uipanel")
+                      || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len > 9)
                     {
@@ -2357,6 +2393,8 @@
             has_property = image::properties::has_core_property (pname);
           else if (pfx == "patch")
             has_property = patch::properties::has_core_property (pname);
+          else if (pfx == "scatter")
+            has_property = scatter::properties::has_core_property (pname);
           else if (pfx == "surface")
             has_property = surface::properties::has_core_property (pname);
           else if (pfx == "hggroup")
@@ -2439,8 +2477,9 @@
                 {
                   pfx = name.substr (0, 7);
 
-                  if (pfx.compare ("surface") || pfx.compare ("hggroup")
-                      || pfx.compare ("uipanel") || pfx.compare ("uitable"))
+                  if (pfx.compare ("surface") || pfx.compare ("scatter")
+                      || pfx.compare ("hggroup") || pfx.compare ("uipanel")
+                      || pfx.compare ("uitable"))
                     offset = 7;
                   else if (len > 9)
                     {
@@ -2729,7 +2768,7 @@
 graphics_object::set_value_or_default (const caseless_str& pname,
                                        const octave_value& val)
 {
-  if (val.is_string ())
+  if (val.is_string () && val.rows () == 1)
     {
       std::string sval = val.string_value ();
 
@@ -3055,9 +3094,7 @@
 delete_graphics_objects (const NDArray vals, bool from_root = false)
 {
   // Prevent redraw of partially deleted objects.
-  octave::unwind_protect frame;
-  frame.protect_var (delete_executing);
-  delete_executing = true;
+  octave::unwind_protect_var<bool> restore_var (delete_executing, true);
 
   for (octave_idx_type i = 0; i < vals.numel (); i++)
     delete_graphics_object (vals.elem (i), from_root);
@@ -3122,7 +3159,7 @@
   hlist = figure_handle_list (true);
 
   if (hlist.numel () != 0)
-    warning ("gh_manager::close_all_figures: some graphics elements failed to close.");
+    warning ("gh_manager::close_all_figures: some graphics elements failed to close");
 
   // Clear all callback objects from our list.
 
@@ -3285,9 +3322,9 @@
             {
               bgo.set (pname, prop_val.second);
             }
-          catch (octave::execution_exception& e)
-            {
-              error (e, "error setting default property %s", pname.c_str ());
+          catch (octave::execution_exception& ee)
+            {
+              error (ee, "error setting default property %s", pname.c_str ());
             }
         }
     }
@@ -3296,7 +3333,7 @@
 /*
 ## test defaults are set in the order they were stored
 %!test
-%! set(0, "defaultfigureunits", "normalized");
+%! set (0, "defaultfigureunits", "normalized");
 %! set(0, "defaultfigureposition", [0.7 0 0.3 0.3]);
 %! hf = figure ("visible", "off");
 %! tol = 20 * eps;
@@ -3304,8 +3341,8 @@
 %!   assert (get (hf, "position"), [0.7 0 0.3 0.3], tol);
 %! unwind_protect_cleanup
 %!   close (hf);
-%!   set(0, "defaultfigureunits", "remove");
-%!   set(0, "defaultfigureposition", "remove");
+%!   set (0, "defaultfigureunits", "remove");
+%!   set (0, "defaultfigureposition", "remove");
 %! end_unwind_protect
 */
 
@@ -3483,15 +3520,15 @@
 }
 
 void
-base_properties::update_uicontextmenu (void) const
-{
-  if (uicontextmenu.get ().isempty ())
+base_properties::update_contextmenu (void) const
+{
+  if (contextmenu.get ().isempty ())
     return;
 
   gh_manager& gh_mgr
-    = octave::__get_gh_manager__ ("base_properties::update_uicontextmenu");
-
-  graphics_object go = gh_mgr.get_object (uicontextmenu.get ());
+    = octave::__get_gh_manager__ ("base_properties::update_contextmenu");
+
+  graphics_object go = gh_mgr.get_object (contextmenu.get ());
 
   if (go && go.isa ("uicontextmenu"))
     {
@@ -3605,7 +3642,7 @@
 %! hf = figure ("handlevisibility", "off", "visible", "off");
 %! hax = axes ("parent", hf, "handlevisibility", "off");
 %! unwind_protect
-%!   fcn = @(h) setappdata (h, "testdata", gcbo ());
+%!   fcn = @(h, ~) setappdata (h, "testdata", gcbo ());
 %!   addlistener (hf, "color", fcn);
 %!   addlistener (hax, "color", fcn);
 %!   set (hf, "color", "b");
@@ -4185,7 +4222,7 @@
 figure::properties::set___graphics_toolkit__ (const octave_value& val)
 {
   if (! val.is_string ())
-    error ("set___graphics_toolkit__ must be a string");
+    error ("set___graphics_toolkit__: toolkit must be a string");
 
   std::string nm = val.string_value ();
 
@@ -5267,7 +5304,7 @@
 axes::properties::sync_positions (void)
 {
   // First part is equivalent to 'update_tightinset ()'
-  if (activepositionproperty.is ("position"))
+  if (positionconstraint.is ("innerposition"))
     update_position ();
   else
     update_outerposition ();
@@ -5284,7 +5321,7 @@
   tightinset = tinset;
   set_units (old_units);
   update_transform ();
-  if (activepositionproperty.is ("position"))
+  if (positionconstraint.is ("innerposition"))
     update_position ();
   else
     update_outerposition ();
@@ -5295,13 +5332,13 @@
 %! hf = figure ("visible", "off");
 %! graphics_toolkit (hf, "qt");
 %! unwind_protect
-%!   subplot(2,1,1); plot(rand(10,1)); subplot(2,1,2); plot(rand(10,1));
+%!   subplot (2,1,1); plot (rand (10,1)); subplot (2,1,2); plot (rand (10,1));
 %!   hax = findall (gcf (), "type", "axes");
 %!   positions = cell2mat (get (hax, "position"));
 %!   outerpositions = cell2mat (get (hax, "outerposition"));
 %!   looseinsets = cell2mat (get (hax, "looseinset"));
 %!   tightinsets = cell2mat (get (hax, "tightinset"));
-%!   subplot(2,1,1); plot(rand(10,1)); subplot(2,1,2); plot(rand(10,1));
+%!   subplot (2,1,1); plot (rand (10,1)); subplot (2,1,2); plot (rand (10,1));
 %!   hax = findall (gcf (), "type", "axes");
 %!   assert (cell2mat (get (hax, "position")), positions, 1e-4);
 %!   assert (cell2mat (get (hax, "outerposition")), outerpositions, 1e-4);
@@ -5335,7 +5372,7 @@
 %! hf = figure ("visible", "off");
 %! graphics_toolkit (hf, "qt");
 %! fpos = get (hf, "position");
-%! set (gca, "activepositionproperty", "position");
+%! set (gca, "positionconstraint", "innerposition");
 %! unwind_protect
 %!   plot (rand (3));
 %!   position = get (gca, "position");
@@ -6269,9 +6306,7 @@
   zPlaneN = (zPlane == z_min ? z_max : z_min);
   fz = (z_max - z_min) / sqrt (dir(0)*dir(0) + dir(1)*dir(1));
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_axes_layout);
-  updating_axes_layout = true;
+  octave::unwind_protect_var<bool> restore_var (updating_axes_layout, true);
 
   xySym = (xd*yd*(xPlane-xPlaneN)*(yPlane-yPlaneN) > 0);
   zSign = (zd*(zPlane-zPlaneN) <= 0);
@@ -6431,9 +6466,8 @@
 
   bool isempty = xlabel_props.get_string ().isempty ();
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_xlabel_position);
-  updating_xlabel_position = true;
+  octave::unwind_protect_var<bool>
+    restore_var (updating_xlabel_position, true);
 
   if (! isempty)
     {
@@ -6536,9 +6570,8 @@
 
   bool isempty = ylabel_props.get_string ().isempty ();
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_ylabel_position);
-  updating_ylabel_position = true;
+  octave::unwind_protect_var<bool>
+    restore_var (updating_ylabel_position, true);
 
   if (! isempty)
     {
@@ -6642,9 +6675,8 @@
   bool camAuto = cameraupvectormode_is ("auto");
   bool isempty = zlabel_props.get_string ().isempty ();
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_zlabel_position);
-  updating_zlabel_position = true;
+  octave::unwind_protect_var<bool>
+    restore_updating_zlabel_position (updating_zlabel_position, true);
 
   if (! isempty)
     {
@@ -6767,9 +6799,7 @@
   text::properties& title_props
     = reinterpret_cast<text::properties&> (go.get_properties ());
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_title_position);
-  updating_title_position = true;
+  octave::unwind_protect_var<bool> restore_var (updating_title_position, true);
 
   if (title_props.positionmode_is ("auto"))
     {
@@ -6920,8 +6950,8 @@
 
       if (modified_limits)
         {
-          octave::unwind_protect frame;
-          frame.protect_var (updating_aspectratios);
+          octave::unwind_protect_var<std::set<double>>
+            restore_var (updating_aspectratios);
 
           updating_aspectratios.insert (get___myhandle__ ().value ());
 
@@ -7098,7 +7128,7 @@
             }
           else
             {
-              Matrix text_ext = text_props.get_extent_matrix ();
+              Matrix text_ext = text_props.get_extent_matrix (true);
 
               // The text extent is returned in device pixels.  Unscale and
               // work with logical pixels
@@ -7503,7 +7533,7 @@
 void
 axes::properties::update_outerposition (void)
 {
-  set_activepositionproperty ("outerposition");
+  set_positionconstraint ("outerposition");
   caseless_str old_units = get_units ();
   set_units ("normalized");
 
@@ -7562,7 +7592,7 @@
 void
 axes::properties::update_position (void)
 {
-  set_activepositionproperty ("position");
+  set_positionconstraint ("innerposition");
   caseless_str old_units = get_units ();
   set_units ("normalized");
 
@@ -7621,7 +7651,7 @@
   double right_margin = std::max (linset(2), tinset(2));
   double top_margin = std::max (linset(3), tinset(3));
 
-  if (activepositionproperty.is ("position"))
+  if (positionconstraint.is ("innerposition"))
     {
       Matrix innerbox = position.get ().matrix_value ();
 
@@ -8595,8 +8625,8 @@
 
 #undef FIX_LIMITS
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_axis_limits);
+  octave::unwind_protect_var<std::set<double>>
+    restore_var (updating_axis_limits);
 
   updating_axis_limits.insert (get_handle ().value ());
   bool is_auto;
@@ -8686,6 +8716,8 @@
           xproperties.check_axis_limits (limits, kids,
                                          xproperties.xscale_is ("log"),
                                          update_type);
+          if (axis_type == "xscale")
+            update_type = 'x';
         }
     }
   else if (axis_type == "ydata" || axis_type == "yscale"
@@ -8707,6 +8739,8 @@
           xproperties.check_axis_limits (limits, kids,
                                          xproperties.yscale_is ("log"),
                                          update_type);
+          if (axis_type == "yscale")
+            update_type = 'y';
         }
     }
   else if (axis_type == "zdata" || axis_type == "zscale"
@@ -8721,6 +8755,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,
@@ -8739,6 +8778,8 @@
           xproperties.check_axis_limits (limits, kids,
                                          xproperties.zscale_is ("log"),
                                          update_type);
+          if (axis_type == "zscale")
+            update_type = 'z';
         }
     }
   else if (axis_type == "cdata" || axis_type == "climmode"
@@ -8795,8 +8836,8 @@
 
     }
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_axis_limits);
+  octave::unwind_protect_var<std::set<double>>
+    restore_var (updating_axis_limits);
 
   updating_axis_limits.insert (get_handle ().value ());
   bool is_auto;
@@ -9363,10 +9404,47 @@
 }
 
 Matrix
-text::properties::get_extent_matrix (void) const
+text::properties::get_extent_matrix (bool rotated) const
 {
   // FIXME: Should this function also add the (x,y) base position?
-  return extent.get ().matrix_value ();
+  Matrix ext = extent.get ().matrix_value ();
+
+  if (rotated && get_rotation () != 0)
+    {
+      double rot = get_rotation () * 4.0 * atan (1.0) / 180;
+      double x0 = ext(0) * cos (rot) - ext(1) * sin (rot);
+      double x1 = x0;
+      double y0 = ext(0) * sin (rot) + ext(1) * cos (rot);
+      double y1 = y0;
+
+      double tmp = (ext(0)+ext(2)) * cos (rot) - ext(1) * sin (rot);
+      x0 = std::min (x0, tmp);
+      x1 = std::max (x1, tmp);
+      tmp = (ext(0)+ext(2)) * sin (rot) + ext(1) * cos (rot);
+      y0 = std::min (y0, tmp);
+      y1 = std::max (y1, tmp);
+
+      tmp = (ext(0)+ext(2)) * cos (rot) - (ext(1)+ext(3)) * sin (rot);
+      x0 = std::min (x0, tmp);
+      x1 = std::max (x1, tmp);
+      tmp = (ext(0)+ext(2)) * sin (rot) + (ext(1)+ext(3)) * cos (rot);
+      y0 = std::min (y0, tmp);
+      y1 = std::max (y1, tmp);
+
+      tmp = ext(0) * cos (rot) - (ext(1)+ext(3)) * sin (rot);
+      x0 = std::min (x0, tmp);
+      x1 = std::max (x1, tmp);
+      tmp = ext(0) * sin (rot) + (ext(1)+ext(3)) * cos (rot);
+      y0 = std::min (y0, tmp);
+      y1 = std::max (y1, tmp);
+
+      ext(0) = x0;
+      ext(1) = y0;
+      ext(2) = x1 - x0;
+      ext(3) = y1 - y0;
+    }
+
+  return ext;
 }
 
 octave_value
@@ -9374,7 +9452,7 @@
 {
   // FIXME: This doesn't work right for 3D plots.
   // (It doesn't in Matlab either, at least not in version 6.5.)
-  Matrix m = extent.get ().matrix_value ();
+  Matrix m = get_extent_matrix (true);
   Matrix pos = get_position ().matrix_value ();
   Matrix p = convert_text_position (pos, *this, get_units (), "pixels");
 
@@ -9484,7 +9562,7 @@
   octave::autolock guard (gh_mgr.graphics_lock ());
 
   txt_renderer.text_to_pixels (sv.join ("\n"), pixels, bbox,
-                               halign, valign, get_rotation (),
+                               halign, valign, 0.0,
                                get_interpreter ());
   // The bbox is relative to the text's position.  We'll leave it that
   // way, because get_position does not return valid results when the
@@ -9700,9 +9778,7 @@
 
   // FIXME: shouldn't we update facevertexalphadata here ?
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_patch_data);
-  updating_patch_data = true;
+  octave::unwind_protect_var<bool> restore_var (updating_patch_data, true);
 
   faces.set (idx);
   vertices.set (vert);
@@ -9942,9 +10018,7 @@
   // Update normals
   update_normals (true);
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_patch_data);
-  updating_patch_data = true;
+  octave::unwind_protect_var<bool> restore_var (updating_patch_data, true);
 
   set_xdata (xd);
   set_ydata (yd);
@@ -10206,6 +10280,120 @@
 // ---------------------------------------------------------------------
 
 octave_value
+scatter::properties::get_color_data (void) const
+{
+  octave_value c = get_cdata ();
+  if (c.is_undefined () || c.isempty ())
+    return Matrix ();
+  else
+    return convert_cdata (*this, c, c.columns () == 1, 2);
+}
+
+void
+scatter::properties::update_data (void)
+{
+  Matrix xd = get_xdata ().matrix_value ();
+  Matrix yd = get_ydata ().matrix_value ();
+  Matrix zd = get_zdata ().matrix_value ();
+  Matrix cd = get_cdata ().matrix_value ();
+  Matrix sd = get_sizedata ().matrix_value ();
+
+  bad_data_msg = "";
+  if (xd.dims () != yd.dims ()
+      || (xd.dims () != zd.dims () && ! zd.isempty ()))
+    {
+      bad_data_msg = "x/y/zdata must have the same dimensions";
+      return;
+    }
+
+  octave_idx_type x_rows = xd.rows ();
+  octave_idx_type c_cols = cd.columns ();
+  octave_idx_type c_rows = cd.rows ();
+
+  if (! cd.isempty () && (c_rows != 1 || c_cols != 3)
+      && (c_rows != x_rows || (c_cols != 1 && c_cols != 3)))
+    {
+      bad_data_msg = "cdata must be an rgb triplet or have the same number of "
+                     "rows as X and one or three columns";
+      return;
+    }
+
+  octave_idx_type s_rows = sd.rows ();
+  if (s_rows != 1 && s_rows != x_rows)
+    {
+      bad_data_msg = "sizedata must be a scalar or a vector with the same "
+                     "dimensions as X";
+      return;
+    }
+}
+
+static bool updating_scatter_cdata = false;
+
+void
+scatter::properties::update_color (void)
+{
+  if (updating_scatter_cdata)
+    return;
+
+  Matrix series_idx = get_seriesindex ().matrix_value ();
+  if (series_idx.isempty ())
+    return;
+
+  gh_manager& gh_mgr
+    = octave::__get_gh_manager__ ("scatter::properties::update_color");
+
+  graphics_object go = gh_mgr.get_object (get___myhandle__ ());
+
+  axes::properties& parent_axes_prop
+    = dynamic_cast<axes::properties&>
+        (go.get_ancestor ("axes").get_properties ());
+
+  Matrix color_order = parent_axes_prop.get_colororder ().matrix_value ();
+  octave_idx_type s = (static_cast<octave_idx_type> (series_idx(0)) - 1)
+                      % color_order.rows ();
+
+  Matrix color = Matrix (1, 3, 0.);
+  color(0) = color_order(s,0);
+  color(1) = color_order(s,1);
+  color(2) = color_order(s,2);
+
+  octave::unwind_protect_var<bool> restore_var (updating_scatter_cdata, true);
+
+  set_cdata (color);
+  set_cdatamode ("auto");
+}
+
+void
+scatter::initialize (const graphics_object& go)
+{
+  base_graphics_object::initialize (go);
+
+  Matrix series_idx = xproperties.get_seriesindex ().matrix_value ();
+  if (series_idx.isempty ())
+    {
+      // Increment series index counter in parent axes
+      axes::properties& parent_axes_prop
+        = dynamic_cast<axes::properties&>
+            (go.get_ancestor ("axes").get_properties ());
+
+      if (! parent_axes_prop.nextplot_is ("add"))
+        parent_axes_prop.set_nextseriesindex (1);
+
+      series_idx.resize (1, 1);
+      series_idx(0) = parent_axes_prop.get_nextseriesindex ();
+      xproperties.set_seriesindex (series_idx);
+
+      parent_axes_prop.set_nextseriesindex
+        (parent_axes_prop.get_nextseriesindex () + 1);
+    }
+
+  if (xproperties.cdatamode_is ("auto"))
+    xproperties.update_color ();
+}
+
+// ---------------------------------------------------------------------
+
+octave_value
 surface::properties::get_color_data (void) const
 {
   return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3);
@@ -10649,10 +10837,7 @@
 
   get_children_limits (min_val, max_val, min_pos, max_neg, kids, update_type);
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_hggroup_limits);
-
-  updating_hggroup_limits = true;
+  octave::unwind_protect_var<bool> restore_var (updating_hggroup_limits, true);
 
   if (limits(0) != min_val || limits(1) != max_val
       || limits(2) != min_pos || limits(3) != max_neg)
@@ -10739,10 +10924,7 @@
       update_type = 'a';
     }
 
-  octave::unwind_protect frame;
-  frame.protect_var (updating_hggroup_limits);
-
-  updating_hggroup_limits = true;
+  octave::unwind_protect_var<bool> restore_var (updating_hggroup_limits, true);
 
   Matrix limits (1, 4);
 
@@ -10798,8 +10980,8 @@
           graphics_object go = gh_mgr.get_object (hobj);
 
           if (go.valid_object ()
-              && go.get ("uicontextmenu") == get___myhandle__ ())
-            go.set ("uicontextmenu", Matrix ());
+              && go.get ("contextmenu") == get___myhandle__ ())
+            go.set ("contextmenu", Matrix ());
         }
     }
 }
@@ -11470,7 +11652,7 @@
                 {
                   octave_value p = popup(j);
                   if (! p.is_string () || p.isempty ())
-                    error ("set: pop-up menu definitions must be non-empty strings.");
+                    error ("set: pop-up menu definitions must be non-empty strings");
                 }
             }
           else if (! (v.is_string () || v.isempty ()))
@@ -11492,7 +11674,7 @@
     }
   else
     {
-      error ("set: expecting cell of strings.");
+      error ("set: expecting cell of strings");
     }
 }
 
@@ -11528,7 +11710,7 @@
     error_exists = true;
 
   if (error_exists)
-    error ("set: expecting either 'auto' or a cell of pixel values or auto.");
+    error ("set: expecting either 'auto' or a cell of pixel values or auto");
   else
     {
       if (columnwidth.set (val, true))
@@ -12108,9 +12290,8 @@
       else
         args(1) = Matrix ();
 
-      octave::unwind_protect_safe frame;
-
-      frame.add_method (this, &gh_manager::restore_gcbo);
+      octave::unwind_action_safe restore_gcbo_action
+        (&gh_manager::restore_gcbo, this);
 
       graphics_object go (get_object (h));
       if (go)
@@ -12138,9 +12319,9 @@
             {
               m_interpreter.eval_string (s, false, status, 0);
             }
-          catch (octave::execution_exception& e)
-            {
-              m_interpreter.handle_exception (e);
+          catch (const octave::execution_exception& ee)
+            {
+              m_interpreter.handle_exception (ee);
             }
         }
       else if (cb.iscell () && cb.length () > 0
@@ -12170,9 +12351,9 @@
             else
               octave::feval (fcn, args);
           }
-        catch (octave::execution_exception& e)
+        catch (const octave::execution_exception& ee)
           {
-            m_interpreter.handle_exception (e);
+            m_interpreter.handle_exception (ee);
           }
 
       // Redraw after interacting with a user-interface (ui*) object.
@@ -12350,7 +12531,7 @@
 
 /*
 ## Test interruptible/busyaction properties
-%!function cb (h)
+%!function cb (h, ~)
 %! setappdata (gcbf (), "cb_exec", [getappdata(gcbf (), "cb_exec") h]);
 %! drawnow ();
 %! setappdata (gcbf (), "cb_exec", [getappdata(gcbf (), "cb_exec") h]);
@@ -12433,6 +12614,7 @@
   plist_map["text"] = text::properties::factory_defaults ();
   plist_map["image"] = image::properties::factory_defaults ();
   plist_map["patch"] = patch::properties::factory_defaults ();
+  plist_map["scatter"] = scatter::properties::factory_defaults ();
   plist_map["surface"] = surface::properties::factory_defaults ();
   plist_map["light"] = light::properties::factory_defaults ();
   plist_map["hggroup"] = hggroup::properties::factory_defaults ();
@@ -12477,8 +12659,8 @@
 %! unwind_protect
 %!   assert (ishghandle (hf));
 %!   assert (! ishghandle (-hf));
-%!   ax = gca;
-%!   l = line;
+%!   ax = gca ();
+%!   l = line ();
 %!   assert (ishghandle (ax));
 %!   assert (! ishghandle (-ax));
 %!   assert (ishghandle ([l, -1, ax, hf]), logical ([1, 0, 1, 1]));
@@ -12822,7 +13004,7 @@
                 }
             }
           else
-            error ("set: unknown property");
+            error (R"(set: unknown property "%s")", property.c_str ());
         }
       else if (nargin == 1)
         {
@@ -13086,21 +13268,21 @@
       h = gh_mgr.make_graphics_handle (go_name, parent,
                                        integer_figure_handle, false, false);
     }
-  catch (octave::execution_exception& e)
-    {
-      error (e, "__go_%s__: %s, unable to create graphics handle",
-             go_name.c_str (), e.message ().c_str ());
+  catch (octave::execution_exception& ee)
+    {
+      error (ee, "__go_%s__: %s, unable to create graphics handle",
+             go_name.c_str (), ee.message ().c_str ());
     }
 
   try
     {
       xset (h, xargs);
     }
-  catch (octave::execution_exception& e)
+  catch (octave::execution_exception& ee)
     {
       delete_graphics_object (h);
-      error (e, "__go_%s__: %s, unable to create graphics handle",
-             go_name.c_str (), e.message ().c_str ());
+      error (ee, "__go_%s__: %s, unable to create graphics handle",
+             go_name.c_str (), ee.message ().c_str ());
     }
 
   adopt (parent, h);
@@ -13192,10 +13374,10 @@
         {
           xset (h, xargs);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
           delete_graphics_object (h);
-          error (e, "__go_figure__: unable to create figure handle");
+          error (ee, "__go_figure__: unable to create figure handle");
         }
 
       adopt (0, h);
@@ -13228,7 +13410,7 @@
 
   if (go.isa ("surface"))
     nd = 3;
-  else if ((go.isa ("line") || go.isa ("patch"))
+  else if ((go.isa ("line") || go.isa ("patch") || go.isa ("scatter"))
            && ! go.get ("zdata").isempty ())
     nd = 3;
   else
@@ -13331,6 +13513,15 @@
   GO_BODY (patch);
 }
 
+DEFMETHOD (__go_scatter__, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __go_scatter__ (@var{parent})
+Undocumented internal function.
+@end deftypefn */)
+{
+  GO_BODY (scatter);
+}
+
 DEFMETHOD (__go_light__, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn {} {} __go_light__ (@var{parent})
@@ -13700,9 +13891,7 @@
   if (args.length () > 3)
     print_usage ();
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (Vdrawnow_requested, false);
+  octave::unwind_protect_var<bool> restore_var (Vdrawnow_requested, false);
 
   // Redraw unless we are in the middle of a deletion.
 
@@ -14236,7 +14425,7 @@
 not an integer, it is truncated towards 0.
 
 To define a condition on a property named @qcode{"timeout"}, use the string
-@qcode{'\timeout'} instead.
+@qcode{'@backslashchar{}timeout'} instead.
 
 In all cases, typing CTRL-C stops program execution immediately.
 @seealso{waitforbuttonpress, isequal}
@@ -14256,7 +14445,9 @@
 
   caseless_str pname;
 
-  octave::unwind_protect frame;
+  octave::unwind_action cleanup_waitfor_id_action;
+  octave::unwind_action cleanup_waitfor_postset_listener_action;
+  octave::unwind_action cleanup_waitfor_predelete_listener_action;
 
   static uint32_t id_counter = 0;
   uint32_t id = 0;
@@ -14306,7 +14497,7 @@
           Cell listener (1, max_arg_index >= 2 ? 5 : 4);
 
           id = id_counter++;
-          frame.add_fcn (cleanup_waitfor_id, id);
+          cleanup_waitfor_id_action.set (cleanup_waitfor_id, id);
           waitfor_results[id] = false;
 
           listener(0) = wf_listener;
@@ -14332,8 +14523,9 @@
                 waitfor_results[id] = true;
               else
                 {
-
-                  frame.add_fcn (cleanup_waitfor_postset_listener, ov_listener);
+                  cleanup_waitfor_postset_listener_action.set
+                    (cleanup_waitfor_postset_listener, ov_listener);
+
                   go.add_property_listener (pname, ov_listener, GCB_POSTSET);
                   go.add_property_listener (pname, ov_listener, GCB_PERSISTENT);
 
@@ -14356,8 +14548,9 @@
 
                       octave_value ov_del_listener (del_listener);
 
-                      frame.add_fcn (cleanup_waitfor_predelete_listener,
-                                     ov_del_listener);
+                      cleanup_waitfor_predelete_listener_action.set
+                        (cleanup_waitfor_predelete_listener, ov_del_listener);
+
                       go.add_property_listener (pname, ov_del_listener,
                                                 GCB_PREDELETE);
                     }
@@ -14528,6 +14721,42 @@
   return ovl (go.get_toolkit ().get_pixels (go));
 }
 
+DEFMETHOD (__get_position__, interp, args, ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {@var{pos} =} __get_position__ (@var{h}, @var{units})
+Internal function.
+
+Return the position of the graphics object @var{h} in the specified
+@var{units}.
+@end deftypefn */)
+{
+  if (args.length () != 2)
+    print_usage ();
+
+  double h
+    = args(0).xdouble_value ("__get_position__: H must be a graphics handle");
+
+  std::string units
+    = args(1).xstring_value ("__get_position__: UNITS must be a string");
+
+  gh_manager& gh_mgr = interp.get_gh_manager ();
+
+  graphics_object go = gh_mgr.get_object (h);
+
+  if (h == 0 || ! go)
+    error ("__get_position__: H must be a handle to a valid graphics object");
+
+  graphics_object parent_go = gh_mgr.get_object (go.get_parent ());
+  Matrix bbox = parent_go.get_properties ().get_boundingbox (true)
+                .extract_n (0, 2, 1, 2);
+
+  Matrix pos = convert_position (go.get ("position").matrix_value (),
+                                 go.get ("units").string_value (),
+                                 units, bbox);
+
+  return ovl (pos);
+}
+
 DEFUN (__get_system_fonts__, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {@var{font_struct} =} __get_system_fonts__ ()
--- a/libinterp/corefcn/graphics.in.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/graphics.in.h	Sun May 16 09:44:35 2021 +0200
@@ -60,7 +60,7 @@
 
 // ---------------------------------------------------------------------
 
-class base_scaler
+class OCTINTERP_API base_scaler
 {
 public:
   base_scaler (void) { }
@@ -152,7 +152,7 @@
   }
 };
 
-class neg_log_scaler : public base_scaler
+class OCTINTERP_API neg_log_scaler : public base_scaler
 {
 public:
   neg_log_scaler (void) { }
@@ -192,7 +192,7 @@
   }
 };
 
-class scaler
+class OCTINTERP_API scaler
 {
 public:
   scaler (void) : rep (new base_scaler ()) { }
@@ -268,7 +268,7 @@
 
 // ---------------------------------------------------------------------
 
-class property;
+class OCTINTERP_API property;
 
 // FIXME: These values should probably be defined inside a namespace or
 // class, but which one is most appropriate?  For now, prefix with
@@ -277,7 +277,7 @@
 
 enum listener_mode { GCB_POSTSET, GCB_PERSISTENT, GCB_PREDELETE };
 
-class base_property
+class OCTINTERP_API base_property
 {
 public:
   friend class property;
@@ -430,7 +430,7 @@
 
 // ---------------------------------------------------------------------
 
-class string_property : public base_property
+class OCTINTERP_API string_property : public base_property
 {
 public:
   string_property (const std::string& s, const graphics_handle& h,
@@ -476,7 +476,7 @@
 
 // ---------------------------------------------------------------------
 
-class string_array_property : public base_property
+class OCTINTERP_API string_array_property : public base_property
 {
 public:
   enum desired_enum { string_t, cell_t };
@@ -676,7 +676,7 @@
 
 // ---------------------------------------------------------------------
 
-class text_label_property : public base_property
+class OCTINTERP_API text_label_property : public base_property
 {
 public:
   enum type { char_t, cellstr_t };
@@ -808,9 +808,9 @@
           {
             nda = val.array_value ();
           }
-        catch (octave::execution_exception& e)
+        catch (octave::execution_exception& ee)
           {
-            error (e, R"(set: invalid string property value for "%s")",
+            error (ee, R"(set: invalid string property value for "%s")",
                    get_name ().c_str ());
           }
 
@@ -838,7 +838,7 @@
 
 // ---------------------------------------------------------------------
 
-class radio_values
+class OCTINTERP_API radio_values
 {
 public:
   OCTINTERP_API radio_values (const std::string& opt_string = "");
@@ -908,9 +908,9 @@
       return false;
   }
 
-  std::string values_as_string (void) const;
-
-  Cell values_as_cell (void) const;
+  OCTINTERP_API std::string values_as_string (void) const;
+
+  OCTINTERP_API Cell values_as_cell (void) const;
 
   octave_idx_type nelem (void) const { return possible_vals.size (); }
 
@@ -920,7 +920,7 @@
   std::set<caseless_str> possible_vals;
 };
 
-class radio_property : public base_property
+class OCTINTERP_API radio_property : public base_property
 {
 public:
   radio_property (const std::string& nm, const graphics_handle& h,
@@ -997,7 +997,7 @@
 
 // ---------------------------------------------------------------------
 
-class color_values
+class OCTINTERP_API color_values
 {
 public:
   color_values (double r = 0, double g = 0, double b = 1)
@@ -1058,7 +1058,7 @@
   OCTINTERP_API bool str2rgb (const std::string& str);
 };
 
-class color_property : public base_property
+class OCTINTERP_API color_property : public base_property
 {
 public:
   color_property (const color_values& c, const radio_values& v)
@@ -1172,7 +1172,7 @@
   NOT_NAN,
   NOT_INF
 };
-class double_property : public base_property
+class OCTINTERP_API double_property : public base_property
 {
 public:
   double_property (const std::string& nm, const graphics_handle& h,
@@ -1284,7 +1284,7 @@
 
 // ---------------------------------------------------------------------
 
-class double_radio_property : public base_property
+class OCTINTERP_API double_radio_property : public base_property
 {
 public:
   double_radio_property (double d, const radio_values& v)
@@ -1366,7 +1366,7 @@
 
 // ---------------------------------------------------------------------
 
-class array_property : public base_property
+class OCTINTERP_API array_property : public base_property
 {
 public:
   array_property (void)
@@ -1497,7 +1497,7 @@
   std::pair<double, bool> minval, maxval;
 };
 
-class row_vector_property : public array_property
+class OCTINTERP_API row_vector_property : public array_property
 {
 public:
   row_vector_property (const std::string& nm, const graphics_handle& h,
@@ -1591,7 +1591,7 @@
 
 // ---------------------------------------------------------------------
 
-class bool_property : public radio_property
+class OCTINTERP_API bool_property : public radio_property
 {
 public:
   bool_property (const std::string& nm, const graphics_handle& h,
@@ -1630,7 +1630,7 @@
 
 // ---------------------------------------------------------------------
 
-class handle_property : public base_property
+class OCTINTERP_API handle_property : public base_property
 {
 public:
   handle_property (const std::string& nm, const graphics_handle& h,
@@ -1675,7 +1675,7 @@
 
 // ---------------------------------------------------------------------
 
-class any_property : public base_property
+class OCTINTERP_API any_property : public base_property
 {
 public:
   any_property (const std::string& nm, const graphics_handle& h,
@@ -1708,7 +1708,7 @@
 
 // ---------------------------------------------------------------------
 
-class children_property : public base_property
+class OCTINTERP_API children_property : public base_property
 {
 public:
   children_property (void)
@@ -1801,9 +1801,9 @@
       {
         new_kids = val.matrix_value ();
       }
-    catch (octave::execution_exception& e)
+    catch (octave::execution_exception& ee)
       {
-        error (e, "set: children must be an array of graphics handles");
+        error (ee, "set: children must be an array of graphics handles");
       }
 
     octave_idx_type nel = new_kids.numel ();
@@ -1863,7 +1863,7 @@
     children_list = val;
   }
 
-  Matrix do_get_children (bool return_hidden) const;
+  OCTINTERP_API Matrix do_get_children (bool return_hidden) const;
 
   Matrix do_get_all_children (void) const
   {
@@ -1899,7 +1899,7 @@
 
 // ---------------------------------------------------------------------
 
-class callback_property : public base_property
+class OCTINTERP_API callback_property : public base_property
 {
 public:
   callback_property (const std::string& nm, const graphics_handle& h,
@@ -1947,7 +1947,7 @@
 
 // ---------------------------------------------------------------------
 
-class property
+class OCTINTERP_API property
 {
 public:
   property (void) : rep (new base_property ("", graphics_handle ()))
@@ -2037,10 +2037,9 @@
   void run_listeners (listener_mode mode = GCB_POSTSET)
   { rep->run_listeners (mode); }
 
-  OCTINTERP_API static
-  property create (const std::string& name, const graphics_handle& parent,
-                   const caseless_str& type,
-                   const octave_value_list& args);
+  static OCTINTERP_API property
+  create (const std::string& name, const graphics_handle& parent,
+          const caseless_str& type, const octave_value_list& args);
 
   property clone (void) const
   { return property (rep->clone ()); }
@@ -2073,7 +2072,7 @@
 
 typedef std::pair<std::string, octave_value> pval_pair;
 
-class pval_vector : public std::vector<pval_pair>
+class OCTINTERP_API pval_vector : public std::vector<pval_pair>
 {
 public:
   const_iterator find (const std::string pname) const
@@ -2137,7 +2136,7 @@
 
 };
 
-class property_list
+class OCTINTERP_API property_list
 {
 public:
   typedef pval_vector pval_map_type;
@@ -2154,9 +2153,9 @@
 
   ~property_list (void) = default;
 
-  void set (const caseless_str& name, const octave_value& val);
-
-  octave_value lookup (const caseless_str& name) const;
+  OCTINTERP_API void set (const caseless_str& name, const octave_value& val);
+
+  OCTINTERP_API octave_value lookup (const caseless_str& name) const;
 
   plist_map_iterator begin (void) { return plist_map.begin (); }
   plist_map_const_iterator begin (void) const { return plist_map.begin (); }
@@ -2174,7 +2173,8 @@
     return plist_map.find (go_name);
   }
 
-  octave_scalar_map as_struct (const std::string& prefix_arg) const;
+  OCTINTERP_API octave_scalar_map
+  as_struct (const std::string& prefix_arg) const;
 
 private:
   plist_map_type plist_map;
@@ -2196,9 +2196,9 @@
 
   virtual std::string graphics_object_name (void) const { return "unknown"; }
 
-  void mark_modified (void);
-
-  void override_defaults (base_graphics_object& obj);
+  OCTINTERP_API void mark_modified (void);
+
+  OCTINTERP_API void override_defaults (base_graphics_object& obj);
 
   virtual void init_integerhandle (const octave_value&)
   {
@@ -2208,7 +2208,8 @@
   // Look through DEFAULTS for properties with given CLASS_NAME, and
   // apply them to the current object with set (virtual method).
 
-  void set_from_list (base_graphics_object& obj, property_list& defaults);
+  OCTINTERP_API void
+  set_from_list (base_graphics_object& obj, property_list& defaults);
 
   void insert_property (const std::string& name, property p)
   {
@@ -2287,7 +2288,7 @@
 
   void set_tag (const octave_value& val) { tag = val; }
 
-  void set_parent (const octave_value& val);
+  OCTINTERP_API void set_parent (const octave_value& val);
 
   Matrix get_children (void) const
   {
@@ -2304,14 +2305,27 @@
     return children.get_hidden ();
   }
 
-  void get_children_of_type (const caseless_str& type, bool get_invisible,
-                             bool traverse,
-                             std::list<graphics_object> &children_list) const;
+  OCTINTERP_API void
+  get_children_of_type (const caseless_str& type, bool get_invisible,
+                        bool traverse,
+                        std::list<graphics_object> &children_list) const;
 
   void set_modified (const octave_value& val) { set___modified__ (val); }
 
   void set___modified__ (const octave_value& val) { __modified__ = val; }
 
+  // Redirect calls to "uicontextmenu" to "contextmenu".
+
+  graphics_handle get_uicontextmenu (void) const
+  {
+    return get_contextmenu ();
+  }
+
+  void set_uicontextmenu (const octave_value& val)
+  {
+    set_contextmenu (val);
+  }
+
   void reparent (const graphics_handle& new_parent) { parent = new_parent; }
 
   // Update data limits for AXIS_TYPE (xdata, ydata, etc.) in the parent
@@ -2322,7 +2336,7 @@
   virtual void update_axis_limits (const std::string& axis_type,
                                    const graphics_handle& h) const;
 
-  virtual void update_uicontextmenu (void) const;
+  virtual void update_contextmenu (void) const;
 
   virtual void delete_children (bool clear = false, bool from_root = false)
   {
@@ -2339,7 +2353,7 @@
     parent = new_gh;
   }
 
-  static property_list::pval_map_type factory_defaults (void);
+  static OCTINTERP_API property_list::pval_map_type factory_defaults (void);
 
   // FIXME: These functions should be generated automatically by the
   //        genprops.awk script.
@@ -2358,22 +2372,23 @@
   virtual bool is_yliminclude (void) const { return false; }
   virtual bool is_zliminclude (void) const { return false; }
 
-  bool is_handle_visible (void) const;
-
-  std::set<std::string> dynamic_property_names (void) const;
-
-  bool has_dynamic_property (const std::string& pname) const;
+  OCTINTERP_API bool is_handle_visible (void) const;
+
+  OCTINTERP_API std::set<std::string> dynamic_property_names (void) const;
+
+  OCTINTERP_API bool has_dynamic_property (const std::string& pname) const;
 
 protected:
   std::set<std::string> dynamic_properties;
 
-  void set_dynamic (const caseless_str& pname, const octave_value& val);
-
-  octave_value get_dynamic (const caseless_str& pname) const;
-
-  octave_value get_dynamic (bool all = false) const;
-
-  property get_property_dynamic (const caseless_str& pname) const;
+  OCTINTERP_API void
+  set_dynamic (const caseless_str& pname, const octave_value& val);
+
+  OCTINTERP_API octave_value get_dynamic (const caseless_str& pname) const;
+
+  OCTINTERP_API octave_value get_dynamic (bool all = false) const;
+
+  OCTINTERP_API property get_property_dynamic (const caseless_str& pname) const;
 
   BEGIN_BASE_PROPERTIES
     // properties common to all objects
@@ -2382,6 +2397,7 @@
     callback_property buttondownfcn , Matrix ()
     children_property children gf , Matrix ()
     bool_property clipping , "on"
+    handle_property contextmenu u , graphics_handle ()
     callback_property createfcn , Matrix ()
     callback_property deletefcn , Matrix ()
     radio_property handlevisibility u , "{on}|callback|off"
@@ -2393,7 +2409,7 @@
     bool_property selectionhighlight , "on"
     string_property tag s , ""
     string_property type frs , ty
-    handle_property uicontextmenu u , graphics_handle ()
+    handle_property uicontextmenu gsh , graphics_handle ()
     any_property userdata , Matrix ()
     bool_property visible u , "on"
 
@@ -2426,12 +2442,10 @@
   std::map<caseless_str, property, cmp_caseless_str> all_props;
 
 protected:
-  void insert_static_property (const std::string& name, base_property& p)
-  { insert_property (name, property (&p, true)); }
 
   virtual void init (void)
   {
-    uicontextmenu.add_constraint ("uicontextmenu");
+    contextmenu.add_constraint ("uicontextmenu");
   }
 };
 
@@ -2731,15 +2745,15 @@
     rep->set (name, val);
   }
 
-  void set (const octave_value_list& args);
-
-  void set (const Array<std::string>& names, const Cell& values,
-            octave_idx_type row);
-
-  void set (const octave_map& m);
-
-  void set_value_or_default (const caseless_str& name,
-                             const octave_value& val);
+  OCTINTERP_API void set (const octave_value_list& args);
+
+  OCTINTERP_API void set (const Array<std::string>& names, const Cell& values,
+                          octave_idx_type row);
+
+  OCTINTERP_API void set (const octave_map& m);
+
+  OCTINTERP_API void set_value_or_default (const caseless_str& name,
+                                           const octave_value& val);
 
   void set_defaults (const std::string& mode) { rep->set_defaults (mode); }
 
@@ -2814,7 +2828,7 @@
 
   graphics_handle get_handle (void) const { return rep->get_handle (); }
 
-  graphics_object get_ancestor (const std::string& type) const;
+  OCTINTERP_API graphics_object get_ancestor (const std::string& type) const;
 
   void remove_child (const graphics_handle& h) { rep->remove_child (h); }
 
@@ -2888,7 +2902,8 @@
   bool is_handle_visible (void) const
   { return get_properties ().is_handle_visible (); }
 
-  octave::graphics_toolkit get_toolkit (void) const { return rep->get_toolkit (); }
+  octave::graphics_toolkit get_toolkit (void) const
+  { return rep->get_toolkit (); }
 
   void add_property_listener (const std::string& nm, const octave_value& v,
                               listener_mode mode = GCB_POSTSET)
@@ -2928,10 +2943,12 @@
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    void remove_child (const graphics_handle& h, bool from_root = false);
-
-    Matrix get_boundingbox (bool internal = false,
-                            const Matrix& parent_pix_size = Matrix ()) const;
+    OCTINTERP_API void
+    remove_child (const graphics_handle& h, bool from_root = false);
+
+    OCTINTERP_API Matrix
+    get_boundingbox (bool internal = false,
+                     const Matrix& parent_pix_size = Matrix ()) const;
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -3073,7 +3090,7 @@
 
   bool valid_object (void) const { return true; }
 
-  void reset_default_properties (void);
+  OCTINTERP_API void reset_default_properties (void);
 
   bool has_readonly_property (const caseless_str& pname) const
   {
@@ -3089,7 +3106,8 @@
 
   property_list factory_properties;
 
-  static property_list::plist_map_type init_factory_properties (void);
+  static OCTINTERP_API property_list::plist_map_type
+  init_factory_properties (void);
 };
 
 // ---------------------------------------------------------------------
@@ -3097,6 +3115,7 @@
 class OCTINTERP_API figure : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
@@ -3105,41 +3124,44 @@
       integerhandle = val;
     }
 
-    void remove_child (const graphics_handle& h, bool from_root = false);
-
-    void set_visible (const octave_value& val);
-
-    octave::graphics_toolkit get_toolkit (void) const;
-
-    void set_toolkit (const octave::graphics_toolkit& b);
-
-    void set___graphics_toolkit__ (const octave_value& val);
-
-    void adopt (const graphics_handle& h);
-
-    void set_position (const octave_value& val,
-                       bool do_notify_toolkit = true);
-
-    void set_outerposition (const octave_value& val,
-                            bool do_notify_toolkit = true);
-
-    Matrix bbox2position (const Matrix& bbox) const;
-
-    Matrix get_boundingbox (bool internal = false,
-                            const Matrix& parent_pix_size = Matrix ()) const;
-
-    void set_boundingbox (const Matrix& bb, bool internal = false,
-                          bool do_notify_toolkit = true);
-
-    Matrix map_from_boundingbox (double x, double y) const;
-
-    Matrix map_to_boundingbox (double x, double y) const;
-
-    void update_units (const caseless_str& old_units);
-
-    void update_paperunits (const caseless_str& old_paperunits);
-
-    std::string get_title (void) const;
+    OCTINTERP_API void
+    remove_child (const graphics_handle& h, bool from_root = false);
+
+    OCTINTERP_API void set_visible (const octave_value& val);
+
+    OCTINTERP_API octave::graphics_toolkit get_toolkit (void) const;
+
+    OCTINTERP_API void set_toolkit (const octave::graphics_toolkit& b);
+
+    OCTINTERP_API void set___graphics_toolkit__ (const octave_value& val);
+
+    OCTINTERP_API void adopt (const graphics_handle& h);
+
+    OCTINTERP_API void set_position (const octave_value& val,
+                                     bool do_notify_toolkit = true);
+
+    OCTINTERP_API void set_outerposition (const octave_value& val,
+                                          bool do_notify_toolkit = true);
+
+    OCTINTERP_API Matrix bbox2position (const Matrix& bbox) const;
+
+    OCTINTERP_API Matrix
+    get_boundingbox (bool internal = false,
+                     const Matrix& parent_pix_size = Matrix ()) const;
+
+    OCTINTERP_API void
+    set_boundingbox (const Matrix& bb, bool internal = false,
+                     bool do_notify_toolkit = true);
+
+    OCTINTERP_API Matrix map_from_boundingbox (double x, double y) const;
+
+    OCTINTERP_API Matrix map_to_boundingbox (double x, double y) const;
+
+    OCTINTERP_API void update_units (const caseless_str& old_units);
+
+    OCTINTERP_API void update_paperunits (const caseless_str& old_paperunits);
+
+    OCTINTERP_API std::string get_title (void) const;
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -3243,7 +3265,7 @@
     }
 
   private:
-    Matrix get_auto_paperposition (void);
+    OCTINTERP_API Matrix get_auto_paperposition (void);
 
     void update_paperpositionmode (void)
     {
@@ -3251,9 +3273,9 @@
         paperposition.set (get_auto_paperposition ());
     }
 
-    void update_handlevisibility (void);
-
-    void init_toolkit (void);
+    OCTINTERP_API void update_handlevisibility (void);
+
+    OCTINTERP_API void init_toolkit (void);
 
     octave::graphics_toolkit toolkit;
   };
@@ -3305,7 +3327,7 @@
     return retval;
   }
 
-  octave_value get_default (const caseless_str& name) const;
+  OCTINTERP_API octave_value get_default (const caseless_str& name) const;
 
   octave_value get_defaults (void) const
   {
@@ -3323,7 +3345,7 @@
 
   bool valid_object (void) const { return true; }
 
-  void reset_default_properties (void);
+  OCTINTERP_API void reset_default_properties (void);
 
   bool has_readonly_property (const caseless_str& pname) const
   {
@@ -3342,6 +3364,7 @@
 class OCTINTERP_API graphics_xform
 {
 public:
+
   graphics_xform (void)
     : xform (xform_eye ()), xform_inv (xform_eye ()),
       sx ("linear"), sy ("linear"), sz ("linear"),  zlim (1, 2, 0.0)
@@ -3372,15 +3395,15 @@
     return *this;
   }
 
-  static ColumnVector xform_vector (double x, double y, double z);
-
-  static Matrix xform_eye (void);
-
-  ColumnVector transform (double x, double y, double z,
-                          bool use_scale = true) const;
-
-  ColumnVector untransform (double x, double y, double z,
-                            bool use_scale = true) const;
+  static OCTINTERP_API ColumnVector xform_vector (double x, double y, double z);
+
+  static OCTINTERP_API Matrix xform_eye (void);
+
+  OCTINTERP_API ColumnVector
+  transform (double x, double y, double z, bool use_scale = true) const;
+
+  OCTINTERP_API ColumnVector
+  untransform (double x, double y, double z, bool use_scale = true) const;
 
   ColumnVector untransform (double x, double y, bool use_scale = true) const
   { return untransform (x, y, (zlim(0)+zlim(1))/2, use_scale); }
@@ -3430,25 +3453,32 @@
 class OCTINTERP_API axes : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    void set_defaults (base_graphics_object& obj, const std::string& mode);
-
-    void remove_child (const graphics_handle& h, bool from_root = false);
-
-    void adopt (const graphics_handle& h);
+
+    OCTINTERP_API void
+    set_defaults (base_graphics_object& obj, const std::string& mode);
+
+    OCTINTERP_API void
+    remove_child (const graphics_handle& h, bool from_root = false);
+
+    OCTINTERP_API void adopt (const graphics_handle& h);
 
     const scaler& get_x_scaler (void) const { return sx; }
     const scaler& get_y_scaler (void) const { return sy; }
     const scaler& get_z_scaler (void) const { return sz; }
 
-    Matrix get_boundingbox (bool internal = false,
-                            const Matrix& parent_pix_size = Matrix ()) const;
-    Matrix get_extent (bool with_text = false,
-                       bool only_text_height=false) const;
-
-    double get___fontsize_points__ (double box_pix_height = 0) const;
+    OCTINTERP_API Matrix
+    get_boundingbox (bool internal = false,
+                     const Matrix& parent_pix_size = Matrix ()) const;
+    OCTINTERP_API Matrix
+    get_extent (bool with_text = false,
+                bool only_text_height=false) const;
+
+    OCTINTERP_API double
+    get___fontsize_points__ (double box_pix_height = 0) const;
 
     void update_boundingbox (void)
     {
@@ -3459,9 +3489,9 @@
         }
     }
 
-    void update_camera (void);
-    void update_axes_layout (void);
-    void update_aspectratios (void);
+    OCTINTERP_API void update_camera (void);
+    OCTINTERP_API void update_axes_layout (void);
+    OCTINTERP_API void update_aspectratios (void);
     void update_transform (void)
     {
       update_aspectratios ();
@@ -3469,13 +3499,50 @@
       update_axes_layout ();
     }
 
-    void sync_positions (void);
-
-    void update_autopos (const std::string& elem_type);
-    void update_xlabel_position (void);
-    void update_ylabel_position (void);
-    void update_zlabel_position (void);
-    void update_title_position (void);
+    OCTINTERP_API void sync_positions (void);
+
+    // Redirect calls to "activepositionproperty" to "positionconstraint".
+
+    std::string get_activepositionproperty (void) const
+    {
+      std::string cur_val;
+
+      if (positionconstraint.is ("innerposition"))
+        cur_val = "position";
+      else
+        cur_val = "outerposition";
+
+      return cur_val;
+    }
+
+    void set_activepositionproperty (const octave_value& val)
+    {
+      // call set method to validate the input
+      activepositionproperty.set (val);
+
+      if (val.char_matrix_value ().row_as_string (0) == "position")
+        set_positionconstraint ("innerposition");
+      else
+        set_positionconstraint (val);
+    }
+
+    // Redirect calls to "innerposition" to "position".
+
+    octave_value get_innerposition (void) const
+    {
+      return get_position ();
+    }
+
+    void set_innerposition (const octave_value& val)
+    {
+      set_position (val);
+    }
+
+    OCTINTERP_API void update_autopos (const std::string& elem_type);
+    OCTINTERP_API void update_xlabel_position (void);
+    OCTINTERP_API void update_ylabel_position (void);
+    OCTINTERP_API void update_zlabel_position (void);
+    OCTINTERP_API void update_title_position (void);
 
     graphics_xform get_transform (void) const
     { return graphics_xform (x_render, x_render_inv, sx, sy, sz, x_zlim); }
@@ -3533,36 +3600,43 @@
     ColumnVector coord2pixel (double x, double y, double z) const
     { return get_transform ().transform (x, y, z); }
 
-    void zoom_about_point (const std::string& mode, double x, double y,
-                           double factor, bool push_to_zoom_stack = true);
-    void zoom (const std::string& mode, double factor,
-               bool push_to_zoom_stack = true);
-    void zoom (const std::string& mode, const Matrix& xl, const Matrix& yl,
-               bool push_to_zoom_stack = true);
-
-    void translate_view (const std::string& mode,
-                         double x0, double x1, double y0, double y1,
-                         bool push_to_zoom_stack = true);
-
-    void pan (const std::string& mode, double factor,
+    OCTINTERP_API void
+    zoom_about_point (const std::string& mode, double x, double y,
+                      double factor, bool push_to_zoom_stack = true);
+    OCTINTERP_API void
+    zoom (const std::string& mode, double factor,
+          bool push_to_zoom_stack = true);
+    OCTINTERP_API void
+    zoom (const std::string& mode, const Matrix& xl, const Matrix& yl,
+          bool push_to_zoom_stack = true);
+
+    OCTINTERP_API void
+    translate_view (const std::string& mode,
+                    double x0, double x1, double y0, double y1,
+                    bool push_to_zoom_stack = true);
+
+    OCTINTERP_API void
+    pan (const std::string& mode, double factor,
+         bool push_to_zoom_stack = true);
+
+    OCTINTERP_API void
+    rotate3d (double x0, double x1, double y0, double y1,
               bool push_to_zoom_stack = true);
 
-    void rotate3d (double x0, double x1, double y0, double y1,
-                   bool push_to_zoom_stack = true);
-
-    void rotate_view (double delta_az, double delta_el,
-                      bool push_to_zoom_stack = true);
-
-    void unzoom (void);
-    void update_handlevisibility (void);
-    void push_zoom_stack (void);
-    void clear_zoom_stack (bool do_unzoom = true);
-
-    void update_units (const caseless_str& old_units);
-
-    void update_font (std::string prop = "");
-
-    void update_fontunits (const caseless_str& old_fontunits);
+    OCTINTERP_API void
+    rotate_view (double delta_az, double delta_el,
+                 bool push_to_zoom_stack = true);
+
+    OCTINTERP_API void unzoom (void);
+    OCTINTERP_API void update_handlevisibility (void);
+    OCTINTERP_API void push_zoom_stack (void);
+    OCTINTERP_API void clear_zoom_stack (bool do_unzoom = true);
+
+    OCTINTERP_API void update_units (const caseless_str& old_units);
+
+    OCTINTERP_API void update_font (std::string prop = "");
+
+    OCTINTERP_API void update_fontunits (const caseless_str& old_fontunits);
 
     void increase_num_lights (void) { num_lights++; }
     void decrease_num_lights (void) { num_lights--; }
@@ -3630,19 +3704,24 @@
     // Text renderer, used for calculation of text (tick labels) size
     octave::text_renderer txt_renderer;
 
-    void set_text_child (handle_property& h, const std::string& who,
-                         const octave_value& v);
-
-    void delete_text_child (handle_property& h, bool from_root = false);
+    OCTINTERP_API void
+    set_text_child (handle_property& h, const std::string& who,
+                    const octave_value& v);
+
+    OCTINTERP_API void
+    delete_text_child (handle_property& h, bool from_root = false);
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
     // Programming note: Keep property list sorted if new ones are added.
 
     BEGIN_PROPERTIES (axes)
-      radio_property activepositionproperty , "{outerposition}|position"
+      radio_property activepositionproperty gsh , "{outerposition}|position"
       row_vector_property alim m , default_lim ()
       radio_property alimmode , "{auto}|manual"
+      // FIXME: not yet implemented
+      array_property alphamap , Matrix ()
+      radio_property alphascale , "{linear}|log"
       color_property ambientlightcolor , color_values (1, 1, 1)
       bool_property box u , "off"
       radio_property boxstyle , "{back}|full"
@@ -3661,12 +3740,15 @@
       array_property colormap sg , Matrix ()
       array_property colororder , default_colororder ()
       double_property colororderindex , 1.0
+      radio_property colorscale , "{linear}|log"
       array_property currentpoint , Matrix (2, 3, 0.0)
       row_vector_property dataaspectratio mu , Matrix (1, 3, 1.0)
       radio_property dataaspectratiomode u , "{auto}|manual"
       radio_property fontangle u , "{normal}|italic"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
-      double_property fontsize u , 10
+      double_property fontsize mu , 10
+      // FIXME: not yet implemented
+      radio_property fontsizemode , "{auto}|manual"
       bool_property fontsmoothing u , "on"
       radio_property fontunits SU , "{points}|inches|centimeters|normalized|pixels"
       radio_property fontweight u , "{normal}|bold"
@@ -3675,8 +3757,15 @@
       color_property gridcolor m , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
       radio_property gridcolormode , "{auto}|manual"
       radio_property gridlinestyle , "{-}|--|:|-.|none"
+      array_property innerposition sg , default_axes_position ()
+      // FIXME: Should be an array of "interaction objects". Make it read-only for now.
+      any_property interactions r , Matrix ()
       double_property labelfontsizemultiplier u , 1.1
       radio_property layer u , "{bottom}|top"
+      // FIXME: Should be a "layoutoptions" object. Make it read-only for now.
+      handle_property layout r , graphics_handle ()
+      // FIXME: Should be a "legend" object. Make it read-only for now.
+      handle_property legend r , graphics_handle ()
       // FIXME: should be kind of string array.
       any_property linestyleorder S , "-"
       double_property linestyleorderindex , 1.0
@@ -3687,10 +3776,12 @@
       radio_property minorgridcolormode , "{auto}|manual"
       radio_property minorgridlinestyle , "{:}|-|--|-.|none"
       radio_property nextplot , "{replace}|add|replacechildren"
+      double_property nextseriesindex r , 1.0
       array_property outerposition u , default_axes_outerposition ()
       row_vector_property plotboxaspectratio mu , Matrix (1, 3, 1.0)
       radio_property plotboxaspectratiomode u , "{auto}|manual"
       array_property position u , default_axes_position ()
+      radio_property positionconstraint , "{outerposition}|innerposition"
       radio_property projection , "{orthographic}|perspective"
       radio_property sortmethod , "{depth}|childorder"
       radio_property tickdir mu , "{in}|out"
@@ -3702,9 +3793,12 @@
       handle_property title SOf , make_graphics_handle ("text", __myhandle__, false, false, false)
       double_property titlefontsizemultiplier u , 1.1
       radio_property titlefontweight u , "{bold}|normal"
-      // FIXME: uicontextmenu should be moved here.
+      // FIXME: Should be a "axestoolbar" object. Make it read-only for now.
+      handle_property toolbar r , graphics_handle ()
       radio_property units SU , "{normalized}|inches|centimeters|points|pixels|characters"
       array_property view u , default_axes_view ()
+      // FIXME: Should be a "ruler" object. Make it read-only for now.
+      handle_property xaxis r , graphics_handle ()
       radio_property xaxislocation u , "{bottom}|top|origin"
       color_property xcolor mu , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
       radio_property xcolormode , "{auto}|manual"
@@ -3722,6 +3816,8 @@
       radio_property xticklabelmode u , "{auto}|manual"
       double_property xticklabelrotation , 0.0
       radio_property xtickmode u , "{auto}|manual"
+      // FIXME: Should be a "ruler" object. Make it read-only for now.
+      handle_property yaxis r , graphics_handle ()
       radio_property yaxislocation u , "{left}|right|origin"
       color_property ycolor mu , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
       radio_property ycolormode , "{auto}|manual"
@@ -3738,6 +3834,8 @@
       radio_property yticklabelmode u , "{auto}|manual"
       double_property yticklabelrotation , 0.0
       radio_property ytickmode u , "{auto}|manual"
+      // FIXME: Should be a "ruler" object. Make it read-only for now.
+      handle_property zaxis r , graphics_handle ()
       color_property zcolor mu , color_property (color_values (0.15, 0.15, 0.15), radio_values ("none"))
       radio_property zcolormode , "{auto}|manual"
       radio_property zdir u , "{normal}|reverse"
@@ -3771,7 +3869,7 @@
    END_PROPERTIES
 
   protected:
-    void init (void);
+    OCTINTERP_API void init (void);
 
   private:
 
@@ -3801,7 +3899,8 @@
       sz = get_scale (get_zscale (), zlim.get ().matrix_value ());
     }
 
-    void update_label_color (handle_property label, color_property col);
+    OCTINTERP_API void
+    update_label_color (handle_property label, color_property col);
     void update_xcolor (void)
     { update_label_color (xlabel, xcolor); }
 
@@ -3913,12 +4012,12 @@
 
     void update_ticklabelinterpreter (void)
     {
-      update_xtick ();
-      update_ytick ();
-      update_ztick ();
+      update_xtick (false);
+      update_ytick (false);
+      update_ztick (true);
     }
 
-    void update_xtick (void)
+    void update_xtick (bool sync_pos = true)
     {
       calc_ticks_and_lims (xlim, xtick, xminortickvalues, xlimmode.is ("auto"),
                            xtickmode.is ("auto"), xscale.is ("log"));
@@ -3929,9 +4028,11 @@
                            (yaxislocation_is ("origin") ? 0 :
                              (yaxislocation_is ("left") ? -1 : 1)),
                          xlim);
-      sync_positions ();
+
+      if (sync_pos)
+        sync_positions ();
     }
-    void update_ytick (void)
+    void update_ytick (bool sync_pos = true)
     {
       calc_ticks_and_lims (ylim, ytick, yminortickvalues, ylimmode.is ("auto"),
                            ytickmode.is ("auto"), yscale.is ("log"));
@@ -3942,15 +4043,19 @@
                            (xaxislocation_is ("origin") ? 0 :
                              (xaxislocation_is ("bottom") ? -1 : 1)),
                          ylim);
-      sync_positions ();
+
+      if (sync_pos)
+        sync_positions ();
     }
-    void update_ztick (void)
+    void update_ztick (bool sync_pos = true)
     {
       calc_ticks_and_lims (zlim, ztick, zminortickvalues, zlimmode.is ("auto"),
                            ztickmode.is ("auto"), zscale.is ("log"));
       if (zticklabelmode.is ("auto"))
         calc_ticklabels (ztick, zticklabel, zscale.is ("log"), false, 2, zlim);
-      sync_positions ();
+
+      if (sync_pos)
+        sync_positions ();
     }
 
     void update_xtickmode (void)
@@ -4040,21 +4145,24 @@
       sync_positions ();
     }
 
-    void update_outerposition (void);
-    void update_position (void);
-    void update_looseinset (void);
-
-    double calc_tick_sep (double minval, double maxval);
-    void calc_ticks_and_lims (array_property& lims, array_property& ticks,
-                              array_property& mticks, bool limmode_is_auto,
-                              bool tickmode_is_auto, bool is_logscale);
-    void calc_ticklabels (const array_property& ticks, any_property& labels,
-                          bool is_logscale, const bool is_origin,
-                          const int other_axislocation,
-                          const array_property& axis_lims);
-    Matrix get_ticklabel_extents (const Matrix& ticks,
-                                  const string_vector& ticklabels,
-                                  const Matrix& limits);
+    OCTINTERP_API void update_outerposition (void);
+    OCTINTERP_API void update_position (void);
+    OCTINTERP_API void update_looseinset (void);
+
+    OCTINTERP_API double calc_tick_sep (double minval, double maxval);
+    OCTINTERP_API void
+    calc_ticks_and_lims (array_property& lims, array_property& ticks,
+                         array_property& mticks, bool limmode_is_auto,
+                         bool tickmode_is_auto, bool is_logscale);
+    OCTINTERP_API void
+    calc_ticklabels (const array_property& ticks, any_property& labels,
+                     bool is_logscale, const bool is_origin,
+                     const int other_axislocation,
+                     const array_property& axis_lims);
+    OCTINTERP_API Matrix
+    get_ticklabel_extents (const Matrix& ticks,
+                           const string_vector& ticklabels,
+                           const Matrix& limits);
 
     void fix_limits (array_property& lims)
     {
@@ -4076,7 +4184,7 @@
         }
     }
 
-    Matrix calc_tightbox (const Matrix& init_pos);
+    OCTINTERP_API Matrix calc_tightbox (const Matrix& init_pos);
 
     void set_colormap (const octave_value& val)
     {
@@ -4088,15 +4196,17 @@
       colormap.run_listeners (GCB_POSTSET);
     }
 
-    octave_value get_colormap (void) const;
+    OCTINTERP_API octave_value get_colormap (void) const;
 
   public:
-    Matrix get_axis_limits (double xmin, double xmax,
-                            double min_pos, double max_neg,
-                            const bool logscale);
-
-    void check_axis_limits (Matrix &limits, const Matrix kids,
-                            const bool logscale, char &update_type);
+    OCTINTERP_API Matrix
+    get_axis_limits (double xmin, double xmax,
+                     double min_pos, double max_neg,
+                     const bool logscale);
+
+    OCTINTERP_API void
+    check_axis_limits (Matrix &limits, const Matrix kids,
+                       const bool logscale, char &update_type);
 
     void update_xlim ()
     {
@@ -4215,7 +4325,7 @@
     return retval;
   }
 
-  octave_value get_default (const caseless_str& name) const;
+  OCTINTERP_API octave_value get_default (const caseless_str& name) const;
 
   octave_value get_defaults (void) const
   {
@@ -4231,14 +4341,14 @@
 
   const base_properties& get_properties (void) const { return xproperties; }
 
-  void update_axis_limits (const std::string& axis_type);
-
-  void update_axis_limits (const std::string& axis_type,
-                           const graphics_handle& h);
+  OCTINTERP_API void update_axis_limits (const std::string& axis_type);
+
+  OCTINTERP_API void update_axis_limits (const std::string& axis_type,
+                                         const graphics_handle& h);
 
   bool valid_object (void) const { return true; }
 
-  void reset_default_properties (void);
+  OCTINTERP_API void reset_default_properties (void);
 
   bool has_readonly_property (const caseless_str& pname) const
   {
@@ -4249,7 +4359,7 @@
   }
 
 protected:
-  void initialize (const graphics_object& go);
+  OCTINTERP_API void initialize (const graphics_object& go);
 
 private:
   property_list default_properties;
@@ -4260,9 +4370,11 @@
 class OCTINTERP_API line : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
+
     // See the genprops.awk script for an explanation of the
     // properties declarations.
     // Programming note: Keep property list sorted if new ones are added.
@@ -4301,8 +4413,8 @@
     }
 
   private:
-    Matrix compute_xlim (void) const;
-    Matrix compute_ylim (void) const;
+    OCTINTERP_API Matrix compute_xlim (void) const;
+    OCTINTERP_API Matrix compute_ylim (void) const;
 
     void update_xdata (void) { set_xlim (compute_xlim ()); }
 
@@ -4341,14 +4453,17 @@
 class OCTINTERP_API text : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    double get___fontsize_points__ (double box_pix_height = 0) const;
-
-    void update_text_extent (void);
-
-    void update_font (void);
+
+    OCTINTERP_API double
+    get___fontsize_points__ (double box_pix_height = 0) const;
+
+    OCTINTERP_API void update_text_extent (void);
+
+    OCTINTERP_API void update_font (void);
 
     void set_position (const octave_value& val)
     {
@@ -4382,8 +4497,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"
@@ -4417,8 +4531,8 @@
       double_property __fontsize_points__ hgr , 0
     END_PROPERTIES
 
-    Matrix get_data_position (void) const;
-    Matrix get_extent_matrix (void) const;
+    OCTINTERP_API Matrix get_data_position (void) const;
+    OCTINTERP_API Matrix get_extent_matrix (bool rotated = false) const;
     const uint8NDArray& get_pixels (void) const { return pixels; }
 
     // Text renderer, used for calculation of text size
@@ -4465,7 +4579,7 @@
         set_zliminclude ("off");
     }
 
-    void request_autopos (void);
+    OCTINTERP_API void request_autopos (void);
     void update_positionmode (void) { request_autopos (); }
     void update_rotationmode (void) { request_autopos (); }
     void update_horizontalalignmentmode (void) { request_autopos (); }
@@ -4490,11 +4604,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 (); }
 
@@ -4502,8 +4611,8 @@
     void update_horizontalalignment (void) { update_text_extent (); }
     void update_verticalalignment (void) { update_text_extent (); }
 
-    void update_units (void);
-    void update_fontunits (const caseless_str& old_fontunits);
+    OCTINTERP_API void update_units (void);
+    OCTINTERP_API void update_fontunits (const caseless_str& old_fontunits);
 
   private:
     std::string cached_units;
@@ -4542,9 +4651,11 @@
 class OCTINTERP_API image : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
+
     bool is_aliminclude (void) const
     { return (aliminclude.is_on () && alphadatamapping.is ("scaled")); }
     std::string get_aliminclude (void) const
@@ -4555,7 +4666,7 @@
     std::string get_climinclude (void) const
     { return climinclude.current_value (); }
 
-    octave_value get_color_data (void) const;
+    OCTINTERP_API octave_value get_color_data (void) const;
 
     void initialize_data (void) { update_cdata (); }
 
@@ -4755,6 +4866,7 @@
 class OCTINTERP_API light : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
     // See the genprops.awk script for an explanation of the
@@ -4774,7 +4886,7 @@
     }
 
   private:
-    void update_visible (void);
+    OCTINTERP_API void update_visible (void);
   };
 
 private:
@@ -4802,7 +4914,7 @@
   }
 
 protected:
-  void initialize (const graphics_object& go);
+  OCTINTERP_API void initialize (const graphics_object& go);
 };
 
 // ---------------------------------------------------------------------
@@ -4810,9 +4922,11 @@
 class OCTINTERP_API patch : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
+
     octave_value get_color_data (void) const;
 
     // Matlab allows incoherent data to be stored into patch properties.
@@ -4833,7 +4947,7 @@
     std::string get_climinclude (void) const
     { return climinclude.current_value (); }
 
-    bool get_do_lighting (void) const;
+    OCTINTERP_API bool get_do_lighting (void) const;
 
     std::vector<std::vector<octave_idx_type>> coplanar_last_idx;
 
@@ -4952,7 +5066,7 @@
 
     void update_facevertexcdata (void) { update_data ();}
 
-    void update_fvc (void);
+    OCTINTERP_API void update_fvc (void);
 
     void update_xdata (void)
     {
@@ -5011,11 +5125,11 @@
         clim = cdata.get_limits ();
     }
 
-    void update_data (void);
-
-    void calc_face_normals (Matrix& normals);
-    void update_face_normals (bool reset, bool force = false);
-    void update_vertex_normals (bool reset, bool force = false);
+    OCTINTERP_API void update_data (void);
+
+    OCTINTERP_API void calc_face_normals (Matrix& normals);
+    OCTINTERP_API void update_face_normals (bool reset, bool force = false);
+    OCTINTERP_API void update_vertex_normals (bool reset, bool force = false);
 
     void update_edgelighting (void)
     {
@@ -5069,10 +5183,244 @@
     return retval;
   }
 
-  void reset_default_properties (void);
+  OCTINTERP_API void reset_default_properties (void);
 
 protected:
-  void initialize (const graphics_object& go);
+  OCTINTERP_API void initialize (const graphics_object& go);
+
+};
+
+// ---------------------------------------------------------------------
+
+class OCTINTERP_API scatter : public base_graphics_object
+{
+public:
+
+  class OCTINTERP_API properties : public base_properties
+  {
+  public:
+
+    OCTINTERP_API octave_value get_color_data (void) const;
+
+    // Matlab allows incoherent data to be stored in scatter properties.
+    // The scatter object should then be ignored by the renderer.
+    bool has_bad_data (std::string& msg) const
+    {
+      msg = bad_data_msg;
+      return ! msg.empty ();
+    }
+
+    bool is_aliminclude (void) const
+    { return aliminclude.is_on (); }
+    std::string get_aliminclude (void) const
+    { return aliminclude.current_value (); }
+
+    bool is_climinclude (void) const
+    { return climinclude.is_on (); }
+    std::string get_climinclude (void) const
+    { return climinclude.current_value (); }
+
+    // See the genprops.awk script for an explanation of the
+    // properties declarations.
+    // Programming note: Keep property list sorted if new ones are added.
+
+    BEGIN_PROPERTIES (scatter)
+      array_property annotation , Matrix ()
+      array_property cdata mu , Matrix ()
+      radio_property cdatamode u , "{auto}|manual"
+      string_property cdatasource , ""
+      array_property datatiptemplate , Matrix ()
+      string_property displayname , ""
+      array_property latitudedata , Matrix ()
+      string_property latitudedatasource , ""
+      double_property linewidth , 0.5
+      array_property longitudedata , Matrix ()
+      string_property longitudedatasource , ""
+      radio_property marker , "{o}|+|*|.|x|s|square|d|diamond|^|v|>|<|p|pentagram|h|hexagram|none"
+      double_property markeredgealpha , 1.0
+      color_property markeredgecolor , color_property (radio_values ("{flat}|none"), color_values (0, 0, 0))
+      double_property markerfacealpha , 1.0
+      color_property markerfacecolor , color_property (radio_values ("{none}|auto|flat"), color_values (0, 0, 0))
+      array_property rdata , Matrix ()
+      string_property rdatasource , ""
+      array_property seriesindex u , Matrix ()
+      array_property sizedata u , Matrix ()
+      string_property sizedatasource , ""
+      array_property thetadata , Matrix ()
+      string_property thetadatasource , ""
+      array_property xdata u , Matrix ()
+      string_property xdatasource , ""
+      array_property ydata u , Matrix ()
+      string_property ydatasource , ""
+      array_property zdata u , Matrix ()
+      string_property zdatasource , ""
+
+      // hidden properties for limit computation
+      row_vector_property alim hlr , Matrix ()
+      row_vector_property clim hlr , Matrix ()
+      row_vector_property xlim hlr , Matrix ()
+      row_vector_property ylim hlr , Matrix ()
+      row_vector_property zlim hlr , Matrix ()
+      bool_property aliminclude hlg , "on"
+      bool_property climinclude hlg , "on"
+      bool_property xliminclude hl , "on"
+      bool_property yliminclude hl , "on"
+      bool_property zliminclude hl , "on"
+    END_PROPERTIES
+
+  protected:
+    void init (void)
+    {
+      xdata.add_constraint (dim_vector (-1, 1));
+      xdata.add_constraint (dim_vector (1, -1));
+      xdata.add_constraint (dim_vector (-1, 0));
+      xdata.add_constraint (dim_vector (0, -1));
+      ydata.add_constraint (dim_vector (-1, 1));
+      ydata.add_constraint (dim_vector (1, -1));
+      ydata.add_constraint (dim_vector (-1, 0));
+      ydata.add_constraint (dim_vector (0, -1));
+      zdata.add_constraint (dim_vector (-1, 1));
+      zdata.add_constraint (dim_vector (1, -1));
+      zdata.add_constraint (dim_vector (-1, 0));
+      zdata.add_constraint (dim_vector (0, -1));
+      sizedata.add_constraint ("min", 0.0, false);
+      sizedata.add_constraint (dim_vector (-1, 1));
+      sizedata.add_constraint (dim_vector (1, -1));
+      sizedata.add_constraint (dim_vector (-1, 0));
+      sizedata.add_constraint (dim_vector (0, -1));
+      cdata.add_constraint ("double");
+      cdata.add_constraint ("single");
+      cdata.add_constraint ("logical");
+      cdata.add_constraint ("int8");
+      cdata.add_constraint ("int16");
+      cdata.add_constraint ("int32");
+      cdata.add_constraint ("int64");
+      cdata.add_constraint ("uint8");
+      cdata.add_constraint ("uint16");
+      cdata.add_constraint ("uint32");
+      cdata.add_constraint ("uint64");
+      cdata.add_constraint ("real");
+      cdata.add_constraint (dim_vector (-1, 1));
+      cdata.add_constraint (dim_vector (-1, 3));
+      cdata.add_constraint (dim_vector (-1, 0));
+      cdata.add_constraint (dim_vector (0, -1));
+
+      linewidth.add_constraint ("min", 0.0, false);
+      seriesindex.add_constraint (dim_vector (1, 1));
+      seriesindex.add_constraint (dim_vector (-1, 0));
+      seriesindex.add_constraint (dim_vector (0, -1));
+    }
+
+  public:
+    OCTINTERP_API void update_color (void);
+
+  private:
+    std::string bad_data_msg;
+
+    void update_xdata (void)
+    {
+      if (get_xdata ().isempty ())
+        {
+          // For compatibility with Matlab behavior,
+          // if x/ydata are set empty, silently empty other *data properties.
+          set_ydata (Matrix ());
+          set_zdata (Matrix ());
+          bool cdatamode_auto = cdatamode.is ("auto");
+          set_cdata (Matrix ());
+          if (cdatamode_auto)
+            set_cdatamode ("auto");
+        }
+
+      set_xlim (xdata.get_limits ());
+
+      update_data ();
+    }
+
+    void update_ydata (void)
+    {
+      if (get_ydata ().isempty ())
+        {
+          set_xdata (Matrix ());
+          set_zdata (Matrix ());
+          bool cdatamode_auto = cdatamode.is ("auto");
+          set_cdata (Matrix ());
+          if (cdatamode_auto)
+            set_cdatamode ("auto");
+        }
+
+      set_ylim (ydata.get_limits ());
+
+      update_data ();
+    }
+
+    void update_zdata (void)
+    {
+      set_zlim (zdata.get_limits ());
+
+      update_data ();
+    }
+
+    void update_sizedata (void)
+    {
+      update_data ();
+    }
+
+    void update_cdata (void)
+    {
+      if (get_cdata ().matrix_value ().rows () == 1)
+        set_clim (cdata.get_limits ());
+      else
+        clim = cdata.get_limits ();
+
+      update_data ();
+    }
+
+    void update_cdatamode (void)
+    {
+      if (cdatamode.is ("auto"))
+        update_color ();
+    }
+
+    void update_seriesindex (void)
+    {
+      if (cdatamode.is ("auto"))
+        update_color ();
+    }
+
+    void update_data (void);
+
+  };
+
+private:
+  properties xproperties;
+  property_list default_properties;
+
+public:
+  scatter (const graphics_handle& mh, const graphics_handle& p)
+    : base_graphics_object (), xproperties (mh, p)
+  {
+    // FIXME: seriesindex should increment by one each time a new scatter
+    // object is added to the axes.
+  }
+
+  ~scatter (void) = default;
+
+  base_properties& get_properties (void) { return xproperties; }
+
+  const base_properties& get_properties (void) const { return xproperties; }
+
+  bool valid_object (void) const { return true; }
+
+  bool has_readonly_property (const caseless_str& pname) const
+  {
+    bool retval = xproperties.has_readonly_property (pname);
+    if (! retval)
+      retval = base_properties::has_readonly_property (pname);
+    return retval;
+  }
+
+protected:
+  OCTINTERP_API void initialize (const graphics_object& go);
 
 };
 
@@ -5081,9 +5429,11 @@
 class OCTINTERP_API surface : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
+
     octave_value get_color_data (void) const;
 
     bool is_aliminclude (void) const
@@ -5096,7 +5446,7 @@
     std::string get_climinclude (void) const
     { return climinclude.current_value (); }
 
-    bool get_do_lighting (void) const;
+    OCTINTERP_API bool get_do_lighting (void) const;
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -5236,8 +5586,8 @@
       set_zlim (zdata.get_limits ());
     }
 
-    void update_face_normals (bool reset, bool force = false);
-    void update_vertex_normals (bool reset, bool force = false);
+    OCTINTERP_API void update_face_normals (bool reset, bool force = false);
+    OCTINTERP_API void update_vertex_normals (bool reset, bool force = false);
 
     void update_facenormalsmode (void)
     { update_face_normals (false); }
@@ -5289,12 +5639,15 @@
 class OCTINTERP_API hggroup : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    void remove_child (const graphics_handle& h, bool from_root = false);
-
-    void adopt (const graphics_handle& h);
+
+    OCTINTERP_API void
+    remove_child (const graphics_handle& h, bool from_root = false);
+
+    OCTINTERP_API void adopt (const graphics_handle& h);
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -5317,9 +5670,9 @@
     END_PROPERTIES
 
   private:
-    void update_limits (void) const;
-
-    void update_limits (const graphics_handle& h) const;
+    OCTINTERP_API void update_limits (void) const;
+
+    OCTINTERP_API void update_limits (const graphics_handle& h) const;
 
   protected:
     void init (void)
@@ -5343,10 +5696,10 @@
 
   bool valid_object (void) const { return true; }
 
-  void update_axis_limits (const std::string& axis_type);
-
-  void update_axis_limits (const std::string& axis_type,
-                           const graphics_handle& h);
+  OCTINTERP_API void update_axis_limits (const std::string& axis_type);
+
+  OCTINTERP_API void update_axis_limits (const std::string& axis_type,
+                                         const graphics_handle& h);
 
   bool has_readonly_property (const caseless_str& pname) const
   {
@@ -5363,9 +5716,11 @@
 class OCTINTERP_API uimenu : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
+
     void remove_child (const graphics_handle& h, bool from_root = false)
     {
       base_properties::remove_child (h, from_root);
@@ -5430,9 +5785,11 @@
 
 // ---------------------------------------------------------------------
 
+// FIXME: This class has been renamed to "contextmenu" in Matlab R2020a.
 class OCTINTERP_API uicontextmenu : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
@@ -5469,7 +5826,7 @@
     // List of objects that might depend on this uicontextmenu object
     std::list<graphics_handle> dependent_obj_list;
 
-    void update_beingdeleted (void);
+    OCTINTERP_API void update_beingdeleted (void);
 
   };
 
@@ -5504,13 +5861,17 @@
 class OCTINTERP_API uicontrol : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    Matrix get_boundingbox (bool internal = false,
-                            const Matrix& parent_pix_size = Matrix ()) const;
-
-    double get___fontsize_points__ (double box_pix_height = 0) const;
+
+    OCTINTERP_API Matrix
+    get_boundingbox (bool internal = false,
+                     const Matrix& parent_pix_size = Matrix ()) const;
+
+    OCTINTERP_API double
+    get___fontsize_points__ (double box_pix_height = 0) const;
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -5523,8 +5884,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"
@@ -5566,7 +5926,7 @@
       cached_units = get_units ();
     }
 
-    void update_text_extent (void);
+    OCTINTERP_API void update_text_extent (void);
 
     void update_string (void) { update_text_extent (); }
     void update_fontname (void) { update_text_extent (); }
@@ -5574,17 +5934,12 @@
     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 (); }
 
-    void update_fontunits (const caseless_str& old_units);
-
-    void update_units (void);
+    OCTINTERP_API void update_fontunits (const caseless_str& old_units);
+
+    OCTINTERP_API void update_units (void);
 
   };
 
@@ -5618,17 +5973,22 @@
 class OCTINTERP_API uibuttongroup : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    void remove_child (const graphics_handle& h, bool from_root = false);
-
-    void adopt (const graphics_handle& h);
-
-    Matrix get_boundingbox (bool internal = false,
-                            const Matrix& parent_pix_size = Matrix ()) const;
-
-    double get___fontsize_points__ (double box_pix_height = 0) const;
+
+    OCTINTERP_API void
+    remove_child (const graphics_handle& h, bool from_root = false);
+
+    OCTINTERP_API void adopt (const graphics_handle& h);
+
+    OCTINTERP_API Matrix
+    get_boundingbox (bool internal = false,
+                     const Matrix& parent_pix_size = Matrix ()) const;
+
+    OCTINTERP_API double
+    get___fontsize_points__ (double box_pix_height = 0) const;
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -5639,8 +5999,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"
@@ -5679,8 +6038,8 @@
     // void update_fontangle (void) { update_text_extent (); }
     // void update_fontweight (void) { update_fontweight (); }
 
-    void update_units (const caseless_str& old_units);
-    void update_fontunits (const caseless_str& old_units);
+    OCTINTERP_API void update_units (const caseless_str& old_units);
+    OCTINTERP_API void update_fontunits (const caseless_str& old_units);
 
   };
 
@@ -5715,13 +6074,17 @@
 class OCTINTERP_API uipanel : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    Matrix get_boundingbox (bool internal = false,
-                            const Matrix& parent_pix_size = Matrix ()) const;
-
-    double get___fontsize_points__ (double box_pix_height = 0) const;
+
+    OCTINTERP_API Matrix
+    get_boundingbox (bool internal = false,
+                     const Matrix& parent_pix_size = Matrix ()) const;
+
+    OCTINTERP_API double
+    get___fontsize_points__ (double box_pix_height = 0) const;
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -5731,8 +6094,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"
@@ -5761,8 +6123,8 @@
       position.add_constraint (dim_vector (1, 4));
     }
 
-    void update_units (const caseless_str& old_units);
-    void update_fontunits (const caseless_str& old_units);
+    OCTINTERP_API void update_units (const caseless_str& old_units);
+    OCTINTERP_API void update_fontunits (const caseless_str& old_units);
 
   };
 
@@ -5796,15 +6158,20 @@
 class OCTINTERP_API uitable : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    Matrix get_boundingbox (bool internal = false,
-                            const Matrix& parent_pix_size = Matrix ()) const;
-
-    double get___fontsize_points__ (double box_pix_height = 0) const;
-
-    double get_fontsize_pixels (double box_pix_height = 0) const;
+
+    OCTINTERP_API Matrix
+    get_boundingbox (bool internal = false,
+                     const Matrix& parent_pix_size = Matrix ()) const;
+
+    OCTINTERP_API double
+    get___fontsize_points__ (double box_pix_height = 0) const;
+
+    OCTINTERP_API double
+    get_fontsize_pixels (double box_pix_height = 0) const;
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -5825,8 +6192,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"
@@ -5842,11 +6208,11 @@
       radio_property units S , "normalized|inches|centimeters|points|{pixels}|characters"
     END_PROPERTIES
 
-    Matrix get_extent_matrix (void) const;
-
-    Matrix get_backgroundcolor_rgb (void);
-
-    Matrix get_alternatebackgroundcolor_rgb (void);
+    OCTINTERP_API Matrix get_extent_matrix (void) const;
+
+    OCTINTERP_API Matrix get_backgroundcolor_rgb (void);
+
+    OCTINTERP_API Matrix get_alternatebackgroundcolor_rgb (void);
 
   protected:
     void init (void)
@@ -5858,8 +6224,8 @@
       columneditable.add_constraint ("logical");
     }
 
-    void update_units (const caseless_str& old_units);
-    void update_fontunits (const caseless_str& old_units);
+    OCTINTERP_API void update_units (const caseless_str& old_units);
+    OCTINTERP_API void update_fontunits (const caseless_str& old_units);
     void update_table_extent (void) { };
     void update_data (void) { update_table_extent (); }
     void update_fontname (void) { update_table_extent (); }
@@ -5867,11 +6233,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 (); }
   };
@@ -5906,9 +6267,11 @@
 class OCTINTERP_API uitoolbar : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
+
     // See the genprops.awk script for an explanation of the
     // properties declarations.
     // Programming note: Keep property list sorted if new ones are added.
@@ -5970,7 +6333,7 @@
     return retval;
   }
 
-  octave_value get_default (const caseless_str& name) const;
+  OCTINTERP_API octave_value get_default (const caseless_str& name) const;
 
   octave_value get_defaults (void) const
   {
@@ -5988,7 +6351,7 @@
 
   bool valid_object (void) const { return true; }
 
-  void reset_default_properties (void);
+  OCTINTERP_API void reset_default_properties (void);
 
   bool has_readonly_property (const caseless_str& pname) const
   {
@@ -6007,9 +6370,11 @@
 class OCTINTERP_API uipushtool : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
+
     // See the genprops.awk script for an explanation of the
     // properties declarations.
     // Programming note: Keep property list sorted if new ones are added.
@@ -6068,9 +6433,11 @@
 class OCTINTERP_API uitoggletool : public base_graphics_object
 {
 public:
+
   class OCTINTERP_API properties : public base_properties
   {
   public:
+
     // See the genprops.awk script for an explanation of the
     // properties declarations.
     // Programming note: Keep property list sorted if new ones are added.
@@ -6129,10 +6496,10 @@
 
 // ---------------------------------------------------------------------
 
-octave_value
+OCTINTERP_API octave_value
 get_property_from_handle (double handle, const std::string& property,
                           const std::string& func);
-bool
+OCTINTERP_API bool
 set_property_in_handle (double handle, const std::string& property,
                         const octave_value& arg, const std::string& func);
 
@@ -6141,6 +6508,7 @@
 class graphics_event;
 
 class
+OCTINTERP_API
 base_graphics_event
 {
 public:
@@ -6167,6 +6535,7 @@
 };
 
 class
+OCTINTERP_API
 graphics_event
 {
 public:
@@ -6199,26 +6568,26 @@
 
   bool ok (void) const { return (rep != nullptr); }
 
-  static graphics_event
+  static OCTINTERP_API graphics_event
   create_callback_event (const graphics_handle& h,
                          const std::string& name,
                          const octave_value& data = Matrix (),
                          int busyaction = base_graphics_event::QUEUE);
 
-  static graphics_event
+  static OCTINTERP_API graphics_event
   create_callback_event (const graphics_handle& h,
                          const octave_value& cb,
                          const octave_value& data = Matrix (),
                          int busyaction = base_graphics_event::QUEUE);
 
-  static graphics_event
+  static OCTINTERP_API graphics_event
   create_mcode_event (const graphics_handle& h, const std::string& cmd,
                       int busyaction);
 
-  static graphics_event
+  static OCTINTERP_API graphics_event
   create_function_event (event_fcn fcn, void *data = nullptr);
 
-  static graphics_event
+  static OCTINTERP_API graphics_event
   create_set_event (const graphics_handle& h, const std::string& name,
                     const octave_value& value, bool notify_toolkit = true,
                     bool redraw_figure = false);
@@ -6231,17 +6600,17 @@
 {
 public:
 
-  gh_manager (octave::interpreter& interp);
+  OCTINTERP_API gh_manager (octave::interpreter& interp);
 
   // FIXME: eventually eliminate these static functions and access
   // gh_manager object through the interpreter.
 
-  graphics_handle get_handle (bool integer_figure_handle);
-
-  void free (const graphics_handle& h, bool from_root = false);
-
-  void renumber_figure (const graphics_handle& old_gh,
-                           const graphics_handle& new_gh);
+  OCTINTERP_API graphics_handle get_handle (bool integer_figure_handle);
+
+  OCTINTERP_API void free (const graphics_handle& h, bool from_root = false);
+
+  OCTINTERP_API void renumber_figure (const graphics_handle& old_gh,
+                                      const graphics_handle& new_gh);
 
   graphics_handle lookup (double val) const
   {
@@ -6269,18 +6638,19 @@
     return (p != m_handle_map.end ()) ? p->second : graphics_object ();
   }
 
-graphics_handle make_graphics_handle (const std::string& go_name,
-                                      const graphics_handle& p,
-                                      bool integer_figure_handle = false,
-                                      bool call_createfcn = true,
-                                      bool notify_toolkit = true);
-
-  graphics_handle make_figure_handle (double val,
-                                      bool notify_toolkit = true);
-
-  void push_figure (const graphics_handle& h);
-
-  void pop_figure (const graphics_handle& h);
+  OCTINTERP_API graphics_handle
+  make_graphics_handle (const std::string& go_name,
+                        const graphics_handle& p,
+                        bool integer_figure_handle = false,
+                        bool call_createfcn = true,
+                        bool notify_toolkit = true);
+
+  OCTINTERP_API graphics_handle
+  make_figure_handle (double val, bool notify_toolkit = true);
+
+  OCTINTERP_API void push_figure (const graphics_handle& h);
+
+  OCTINTERP_API void pop_figure (const graphics_handle& h);
 
   graphics_handle current_figure (void) const
   {
@@ -6335,7 +6705,8 @@
     return retval;
   }
 
-  void execute_listener (const graphics_handle& h, const octave_value& l);
+  OCTINTERP_API void
+  execute_listener (const graphics_handle& h, const octave_value& l);
 
   void execute_callback (const graphics_handle& h,
                          const std::string& name,
@@ -6356,21 +6727,25 @@
     execute_callback (h, cb, data);
   }
 
-  void execute_callback (const graphics_handle& h, const octave_value& cb,
-                         const octave_value& data = Matrix ());
-
-  void post_callback (const graphics_handle& h, const std::string& name,
-                      const octave_value& data = Matrix ());
-
-  void post_function (graphics_event::event_fcn fcn, void *fcn_data = nullptr);
-
-  void post_set (const graphics_handle& h, const std::string& name,
-                 const octave_value& value, bool notify_toolkit = true,
-                 bool redraw_figure = false);
-
-  int process_events (bool force = false);
-
-  void enable_event_processing (bool enable = true);
+  OCTINTERP_API void
+  execute_callback (const graphics_handle& h, const octave_value& cb,
+                    const octave_value& data = Matrix ());
+
+  OCTINTERP_API void
+  post_callback (const graphics_handle& h, const std::string& name,
+                 const octave_value& data = Matrix ());
+
+  OCTINTERP_API void
+  post_function (graphics_event::event_fcn fcn, void *fcn_data = nullptr);
+
+  OCTINTERP_API void
+  post_set (const graphics_handle& h, const std::string& name,
+            const octave_value& value, bool notify_toolkit = true,
+            bool redraw_figure = false);
+
+  OCTINTERP_API int process_events (bool force = false);
+
+  OCTINTERP_API void enable_event_processing (bool enable = true);
 
   bool is_handle_visible (const graphics_handle& h) const
   {
@@ -6384,11 +6759,11 @@
     return retval;
   }
 
-  void close_all_figures (void);
-
-  void restore_gcbo (void);
-
-  void post_event (const graphics_event& e);
+  OCTINTERP_API void close_all_figures (void);
+
+  OCTINTERP_API void restore_gcbo (void);
+
+  OCTINTERP_API void post_event (const graphics_event& e);
 
   octave::mutex graphics_lock (void)
   {
@@ -6435,9 +6810,10 @@
   int m_event_processing;
 };
 
-void get_children_limits (double& min_val, double& max_val,
-                          double& min_pos, double& max_neg,
-                          const Matrix& kids, char limit_type);
+OCTINTERP_API void
+get_children_limits (double& min_val, double& max_val,
+                     double& min_pos, double& max_neg,
+                     const Matrix& kids, char limit_type);
 
 OCTINTERP_API int calc_dimensions (const graphics_object& gh);
 
--- a/libinterp/corefcn/gsvd.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/gsvd.cc	Sun May 16 09:44:35 2021 +0200
@@ -319,7 +319,7 @@
 %! B = B0;
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 3);  D1(1:3, 1:3) = C;
+%! D1 = zeros (5, 3);  D1(1:3, 1:3) = C;
 %! D2 = S;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
@@ -329,7 +329,7 @@
 %!test <48807>
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 2);  D1(1:2, 1:2) = C;
+%! D1 = zeros (5, 2);  D1(1:2, 1:2) = C;
 %! D2 = [S; zeros(1, 2)];
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*[zeros(2, 1) R]) <= 1e-6);
@@ -351,8 +351,8 @@
 %!test <48807>
 %! B(2, 2) = 0;
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(3, 5); D1(1, 1) = 1; D1(2:3, 2:3) = C;
-%! D2 = zeros(5, 5); D2(1:2, 2:3) = S; D2(3:4, 4:5) = eye (2);
+%! D1 = zeros (3, 5); D1(1, 1) = 1; D1(2:3, 2:3) = C;
+%! D2 = zeros (5, 5); D2(1:2, 2:3) = S; D2(3:4, 4:5) = eye (2);
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
 %! assert (norm ((V'*B*X) - D2*R) <= 1e-6);
@@ -374,7 +374,7 @@
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S, R]=gsvd (A, B);
-%! D1 = zeros(3, 4); D1(1:3, 1:3) = C;
+%! D1 = zeros (3, 4); D1(1:3, 1:3) = C;
 %! D2 = eye (4); D2(1:3, 1:3) = S; D2(5,:) = 0;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*[zeros(4, 1) R]) <= 1e-6);
@@ -387,7 +387,7 @@
 %! A = A0;
 %! B = B0;
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 3);  D1(1:3, 1:3) = C;
+%! D1 = zeros (5, 3);  D1(1:3, 1:3) = C;
 %! D2 = S;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
@@ -397,7 +397,7 @@
 %!test <48807>
 %! B(2, 2) = 0;
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 3);  D1(1, 1) = 1;  D1(2:3, 2:3) = C;
+%! D1 = zeros (5, 3);  D1(1, 1) = 1;  D1(2:3, 2:3) = C;
 %! D2 = [zeros(2, 1) S; zeros(1, 3)];
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
@@ -408,7 +408,7 @@
 %! B = B0;
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 3);  D1(1:3, 1:3) = C;
+%! D1 = zeros (5, 3);  D1(1:3, 1:3) = C;
 %! D2 = S;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
@@ -418,7 +418,7 @@
 %!test <48807>
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(5, 2);  D1(1:2, 1:2) = C;
+%! D1 = zeros (5, 2);  D1(1:2, 1:2) = C;
 %! D2 = [S; zeros(1, 2)];
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*[zeros(2, 1) R]) <= 1e-6);
@@ -441,8 +441,8 @@
 %!test <48807>
 %! B(2, 2) = 0;
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(3, 5);  D1(1, 1) = 1;  D1(2:3, 2:3) = C;
-%! D2 = zeros(5,5);  D2(1:2, 2:3) = S;  D2(3:4, 4:5) = eye (2);
+%! D1 = zeros (3, 5);  D1(1, 1) = 1;  D1(2:3, 2:3) = C;
+%! D2 = zeros (5,5);  D2(1:2, 2:3) = S;  D2(3:4, 4:5) = eye (2);
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (2, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
 %! assert (norm ((V'*B*X) - D2*R) <= 1e-6);
@@ -452,8 +452,8 @@
 %! B = B0;
 %! A(3, :) = 2*A(1, :) - A(2, :);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(3, 5);  D1(1:3, 1:3) = C;
-%! D2 = zeros(5,5);  D2(1:3, 1:3) = S;  D2(4:5, 4:5) = eye (2);
+%! D1 = zeros (3, 5);  D1(1:3, 1:3) = C;
+%! D2 = zeros (5,5);  D2(1:3, 1:3) = S;  D2(4:5, 4:5) = eye (2);
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*R) <= 1e-6);
 %! assert (norm ((V'*B*X) - D2*R) <= 1e-6);
@@ -465,7 +465,7 @@
 %! A(:, 3) = 2*A(:, 1) - A(:, 2);
 %! B(:, 3) = 2*B(:, 1) - B(:, 2);
 %! [U, V, X, C, S, R] = gsvd (A, B);
-%! D1 = zeros(3, 4);  D1(1:3, 1:3) = C;
+%! D1 = zeros (3, 4);  D1(1:3, 1:3) = C;
 %! D2 = eye (4);  D2(1:3, 1:3) = S;  D2(5,:) = 0;
 %! assert (norm (diag (C).^2 + diag (S).^2 - ones (3, 1)) <= 1e-6);
 %! assert (norm ((U'*A*X) - D1*[zeros(4, 1) R]) <= 1e-6);
--- a/libinterp/corefcn/gtk-manager.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/gtk-manager.h	Sun May 16 09:44:35 2021 +0200
@@ -37,7 +37,7 @@
 
 namespace octave
 {
-  class gtk_manager
+  class OCTINTERP_API gtk_manager
   {
   public:
 
--- a/libinterp/corefcn/hook-fcn.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/hook-fcn.cc	Sun May 16 09:44:35 2021 +0200
@@ -30,39 +30,41 @@
 #include "hook-fcn.h"
 #include "parse.h"
 
-hook_function::hook_function (const octave_value& f, const octave_value& d)
-{
-  if (f.is_string ())
-    {
-      std::string name = f.string_value ();
-
-      rep = new named_hook_function (name, d);
-    }
-  else if (f.is_function_handle ())
-    {
-      rep = new fcn_handle_hook_function (f, d);
-    }
-  else
-    error ("invalid hook function");
-}
-
-void named_hook_function::eval (const octave_value_list& initial_args)
+namespace octave
 {
-  octave_value_list args = initial_args;
+  hook_function::hook_function (const octave_value& f, const octave_value& d)
+  {
+    if (f.is_string ())
+      {
+        std::string name = f.string_value ();
 
-  if (data.is_defined ())
-    args.append (data);
-
-  octave::feval (name, args, 0);
-}
+        m_rep = std::shared_ptr<base_hook_function> (new named_hook_function (name, d));
+      }
+    else if (f.is_function_handle ())
+      {
+        m_rep = std::shared_ptr<base_hook_function> (new fcn_handle_hook_function (f, d));
+      }
+    else
+      error ("invalid hook function");
+  }
 
-void fcn_handle_hook_function::eval (const octave_value_list& initial_args)
-{
-  octave_value_list args = initial_args;
+  void named_hook_function::eval (const octave_value_list& initial_args)
+  {
+    octave_value_list args = initial_args;
+
+    if (m_data.is_defined ())
+      args.append (m_data);
+
+    octave::feval (m_name, args, 0);
+  }
 
-  if (data.is_defined ())
-    args.append (data);
+  void fcn_handle_hook_function::eval (const octave_value_list& initial_args)
+  {
+    octave_value_list args = initial_args;
 
-  octave::feval (fcn_handle, args, 0);
+    if (m_data.is_defined ())
+      args.append (m_data);
+
+    octave::feval (m_fcn_handle, args, 0);
+  }
 }
-
--- a/libinterp/corefcn/hook-fcn.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/hook-fcn.h	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,7 @@
 
 #include "octave-config.h"
 
+#include <memory>
 #include <string>
 
 #include "ovl.h"
@@ -35,216 +36,196 @@
 #include "ov-fcn-handle.h"
 #include "variables.h"
 
-class
-base_hook_function
+namespace octave
 {
-public:
-
-  friend class hook_function;
-
-  base_hook_function (void) : count (1) { }
-
-  base_hook_function (const base_hook_function&) : count (1) { }
+  class base_hook_function
+  {
+  public:
 
-  virtual ~base_hook_function (void) = default;
-
-  virtual std::string id (void) const { return ""; }
-
-  virtual bool is_valid (void) const { return false; }
+    base_hook_function (void) = default;
 
-  virtual void eval (const octave_value_list&) { }
-
-protected:
-
-  std::size_t count;
-};
+    base_hook_function (const base_hook_function&) = default;
 
-class
-hook_function
-{
-public:
+    virtual ~base_hook_function (void) = default;
 
-  hook_function (void)
-  {
-    static base_hook_function nil_rep;
-    rep = &nil_rep;
-    rep->count++;
-  }
+    virtual std::string id (void) const { return ""; }
 
-  hook_function (const octave_value& f,
-                 const octave_value& d = octave_value ());
+    virtual bool is_valid (void) const { return false; }
 
-  ~hook_function (void)
-  {
-    if (--rep->count == 0)
-      delete rep;
-  }
+    virtual void eval (const octave_value_list&) { }
+  };
 
-  hook_function (const hook_function& hf)
-    : rep (hf.rep)
-  {
-    rep->count++;
-  }
-
-  hook_function& operator = (const hook_function& hf)
+  class hook_function
   {
-    if (rep != hf.rep)
-      {
-        if (--rep->count == 0)
-          delete rep;
+  public:
+
+    hook_function (void)
+    {
+      static std::shared_ptr<base_hook_function>
+        nil_rep (new base_hook_function ());
 
-        rep = hf.rep;
-        rep->count++;
-      }
+      m_rep = nil_rep;
+    }
 
-    return *this;
-  }
+    hook_function (const octave_value& f,
+                   const octave_value& d = octave_value ());
+
+    ~hook_function (void) = default;
+
+    hook_function (const hook_function& hf) = default;
 
-  std::string id (void) const { return rep->id (); }
+    hook_function& operator = (const hook_function& hf) = default;
+
+    std::string id (void) const { return m_rep->id (); }
+
+    bool is_valid (void) const { return m_rep->is_valid (); }
 
-  bool is_valid (void) const { return rep->is_valid (); }
+    void eval (const octave_value_list& initial_args)
+    {
+      m_rep->eval (initial_args);
+    }
 
-  void eval (const octave_value_list& initial_args)
+  private:
+
+    std::shared_ptr<base_hook_function> m_rep;
+  };
+
+  class named_hook_function : public base_hook_function
   {
-    rep->eval (initial_args);
-  }
-
-private:
-
-  base_hook_function *rep;
-};
+  public:
 
-class
-named_hook_function : public base_hook_function
-{
-public:
+    named_hook_function (const std::string& n, const octave_value& d)
+      : m_name (n), m_data (d)
+    { }
+
+    void eval (const octave_value_list& initial_args);
+
+    std::string id (void) const { return m_name; }
 
-  named_hook_function (const std::string& n, const octave_value& d)
-    : name (n), data (d)
-  { }
+    bool is_valid (void) const { return is_valid_function (m_name); }
+
+  private:
 
-  void eval (const octave_value_list& initial_args);
+    std::string m_name;
 
-  std::string id (void) const { return name; }
+    octave_value m_data;
+  };
 
-  bool is_valid (void) const { return is_valid_function (name); }
+  class fcn_handle_hook_function : public base_hook_function
+  {
+  public:
 
-private:
-
-  std::string name;
+    fcn_handle_hook_function (const octave_value& fh_arg, const octave_value& d)
+      : m_ident (), m_valid (false), m_fcn_handle (fh_arg), m_data (d)
+    {
+      octave_fcn_handle *fh = m_fcn_handle.fcn_handle_value (true);
 
-  octave_value data;
-};
+      if (fh)
+        {
+          m_valid = true;
 
-class
-fcn_handle_hook_function : public base_hook_function
-{
-public:
+          std::ostringstream buf;
+          buf << fh;
+          m_ident = fh->fcn_name () + ':' + buf.str ();
+        }
+    }
+
+    void eval (const octave_value_list& initial_args);
 
-  fcn_handle_hook_function (const octave_value& fh_arg, const octave_value& d)
-    : ident (), valid (false), fcn_handle (fh_arg), data (d)
-  {
-    octave_fcn_handle *fh = fcn_handle.fcn_handle_value (true);
+    std::string id (void) const { return m_ident; }
 
-    if (fh)
-      {
-        valid = true;
+    bool is_valid (void) const { return m_valid; }
 
-        std::ostringstream buf;
-        buf << fh;
-        ident = fh->fcn_name () + ':' + buf.str ();
-      }
-  }
-
-  void eval (const octave_value_list& initial_args);
+  private:
 
-  std::string id (void) const { return ident; }
-
-  bool is_valid (void) const { return valid; }
-
-private:
-
-  std::string ident;
+    std::string m_ident;
 
-  bool valid;
-
-  octave_value fcn_handle;
+    bool m_valid;
 
-  octave_value data;
-};
-
-class
-hook_function_list
-{
-public:
+    octave_value m_fcn_handle;
 
-  typedef std::map<std::string, hook_function> map_type;
-
-  typedef map_type::iterator iterator;
-  typedef map_type::const_iterator const_iterator;
-
-  hook_function_list (void) : fcn_map () { }
+    octave_value m_data;
+  };
 
-  ~hook_function_list (void) = default;
-
-  hook_function_list (const hook_function_list& lst)
-    : fcn_map (lst.fcn_map)
-  { }
-
-  hook_function_list& operator = (const hook_function_list& lst)
+  class hook_function_list
   {
-    if (&lst != this)
-      fcn_map = lst.fcn_map;
+  public:
+
+    typedef std::map<std::string, hook_function> map_type;
+
+    typedef map_type::iterator iterator;
+    typedef map_type::const_iterator const_iterator;
+
+    hook_function_list (void) = default;
 
-    return *this;
-  }
+    ~hook_function_list (void) = default;
+
+    hook_function_list (const hook_function_list& lst) = default;
 
-  bool empty (void) const { return fcn_map.empty (); }
+    hook_function_list& operator = (const hook_function_list& lst) = default;
 
-  void clear (void) { fcn_map.clear (); }
+    bool empty (void) const { return m_fcn_map.empty (); }
+
+    void clear (void) { m_fcn_map.clear (); }
 
-  void insert (const std::string& id, const hook_function& f)
-  {
-    fcn_map[id] = f;
-  }
+    void insert (const std::string& id, const hook_function& f)
+    {
+      m_fcn_map[id] = f;
+    }
 
-  iterator find (const std::string& id)
-  {
-    return fcn_map.find (id);
-  }
+    iterator find (const std::string& id)
+    {
+      return m_fcn_map.find (id);
+    }
 
-  const_iterator find (const std::string& id) const
-  {
-    return fcn_map.find (id);
-  }
+    const_iterator find (const std::string& id) const
+    {
+      return m_fcn_map.find (id);
+    }
 
-  iterator end (void) { return fcn_map.end (); }
+    iterator end (void) { return m_fcn_map.end (); }
+
+    const_iterator end (void) const { return m_fcn_map.end (); }
 
-  const_iterator end (void) const { return fcn_map.end (); }
+    void erase (iterator p) { m_fcn_map.erase (p); }
 
-  void erase (iterator p) { fcn_map.erase (p); }
+    void run (const octave_value_list& initial_args = octave_value_list ())
+    {
+      auto p = m_fcn_map.begin ();
 
-  void run (const octave_value_list& initial_args = octave_value_list ())
-  {
-    auto p = fcn_map.begin ();
+      while (p != m_fcn_map.end ())
+        {
+          std::string hook_fcn_id = p->first;
+          hook_function hook_fcn = p->second;
+
+          auto q = p++;
 
-    while (p != fcn_map.end ())
-      {
-        std::string hook_fcn_id = p->first;
-        hook_function hook_fcn = p->second;
+          if (hook_fcn.is_valid ())
+            hook_fcn.eval (initial_args);
+          else
+            m_fcn_map.erase (q);
+        }
+    }
 
-        auto q = p++;
+  private:
+
+    map_type m_fcn_map;
+  };
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::base_hook_function' instead")
+typedef octave::base_hook_function base_hook_function;
 
-        if (hook_fcn.is_valid ())
-          hook_fcn.eval (initial_args);
-        else
-          fcn_map.erase (q);
-      }
-  }
+OCTAVE_DEPRECATED (7, "use 'octave::hook_function' instead")
+typedef octave::hook_function hook_function;
+
+OCTAVE_DEPRECATED (7, "use 'octave::named_hook_function' instead")
+typedef octave::named_hook_function named_hook_function;
 
-private:
+OCTAVE_DEPRECATED (7, "use 'octave::fcn_handle_hook_function' instead")
+typedef octave::fcn_handle_hook_function fcn_handle_hook_function;
 
-  map_type fcn_map;
-};
+OCTAVE_DEPRECATED (7, "use 'octave::hook_function_list' instead")
+typedef octave::hook_function_list hook_function_list;
 
 #endif
--- a/libinterp/corefcn/input.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/input.cc	Sun May 16 09:44:35 2021 +0200
@@ -194,8 +194,8 @@
 
             unwind_protect frame;
 
-            frame.add_method (es, &error_system::set_discard_warning_messages,
-                              es.discard_warning_messages ());
+            frame.add (&error_system::set_discard_warning_messages, &es,
+                       es.discard_warning_messages ());
 
             es.discard_warning_messages (true);
 
@@ -411,7 +411,7 @@
   input_system::input_system (interpreter& interp)
     : m_interpreter (interp), m_PS1 (R"(octave:\#> )"), m_PS2 ("> "),
       m_completion_append_char (' '), m_gud_mode (false),
-      m_mfile_encoding ("system"), m_auto_repeat_debug_command (true),
+      m_mfile_encoding ("utf-8"), m_auto_repeat_debug_command (true),
       m_last_debugging_command ("\n"), m_input_event_hook_functions (),
       m_initialized (false)
   { }
@@ -526,7 +526,7 @@
                   error ("__mfile_encoding__: conversion from encoding '%s' "
                          "not supported", encoding.c_str ());
                 else
-                  error ("__mfile_encoding__: error %d opening encoding '%s'.",
+                  error ("__mfile_encoding__: error %d opening encoding '%s'",
                          errno, encoding.c_str ());
               }
             else
@@ -542,6 +542,92 @@
     return retval;
   }
 
+  // Get part of the directory that would be added to the load path
+  static std::string load_path_dir (const std::string& dir)
+  {
+    std::string lp_dir = dir;
+
+    // strip trailing filesep
+    std::size_t ipos = lp_dir.find_last_not_of (sys::file_ops::dir_sep_chars ());
+    if (ipos != std::string::npos)
+      lp_dir = lp_dir.erase (ipos+1);
+
+    // strip trailing private folder
+    ipos = lp_dir.find_last_of (sys::file_ops::dir_sep_chars ());
+    if (ipos != std::string::npos
+        && lp_dir.substr (ipos+1).compare ("private") == 0)
+      {
+        lp_dir = lp_dir.erase (ipos);
+        ipos = lp_dir.find_last_of (sys::file_ops::dir_sep_chars ());
+      }
+
+    // strip trailing @class folder
+    if (ipos != std::string::npos && lp_dir[ipos+1] == '@')
+      {
+        lp_dir = lp_dir.erase (ipos);
+        ipos = lp_dir.find_last_of (sys::file_ops::dir_sep_chars ());
+      }
+
+    // strip (nested) +namespace folders
+    while (ipos != std::string::npos && lp_dir[ipos+1] == '+')
+      {
+        lp_dir = lp_dir.erase (ipos);
+        ipos = lp_dir.find_last_of (sys::file_ops::dir_sep_chars ());
+      }
+
+    return lp_dir;
+  }
+
+  std::string input_system::dir_encoding (const std::string& dir)
+  {
+    std::string enc = m_mfile_encoding;
+
+    auto enc_it = m_dir_encoding.find (load_path_dir (dir));
+    if (enc_it != m_dir_encoding.end ())
+      enc = enc_it->second;
+
+    return enc;
+  }
+
+  void input_system::set_dir_encoding (const std::string& dir,
+                                       std::string& enc)
+  {
+    // use lower case
+    std::transform (enc.begin (), enc.end (), enc.begin (), ::tolower);
+
+    if (enc.compare ("delete") == 0)
+      {
+        // Remove path from map
+        m_dir_encoding.erase (load_path_dir (dir));
+        return;
+      }
+    else if (enc.compare ("utf-8"))
+      {
+        // Check for valid encoding name.
+        // FIXME: This will probably not happen very often and opening the
+        //        encoder doesn't take long.
+        //        Should we cache working encoding identifiers anyway?
+        void *codec
+          = octave_iconv_open_wrapper (enc.c_str (), "utf-8");
+
+        if (codec == reinterpret_cast<void *> (-1))
+          {
+            if (errno == EINVAL)
+              error ("dir_encoding: conversion from encoding '%s' "
+                     "not supported", enc.c_str ());
+            else
+              error ("dir_encoding: error %d opening encoding '%s'.",
+                     errno, enc.c_str ());
+          }
+        else
+          octave_iconv_close_wrapper (codec);
+      }
+
+    m_dir_encoding[load_path_dir (dir)] = enc;
+
+    return;
+   }
+
   octave_value
   input_system::auto_repeat_debug_command (const octave_value_list& args,
                                            int nargout)
@@ -581,11 +667,11 @@
           {
             Fdrawnow (m_interpreter);
           }
-        catch (const execution_exception& e)
+        catch (const execution_exception& ee)
           {
             eval_error = true;
 
-            m_interpreter.handle_exception (e);
+            m_interpreter.handle_exception (ee);
           }
 
         flush_stdout ();
@@ -820,7 +906,14 @@
   public:
 
     file_reader (interpreter& interp, FILE *f_arg)
-      : base_reader (interp), m_file (f_arg) { }
+      : base_reader (interp), m_file (f_arg)
+    {
+      octave::input_system& input_sys = interp.get_input_system ();
+      m_encoding = input_sys.mfile_encoding ();
+    }
+
+    file_reader (interpreter& interp, FILE *f_arg, const std::string& enc)
+      : base_reader (interp), m_file (f_arg), m_encoding (enc) { }
 
     std::string get_input (const std::string& prompt, bool& eof);
 
@@ -832,6 +925,8 @@
 
     FILE *m_file;
 
+    std::string m_encoding;
+
     static const std::string s_in_src;
   };
 
@@ -865,6 +960,10 @@
     : m_rep (new file_reader (interp, file))
   { }
 
+  input_reader::input_reader (interpreter& interp, FILE *file, const std::string& enc)
+    : m_rep (new file_reader (interp, file, enc))
+  { }
+
   input_reader::input_reader (interpreter& interp, const std::string& str)
     : m_rep (new eval_string_reader (interp, str))
   { }
@@ -948,9 +1047,15 @@
 
     std::string src_str = octave_fgets (m_file, eof);
 
-    input_system& input_sys = m_interpreter.get_input_system ();
+    std::string mfile_encoding;
 
-    std::string mfile_encoding = input_sys.mfile_encoding ();
+    if (m_encoding.empty ())
+      {
+        input_system& input_sys = m_interpreter.get_input_system ();
+        mfile_encoding = input_sys.mfile_encoding ();
+      }
+    else
+      mfile_encoding = m_encoding;
 
     std::string encoding;
     if (mfile_encoding.compare ("system") == 0)
@@ -992,8 +1097,7 @@
                  "converting from codepage '%s' to UTF-8: %s",
                  encoding.c_str (), std::strerror (errno));
 
-        unwind_protect frame;
-        frame.add_fcn (::free, static_cast<void *> (utf8_str));
+        unwind_action free_utf8_str ([=] () { ::free (utf8_str); });
 
         src_str = std::string (reinterpret_cast<char *> (utf8_str), length);
       }
@@ -1305,7 +1409,7 @@
 
   octave::input_system& input_sys = interp.get_input_system ();
 
-  hook_function hook_fcn (args(0), user_data);
+  octave::hook_function hook_fcn (args(0), user_data);
 
   input_sys.add_input_event_hook (hook_fcn);
 
@@ -1350,11 +1454,11 @@
 When executing interactively, Octave displays the primary prompt when it is
 ready to read a command.
 
-The default value of the primary prompt string is @qcode{'octave:\#> '}.
-To change it, use a command like
+The default value of the primary prompt string is
+@qcode{'octave:@backslashchar{}#> '}.  To change it, use a command like
 
 @example
-PS1 ("\\u@@\\H> ")
+PS1 ('\u@@\H> ')
 @end example
 
 @noindent
@@ -1470,6 +1574,73 @@
   return input_sys.mfile_encoding (args, nargout);
 }
 
+DEFMETHOD (dir_encoding, interp, args, nargout,
+           doc: /* -*- texinfo -*-
+@deftypefn {}  {@var{current_encoding} =} dir_encoding (@var{dir})
+@deftypefnx {} {@var{prev_encoding} =} dir_encoding (@var{dir}, @var{encoding})
+@deftypefnx {} {} dir_encoding (@dots{})
+Set and query the @var{encoding} that is used for reading m-files in @var{dir}.
+
+That encoding overrides the (globally set) m-file encoding.
+
+The string @var{DIR} must match the form how the directory would appear in the
+load path.
+
+The @var{encoding} must be a valid encoding identifier or @code{"delete"}.  In
+the latter case, the (globally set) m-file encoding will be used for the given
+@var{dir}.
+
+The currently or previously used encoding is returned in @var{current_encoding}
+or @var{prev_encoding}, respectively.  The output argument must be explicitly
+requested.
+
+The directory encoding is automatically read from the file @file{.oct-config}
+when a new path is added to the load path (for example with @code{addpath}).
+To set the encoding for all files in the same folder, that file must contain
+a line starting with @code{"encoding="} followed by the encoding identifier.
+
+For example to set the file encoding for all files in the same folder to
+ISO 8859-1 (Latin-1), create a file @file{.oct-config} with the following
+content:
+
+@example
+encoding=iso8859-1
+@end example
+
+If the file encoding is changed after the files have already been parsed, the
+files have to be parsed again for that change to take effect.  That can be done
+with the command @code{clear all}.
+
+@seealso{addpath, path}
+@end deftypefn */)
+{
+  int nargin = args.length ();
+
+  if (nargin < 1 || nargin > 2)
+    print_usage ();
+
+  std::string dir
+    = args(0).xstring_value ("dir_encoding: DIR must be a string");
+
+  octave_value retval;
+
+  octave::input_system& input_sys = interp.get_input_system ();
+
+  if (nargout > 0)
+    retval = input_sys.dir_encoding (dir);
+
+  if (nargin > 1)
+    {
+      std::string encoding
+        = args(1).xstring_value ("dir_encoding: ENCODING must be a string");
+
+      input_sys.set_dir_encoding (dir, encoding);
+    }
+
+  return ovl (retval);
+
+}
+
 DEFMETHOD (auto_repeat_debug_command, interp, args, nargout,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} auto_repeat_debug_command ()
@@ -1488,40 +1659,3 @@
 
   return input_sys.auto_repeat_debug_command (args, nargout);
 }
-
-// Always define these functions.  The macro is intended to allow the
-// declarations to be hidden, not so that Octave will not provide the
-// functions if they are requested.
-
-// #if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-bool
-octave_yes_or_no (const std::string& prompt)
-{
-  octave::input_system& input_sys
-    = octave::__get_input_system__ ("set_default_prompts");
-
-  return input_sys.yes_or_no (prompt);
-}
-
-void
-remove_input_event_hook_functions (void)
-{
-  octave::input_system& input_sys
-    = octave::__get_input_system__ ("remove_input_event_hook_functions");
-
-  input_sys.clear_input_event_hooks ();
-}
-
-// Fix things up so that input can come from the standard input.  This
-// may need to become much more complicated, which is why it's in a
-// separate function.
-
-FILE *
-get_input_from_stdin (void)
-{
-  octave::command_editor::set_input_stream (stdin);
-  return octave::command_editor::get_input_stream ();
-}
-
-// #endif
--- a/libinterp/corefcn/input.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/input.h	Sun May 16 09:44:35 2021 +0200
@@ -34,6 +34,7 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 
 #include "hook-fcn.h"
 #include "oct-time.h"
@@ -50,7 +51,7 @@
 OCTAVE_DEPRECATED (6, "'Vtrack_line_num' is an obsolete internal variable; any uses should be removed")
 extern OCTINTERP_API bool Vtrack_line_num;
 
-extern octave::sys::time Vlast_prompt_time;
+extern OCTINTERP_API octave::sys::time Vlast_prompt_time;
 
 class octave_value;
 
@@ -147,6 +148,10 @@
 
     void set_mfile_encoding (const std::string& s) { m_mfile_encoding = s; }
 
+    std::string dir_encoding (const std::string& dir);
+
+    void set_dir_encoding (const std::string& dir, std::string& enc);
+
     octave_value
     auto_repeat_debug_command (const octave_value_list& args, int nargout);
 
@@ -199,6 +204,9 @@
     // Codepage which is used to read .m files
     std::string m_mfile_encoding;
 
+    // map of directories -> used mfile encoding
+    std::unordered_map<std::string, std::string> m_dir_encoding;
+
     // TRUE means repeat last debug command if the user just types RET.
     bool m_auto_repeat_debug_command;
 
@@ -259,6 +267,8 @@
 
     input_reader (interpreter& interp, FILE *file);
 
+    input_reader (interpreter& interp, FILE *file, const std::string& enc);
+
     input_reader (interpreter& interp, const std::string& str);
 
     input_reader (const input_reader& ir) = default;
@@ -298,17 +308,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-OCTAVE_DEPRECATED (5, "use 'octave::input_system::yes_or_no' instead")
-extern bool octave_yes_or_no (const std::string& prompt);
-
-OCTAVE_DEPRECATED (5, "use 'octave::input_system::clear_input_event_hooks' instead")
-extern void remove_input_event_hook_functions (void);
-
-OCTAVE_DEPRECATED (5, "this function will be removed in a future version of Octave")
-extern OCTINTERP_API FILE * get_input_from_stdin (void);
-
 #endif
-
-#endif
--- a/libinterp/corefcn/interpreter-private.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/interpreter-private.h	Sun May 16 09:44:35 2021 +0200
@@ -54,45 +54,45 @@
   class tree_evaluator;
   class type_info;
 
-  extern interpreter& __get_interpreter__ (const std::string& who);
+  extern OCTINTERP_API interpreter& __get_interpreter__ (const std::string& who);
 
-  extern dynamic_loader& __get_dynamic_loader__ (const std::string& who);
+  extern OCTINTERP_API dynamic_loader& __get_dynamic_loader__ (const std::string& who);
 
-  extern error_system& __get_error_system__ (const std::string& who);
+  extern OCTINTERP_API error_system& __get_error_system__ (const std::string& who);
 
-  extern gh_manager& __get_gh_manager__ (const std::string& who);
+  extern OCTINTERP_API gh_manager& __get_gh_manager__ (const std::string& who);
 
-  extern help_system& __get_help_system__ (const std::string& who);
+  extern OCTINTERP_API help_system& __get_help_system__ (const std::string& who);
 
-  extern input_system& __get_input_system__ (const std::string& who);
+  extern OCTINTERP_API input_system& __get_input_system__ (const std::string& who);
 
-  extern load_path& __get_load_path__ (const std::string& who);
+  extern OCTINTERP_API load_path& __get_load_path__ (const std::string& who);
 
-  extern load_save_system& __get_load_save_system__ (const std::string& who);
+  extern OCTINTERP_API load_save_system& __get_load_save_system__ (const std::string& who);
 
-  extern event_manager& __get_event_manager__ (const std::string& who);
+  extern OCTINTERP_API event_manager& __get_event_manager__ (const std::string& who);
 
-  extern output_system& __get_output_system__ (const std::string& who);
+  extern OCTINTERP_API output_system& __get_output_system__ (const std::string& who);
 
-  extern type_info& __get_type_info__ (const std::string& who);
+  extern OCTINTERP_API type_info& __get_type_info__ (const std::string& who);
 
-  extern symbol_table& __get_symbol_table__ (const std::string& who);
+  extern OCTINTERP_API symbol_table& __get_symbol_table__ (const std::string& who);
 
-  extern symbol_scope __get_current_scope__ (const std::string& who);
+  extern OCTINTERP_API symbol_scope __get_current_scope__ (const std::string& who);
 
-  extern symbol_scope __require_current_scope__ (const std::string& who);
+  extern OCTINTERP_API symbol_scope __require_current_scope__ (const std::string& who);
 
-  extern tree_evaluator& __get_evaluator__ (const std::string& who);
+  extern OCTINTERP_API tree_evaluator& __get_evaluator__ (const std::string& who);
 
-  extern bp_table& __get_bp_table__ (const std::string& who);
+  extern OCTINTERP_API bp_table& __get_bp_table__ (const std::string& who);
 
-  extern child_list& __get_child_list__ (const std::string& who);
+  extern OCTINTERP_API child_list& __get_child_list__ (const std::string& who);
 
-  extern cdef_manager& __get_cdef_manager__ (const std::string& who);
+  extern OCTINTERP_API cdef_manager& __get_cdef_manager__ (const std::string& who);
 
-  extern display_info& __get_display_info__ (const std::string& who);
+  extern OCTINTERP_API display_info& __get_display_info__ (const std::string& who);
 
-  extern gtk_manager& __get_gtk_manager__ (const std::string& who);
+  extern OCTINTERP_API gtk_manager& __get_gtk_manager__ (const std::string& who);
 
   // Functions that could be methods in the interpreter class but maybe
   // shouldn't be exposed as part of the public interface.
@@ -102,10 +102,12 @@
   // or the text of an inline function that has the given argument names
   // PARAMETER_NAMES.  Use of the latter form is discouraged.
 
+  OCTINTERP_API
   octave_value
   get_function_handle (interpreter& interp, const octave_value& arg,
                        const std::string& parameter_name);
 
+  OCTINTERP_API
   octave_value
   get_function_handle (interpreter& interp, const octave_value& arg,
                        const std::list<std::string>& parameter_names
--- a/libinterp/corefcn/interpreter.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/interpreter.cc	Sun May 16 09:44:35 2021 +0200
@@ -29,9 +29,10 @@
 
 #include <cstdio>
 
+#include <iostream>
 #include <set>
 #include <string>
-#include <iostream>
+#include <thread>
 
 #include "cmd-edit.h"
 #include "cmd-hist.h"
@@ -42,6 +43,7 @@
 #include "lo-blas-proto.h"
 #include "lo-error.h"
 #include "oct-env.h"
+#include "quit.h"
 #include "str-vec.h"
 #include "signal-wrappers.h"
 #include "unistd-wrappers.h"
@@ -295,6 +297,15 @@
   return retval;
 }
 
+DEFMETHOD (__traditional__, interp, , ,
+           doc: /* -*- texinfo -*-
+@deftypefn {} {} __traditional__ ()
+Undocumented internal function.
+@end deftypefn */)
+{
+  return ovl (interp.traditional ());
+}
+
 namespace octave
 {
   temporary_file_list::~temporary_file_list (void)
@@ -344,9 +355,9 @@
 
         return 1;
       }
-    catch (const execution_exception& e)
+    catch (const execution_exception& ee)
       {
-        interp.handle_exception (e);
+        interp.handle_exception (ee);
 
         return 1;
       }
@@ -463,10 +474,11 @@
       m_read_site_files (true),
       m_read_init_files (m_app_context != nullptr),
       m_verbose (false),
+      m_traditional (false),
       m_inhibit_startup_message (false),
       m_load_path_initialized (false),
       m_history_initialized (false),
-      m_in_top_level_repl (false),
+      m_interrupt_all_in_process_group (true),
       m_cancel_quit (false),
       m_executing_finish_script (false),
       m_executing_atexit (false),
@@ -513,7 +525,6 @@
       m_display_info.initialize ();
 
     bool line_editing = false;
-    bool traditional = false;
 
     if (m_app_context)
       {
@@ -565,7 +576,7 @@
             && ! options.forced_line_editing ())
           line_editing = false;
 
-        traditional = options.traditional ();
+        m_traditional = options.traditional ();
 
         // FIXME: if possible, perform the following actions directly
         // instead of using the interpreter-level functions.
@@ -625,7 +636,7 @@
     // This should be done before initializing the load path because
     // some PKG_ADD files might need --traditional behavior.
 
-    if (traditional)
+    if (m_traditional)
       maximum_braindamage ();
 
     octave_interpreter_ready = true;
@@ -697,12 +708,10 @@
         // be evaluated from the normal interpreter loop where exceptions
         // are already handled.
 
-        unwind_protect frame;
+        unwind_action restore_add_hook (&load_path::set_add_hook, &m_load_path,
+                                        m_load_path.get_add_hook ());
 
-        frame.add_method (m_load_path, &load_path::set_add_hook,
-                          m_load_path.get_add_hook ());
-
-        m_load_path.set_add_hook ([this] (const std::string& dir)
+        m_load_path.set_add_hook ([=] (const std::string& dir)
                                   { this->execute_pkg_add (dir); });
 
         m_load_path.initialize (set_initial_path);
@@ -718,7 +727,20 @@
     if (m_initialized)
       return;
 
-    display_startup_message ();
+    if (m_app_context)
+      {
+        const cmdline_options& options = m_app_context->options ();
+
+        if (options.experimental_terminal_widget ())
+          {
+            if (! options.gui ())
+              display_startup_message ();
+          }
+        else
+          display_startup_message ();
+      }
+    else
+      display_startup_message ();
 
     // Wait to read the history file until the interpreter reads input
     // files and begins evaluating commands.
@@ -750,6 +772,55 @@
     m_initialized = true;
   }
 
+  // Note: this function is currently only used with the new
+  // experimental terminal widget.
+
+  void interpreter::get_line_and_eval (void)
+  {
+    m_evaluator.get_line_and_eval ();
+  }
+
+  // Note: the following class is currently only used with the new
+  // experimental terminal widget.
+
+  class cli_input_reader
+  {
+  public:
+
+    cli_input_reader (interpreter& interp)
+      : m_interpreter (interp), m_thread () { }
+
+    cli_input_reader (const cli_input_reader&) = delete;
+
+    cli_input_reader& operator = (const cli_input_reader&) = delete;
+
+    ~cli_input_reader (void)
+    {
+      // FIXME: Would it be better to ensure that
+      // interpreter::get_line_and_eval exits and then call
+      // m_thread.join () here?
+
+      m_thread.detach ();
+    }
+
+    void start (void)
+    {
+      m_thread = std::thread (&interpreter::get_line_and_eval, &m_interpreter);
+    }
+
+  private:
+
+    interpreter& m_interpreter;
+
+    std::thread m_thread;
+  };
+
+  void interpreter::parse_and_execute (const std::string& input,
+                                       bool& incomplete_parse)
+  {
+    m_evaluator.parse_and_execute (input, incomplete_parse);
+  }
+
   // FIXME: this function is intended to be executed only once.  Should
   // we enforce that restriction?
 
@@ -796,12 +867,36 @@
             if (options.forced_interactive ())
               command_editor::blink_matching_paren (false);
 
-            exit_status = main_loop ();
+            if (options.server ())
+              exit_status = server_loop ();
+            else if (options.experimental_terminal_widget ())
+              {
+                if (options.gui ())
+                  {
+                    m_event_manager.start_gui (true);
+
+                    exit_status = server_loop ();
+                  }
+                else
+                  {
+                    // Use an object so that the thread started for the
+                    // reader will be cleaned up no matter how we exit
+                    // this function.
+
+                    cli_input_reader reader (*this);
+
+                    reader.start ();
+
+                    exit_status = server_loop ();
+                  }
+              }
+            else
+              exit_status = main_loop ();
           }
       }
-    catch (const exit_exception& ex)
+    catch (const exit_exception& xe)
       {
-        return ex.exit_status ();
+        exit_status = xe.exit_status ();
       }
 
     return exit_status;
@@ -824,14 +919,13 @@
     {                                                                   \
       try                                                               \
         {                                                               \
-          unwind_protect frame;                                         \
+          unwind_action restore_debug_on_error                          \
+            (&error_system::set_debug_on_error, &m_error_system,        \
+             m_error_system.debug_on_error ());                        \
                                                                         \
-          frame.add_method (m_error_system,                             \
-                            &error_system::set_debug_on_error,          \
-                            m_error_system.debug_on_error ());          \
-          frame.add_method (m_error_system,                             \
-                            &error_system::set_debug_on_warning,        \
-                            m_error_system.debug_on_warning ());        \
+          unwind_action restore_debug_on_warning                        \
+            (&error_system::set_debug_on_warning, &m_error_system,      \
+             m_error_system.debug_on_warning ());                       \
                                                                         \
           m_error_system.debug_on_error (false);                        \
           m_error_system.debug_on_warning (false);                      \
@@ -1039,9 +1133,9 @@
               {
                 recover_from_exception ();
               }
-            catch (const execution_exception& e)
+            catch (const execution_exception& ee)
               {
-                handle_exception (e);
+                handle_exception (ee);
               }
           }
 
@@ -1149,9 +1243,9 @@
 
         return 1;
       }
-    catch (const execution_exception& e)
+    catch (const execution_exception& ee)
       {
-        handle_exception (e);
+        handle_exception (ee);
 
         return 1;
       }
@@ -1166,23 +1260,26 @@
 
     const cmdline_options& options = m_app_context->options ();
 
-    unwind_protect frame;
-
-    frame.add_method (this, &interpreter::interactive, m_interactive);
-
     string_vector args = options.all_args ();
 
-    frame.add_method (m_app_context, &application::intern_argv, args);
+    void (interpreter::*interactive_fptr) (bool) = &interpreter::interactive;
+    unwind_action restore_interactive (interactive_fptr, this, m_interactive);
 
-    frame.add_method (this, &interpreter::intern_nargin, args.numel () - 1);
+    unwind_action restore_argv (&application::intern_argv, m_app_context, args);
+
+    unwind_action restore_nargin (&interpreter::intern_nargin, this,
+                                  args.numel () - 1);
 
-    frame.add_method (m_app_context,
-                      &application::program_invocation_name,
-                      application::program_invocation_name ());
+    void (application::*program_invocation_name_fptr) (const std::string&)
+      = &application::program_invocation_name;
+    unwind_action restore_program_invocation_name
+      (program_invocation_name_fptr, m_app_context,
+       application::program_invocation_name ());
 
-    frame.add_method (m_app_context,
-                      &application::program_name,
-                      application::program_name ());
+    void (application::*program_name_fptr) (const std::string&)
+      = &application::program_name;
+    unwind_action restore_program_name
+      (program_name_fptr, m_app_context, application::program_name ());
 
     m_interactive = false;
 
@@ -1207,132 +1304,12 @@
 
   int interpreter::main_loop (void)
   {
-    // The big loop.  Read, Eval, Print, Loop.  Normally user
-    // interaction at the command line in a terminal session, but we may
-    // also end up here when reading from a pipe or when stdin is
-    // connected to a file by the magic of input redirection.
-
-    int exit_status = 0;
-
-    // FIXME: should this choice be a command-line option?  Note that we
-    // intend that the push parser interface only be used for
-    // interactive sessions.
-
-#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
-    static bool use_command_line_push_parser = true;
-#else
-    static bool use_command_line_push_parser = false;
-#endif
-
-    // The following logic is written as it is to allow easy transition
-    // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to
-    // simplify the logic of the main loop below by using the same
-    // base_parser::run interface for both push and pull parsers.
-
-    std::shared_ptr<base_parser> repl_parser;
-
-    if (m_interactive)
-      {
-        if (use_command_line_push_parser)
-          {
-            push_parser *pp = new push_parser (*this, new input_reader (*this));
-            repl_parser = std::shared_ptr<base_parser> (pp);
-          }
-        else
-          {
-            parser *pp = new parser (new lexer (*this));
-            repl_parser = std::shared_ptr<base_parser> (pp);
-          }
-      }
-    else
-      {
-        parser *pp = new parser (new lexer (stdin, *this));
-        repl_parser = std::shared_ptr<base_parser> (pp);
-      }
-
-    do
-      {
-        try
-          {
-            unwind_protect_var<bool> upv (m_in_top_level_repl, true);
-
-            repl_parser->reset ();
-
-            if (m_evaluator.at_top_level ())
-              {
-                m_evaluator.dbstep_flag (0);
-                m_evaluator.reset_debug_state ();
-              }
-
-            exit_status = repl_parser->run ();
+    return m_evaluator.repl ();
+  }
 
-            if (exit_status == 0)
-              {
-                std::shared_ptr<tree_statement_list>
-                  stmt_list = repl_parser->statement_list ();
-
-                if (stmt_list)
-                  {
-                    command_editor::increment_current_command_number ();
-
-                    m_evaluator.eval (stmt_list, m_interactive);
-                  }
-                else if (repl_parser->at_end_of_input ())
-                  {
-                    exit_status = EOF;
-                    break;
-                  }
-              }
-          }
-        catch (const interrupt_exception&)
-          {
-            recover_from_exception ();
-
-            // Required newline when the user does Ctrl+C at the prompt.
-            if (m_interactive)
-              octave_stdout << "\n";
-          }
-        catch (const index_exception& e)
-          {
-            recover_from_exception ();
-
-            std::cerr << "error: unhandled index exception: "
-                      << e.message () << " -- trying to return to prompt"
-                      << std::endl;
-          }
-        catch (const execution_exception& ee)
-          {
-            m_error_system.save_exception (ee);
-            m_error_system.display_exception (ee, std::cerr);
-
-            if (m_interactive)
-              recover_from_exception ();
-            else
-              {
-                // We should exit with a nonzero status.
-                exit_status = 1;
-                break;
-              }
-          }
-        catch (const std::bad_alloc&)
-          {
-            recover_from_exception ();
-
-            std::cerr << "error: out of memory -- trying to return to prompt"
-                      << std::endl;
-          }
-      }
-    while (exit_status == 0);
-
-    if (exit_status == EOF)
-      {
-        if (m_interactive)
-          octave_stdout << "\n";
-
-        exit_status = 0;
-      }
-
-    return exit_status;
+  int interpreter::server_loop (void)
+  {
+    return m_evaluator.server_loop ();
   }
 
   tree_evaluator& interpreter::get_evaluator (void)
@@ -1392,6 +1369,7 @@
     // FIXME: should these actions be handled as a list of functions
     // to call so users can add their own chdir handlers?
 
+    m_load_path.read_dir_config (".");
     m_load_path.update ();
 
     m_event_manager.directory_changed (sys::env::get_current_directory ());
@@ -1814,20 +1792,119 @@
     return m_evaluator.autoloaded_functions ();
   }
 
-  void interpreter::handle_exception (const execution_exception& e)
+  // May be used to send an interrupt signal to the the interpreter from
+  // another thread (for example, the GUI).
+
+  void interpreter::interrupt (void)
+  {
+    static int sigint = 0;
+    static bool first = true;
+
+    if (first)
+      {
+        octave_get_sig_number ("SIGINT", &sigint);
+        first = false;
+      }
+
+    // Send SIGINT to Octave and (optionally) all other processes in its
+    // process group.  The signal handler for SIGINT will set a global
+    // variable indicating an interrupt has happened.  That variable is
+    // checked in many places in the Octave interpreter and eventually
+    // results in an interrupt_exception being thrown.  Finally, that
+    // exception is caught and returns control to one of the
+    // read-eval-print loops or to the server loop.  We use a signal
+    // instead of just setting the global variables here so that we will
+    // probably send interrupt signals to any subprocesses as well as
+    // interrupt execution of the interpreter.
+
+    pid_t pid
+      = m_interrupt_all_in_process_group ? 0 : octave_getpid_wrapper ();
+
+    octave_kill_wrapper (pid, sigint);
+  }
+
+  void interpreter::pause (void)
+  {
+    // FIXME: To be reliable, these tree_evaluator functions must be
+    // made thread safe.
+
+    m_evaluator.break_on_next_statement (true);
+    m_evaluator.reset_debug_state ();
+  }
+
+  void interpreter::stop (void)
   {
-    m_error_system.save_exception (e);
+    // FIXME: To be reliable, these tree_evaluator functions must be
+    // made thread safe.
+
+    if (m_evaluator.in_debug_repl ())
+      m_evaluator.dbquit (true);
+    else
+      interrupt ();
+  }
+
+  void interpreter::resume (void)
+  {
+    // FIXME: To be reliable, these tree_evaluator functions must be
+    // made thread safe.
+
+    // FIXME: Should there be any feeback about not doing anything if
+    // not in debug mode?
+
+    if (m_evaluator.in_debug_repl ())
+      m_evaluator.dbcont ();
+  }
+
+  // Provided for convenience.  Will be removed once we eliminate the
+  // old terminal widget.
+  bool interpreter::experimental_terminal_widget (void) const
+  {
+    if (! m_app_context)
+      return false;
+
+    // Embedded interpreters don't execute command line options.
+    const cmdline_options& options = m_app_context->options ();
+
+    return options.experimental_terminal_widget ();
+  }
+
+  void interpreter::add_debug_watch_expression (const std::string& expr)
+  {
+    m_evaluator.add_debug_watch_expression (expr);
+  }
+
+  void interpreter::remove_debug_watch_expression (const std::string& expr)
+  {
+    m_evaluator.remove_debug_watch_expression (expr);
+  }
+
+  void interpreter::clear_debug_watch_expressions (void)
+  {
+    m_evaluator.clear_debug_watch_expressions ();
+  }
+
+  std::set<std::string> interpreter::debug_watch_expressions (void) const
+  {
+    return m_evaluator.debug_watch_expressions ();
+  }
+
+  void interpreter::handle_exception (const execution_exception& ee)
+  {
+    m_error_system.save_exception (ee);
 
     // FIXME: use a separate stream instead of std::cerr directly so that
     // error messages can be redirected more easily?  Pass the message
     // to an event manager function?
-    m_error_system.display_exception (e, std::cerr);
+    m_error_system.display_exception (ee);
 
     recover_from_exception ();
   }
 
   void interpreter::recover_from_exception (void)
   {
+    if (octave_interrupt_state)
+      m_event_manager.interpreter_interrupted ();
+
     can_interrupt = true;
     octave_interrupt_state = 0;
     octave_signal_caught = 0;
@@ -1956,6 +2033,7 @@
     disable_warning ("Octave:abbreviated-property-match");
     disable_warning ("Octave:colon-nonscalar-argument");
     disable_warning ("Octave:data-file-in-path");
+    disable_warning ("Octave:empty-index");
     disable_warning ("Octave:function-name-clash");
     disable_warning ("Octave:possible-matlab-short-circuit-operator");
   }
@@ -1970,9 +2048,9 @@
       {
         recover_from_exception ();
       }
-    catch (const execution_exception& e)
+    catch (const execution_exception& ee)
       {
-        handle_exception (e);
+        handle_exception (ee);
       }
   }
 }
--- a/libinterp/corefcn/interpreter.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/interpreter.h	Sun May 16 09:44:35 2021 +0200
@@ -29,6 +29,7 @@
 #include "octave-config.h"
 
 #include <map>
+#include <set>
 #include <stack>
 #include <string>
 
@@ -73,6 +74,7 @@
 {
   class profiler;
   class child_list;
+  class push_parser;
 
   // The time we last time we changed directories.
   extern sys::time Vlast_chdir_time;
@@ -147,6 +149,17 @@
 
     void initialize (void);
 
+    // Note: GET_LINE_AND_EVAL is only used by new experimental terminal
+    // widget.
+
+    void get_line_and_eval (void);
+
+    // Parse a line of input.  If input ends at a complete statement
+    // boundary, execute the resulting parse tree.  Useful to handle
+    // parsing user input when running in server mode.
+
+    void parse_and_execute (const std::string& input, bool& incomplete_parse);
+
     // Initialize the interpreter (if not already done by an explicit
     // call to initialize), execute startup files, --eval option code,
     // script files, and/or interactive commands.
@@ -155,6 +168,8 @@
 
     void shutdown (void);
 
+    bool server_mode (void) const { return m_evaluator.server_mode (); }
+
     bool interactive (void) const
     {
       return m_interactive;
@@ -180,6 +195,16 @@
       m_verbose = flag;
     }
 
+    void traditional (bool flag)
+    {
+      m_traditional = flag;
+    }
+
+    bool traditional (void) const
+    {
+      return m_traditional;
+    }
+
     void inhibit_startup_message (bool flag)
     {
       m_inhibit_startup_message = flag;
@@ -187,7 +212,7 @@
 
     bool in_top_level_repl (void) const
     {
-      return m_in_top_level_repl;
+      return m_evaluator.in_top_level_repl ();
     }
 
     bool initialized (void) const
@@ -195,6 +220,21 @@
       return m_initialized;
     }
 
+    void interrupt_all_in_process_group (bool b)
+    {
+      m_interrupt_all_in_process_group = b;
+    }
+
+    bool interrupt_all_in_process_group (void) const
+    {
+      return m_interrupt_all_in_process_group;
+    }
+
+    application *get_app_context (void)
+    {
+      return m_app_context;
+    }
+
     display_info& get_display_info (void)
     {
       return m_display_info;
@@ -444,7 +484,40 @@
 
     std::list<std::string> autoloaded_functions (void) const;
 
-    void handle_exception (const execution_exception& e);
+    void interrupt (void);
+
+    // Pause interpreter execution at the next available statement and
+    // enter the debugger.
+    void pause (void);
+
+    // Exit debugger or stop execution and return to the top-level REPL
+    // or server loop.
+    void stop (void);
+
+    // Add EXPR to the set of expressions that may be evaluated when the
+    // debugger stops at a breakpoint.
+    void add_debug_watch_expression (const std::string& expr);
+
+    // Remove EXPR from the set of expressions that may be evaluated
+    // when the debugger stops at a breakpoint.
+    void remove_debug_watch_expression (const std::string& expr);
+
+    // Clear the set of expressions that may be evaluated when the
+    // debugger stops at a breakpoint.
+    void clear_debug_watch_expressions (void);
+
+    // Return the set of expressions that may be evaluated when the
+    // debugger stops at a breakpoint.
+    std::set<std::string> debug_watch_expressions (void) const;
+
+    // Resume interpreter execution if paused.
+    void resume (void);
+
+    // Provided for convenience.  Will be removed once we eliminate the
+    // old terminal widget.
+    bool experimental_terminal_widget (void) const;
+
+    void handle_exception (const execution_exception& ee);
 
     void recover_from_exception (void);
 
@@ -495,6 +568,8 @@
 
     int main_loop (void);
 
+    int server_loop (void);
+
     void execute_atexit_fcns (void);
 
     application *m_app_context;
@@ -554,14 +629,15 @@
 
     bool m_verbose;
 
+    bool m_traditional;
+
     bool m_inhibit_startup_message;
 
     bool m_load_path_initialized;
 
     bool m_history_initialized;
 
-    // TRUE if we are in the top level interactive read eval print loop.
-    bool m_in_top_level_repl;
+    bool m_interrupt_all_in_process_group;
 
     bool m_cancel_quit;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/jsondecode.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,561 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "defun.h"
+#include "error.h"
+#include "errwarn.h"
+#include "ovl.h"
+#include "utils.h"
+
+#if defined (HAVE_RAPIDJSON)
+#  include <rapidjson/document.h>
+#  include <rapidjson/error/en.h>
+#endif
+
+#if defined (HAVE_RAPIDJSON)
+
+octave_value
+decode (const rapidjson::Value& val,
+        const octave::make_valid_name_options& options);
+
+//! Decodes a numerical JSON value into a scalar number.
+//!
+//! @param val JSON value that is guaranteed to be a numerical value.
+//!
+//! @return @ref octave_value that contains the numerical value of @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("123");
+//! octave_value num = decode_number (d);
+//! @endcode
+
+octave_value
+decode_number (const rapidjson::Value& val)
+{
+  if (val.IsUint ())
+    return octave_value (val.GetUint ());
+  else if (val.IsInt ())
+    return octave_value (val.GetInt ());
+  else if (val.IsUint64 ())
+    return octave_value (val.GetUint64 ());
+  else if (val.IsInt64 ())
+    return octave_value (val.GetInt64 ());
+  else if (val.IsDouble ())
+    return octave_value (val.GetDouble ());
+  else
+    error ("jsondecode: unidentified type");
+}
+
+//! Decodes a JSON object into a scalar struct.
+//!
+//! @param val JSON value that is guaranteed to be a JSON object.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the equivalent scalar struct of @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("{\"a\": 1, \"b\": 2}");
+//! octave_value struct = decode_object (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_object (const rapidjson::Value& val,
+               const octave::make_valid_name_options& options)
+{
+  octave_scalar_map retval;
+
+  for (const auto& pair : val.GetObject ())
+  {
+    // Validator function "matlab.lang.makeValidName" to guarantee legitimate
+    // variable name.
+    std::string varname = pair.name.GetString ();
+    octave::make_valid_name (varname, options);
+    retval.assign (varname, decode (pair.value, options));
+  }
+
+  return retval;
+}
+
+//! Decodes a JSON array that contains only numerical or null values
+//! into an NDArray.
+//!
+//! @param val JSON value that is guaranteed to be a numeric array.
+//!
+//! @return @ref octave_value that contains the equivalent NDArray of @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[1, 2, 3, 4]");
+//! octave_value numeric_array = decode_numeric_array (d);
+//! @endcode
+
+octave_value
+decode_numeric_array (const rapidjson::Value& val)
+{
+  NDArray retval (dim_vector (val.Size (), 1));
+  octave_idx_type index = 0;
+  for (const auto& elem : val.GetArray ())
+    retval(index++) = elem.IsNull () ? octave_NaN
+                                     : decode_number (elem).double_value ();
+  return retval;
+}
+
+//! Decodes a JSON array that contains only boolean values into a boolNDArray.
+//!
+//! @param val JSON value that is guaranteed to be a boolean array.
+//!
+//! @return @ref octave_value that contains the equivalent boolNDArray of @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[true, false, true]");
+//! octave_value boolean_array = decode_boolean_array (d);
+//! @endcode
+
+octave_value
+decode_boolean_array (const rapidjson::Value& val)
+{
+  boolNDArray retval (dim_vector (val.Size (), 1));
+  octave_idx_type index = 0;
+  for (const auto& elem : val.GetArray ())
+    retval(index++) = elem.GetBool ();
+  return retval;
+}
+
+//! Decodes a JSON array that contains different types
+//! or string values only into a Cell.
+//!
+//! @param val JSON value that is guaranteed to be a mixed or string array.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the equivalent Cell of @p val.
+//!
+//! @b Example (decoding a string array):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[\"foo\", \"bar\", \"baz\"]");
+//! octave_value cell = decode_string_and_mixed_array (d, octave_value_list ());
+//! @endcode
+//!
+//! @b Example (decoding a mixed array):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[\"foo\", 123, true]");
+//! octave_value cell = decode_string_and_mixed_array (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_string_and_mixed_array (const rapidjson::Value& val,
+                               const octave::make_valid_name_options& options)
+{
+  Cell retval (dim_vector (val.Size (), 1));
+  octave_idx_type index = 0;
+  for (const auto& elem : val.GetArray ())
+    retval(index++) = decode (elem, options);
+  return retval;
+}
+
+//! Decodes a JSON array that contains only objects into a Cell or struct array
+//! depending on the similarity of the objects' keys.
+//!
+//! @param val JSON value that is guaranteed to be an object array.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the equivalent Cell
+//! or struct array of @p val.
+//!
+//! @b Example (returns a struct array):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[{\"a\":1,\"b\":2},{\"a\":3,\"b\":4}]");
+//! octave_value object_array = decode_object_array (d, octave_value_list ());
+//! @endcode
+//!
+//! @b Example (returns a Cell):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[{\"a\":1,\"b\":2},{\"b\":3,\"a\":4}]");
+//! octave_value object_array = decode_object_array (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_object_array (const rapidjson::Value& val,
+                     const octave::make_valid_name_options& options)
+{
+  Cell struct_cell = decode_string_and_mixed_array (val, options).cell_value ();
+  string_vector field_names = struct_cell(0).scalar_map_value ().fieldnames ();
+
+  bool same_field_names = true;
+  for (octave_idx_type i = 1; i < struct_cell.numel (); ++i)
+    if (field_names.std_list ()
+        != struct_cell(i).scalar_map_value ().fieldnames ().std_list ())
+      {
+        same_field_names = false;
+        break;
+      }
+
+  if (same_field_names)
+    {
+      octave_map struct_array;
+      Cell value (dim_vector (struct_cell.numel (), 1));
+      for (octave_idx_type i = 0; i < field_names.numel (); ++i)
+        {
+          for (octave_idx_type k = 0; k < struct_cell.numel (); ++k)
+            value(k) = struct_cell(k).scalar_map_value ().getfield (field_names(i));
+          struct_array.assign (field_names(i), value);
+        }
+      return struct_array;
+    }
+  else
+    return struct_cell;
+}
+
+//! Decodes a JSON array that contains only arrays into a Cell or an NDArray
+//! depending on the dimensions and element types of the sub-arrays.
+//!
+//! @param val JSON value that is guaranteed to be an array of arrays.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the equivalent Cell
+//! or NDArray of @p val.
+//!
+//! @b Example (returns an NDArray):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[[1, 2], [3, 4]]");
+//! octave_value array = decode_array_of_arrays (d, octave_value_list ());
+//! @endcode
+//!
+//! @b Example (returns a Cell):
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[[1, 2], [3, 4, 5]]");
+//! octave_value cell = decode_array_of_arrays (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_array_of_arrays (const rapidjson::Value& val,
+                        const octave::make_valid_name_options& options)
+{
+  // Some arrays should be decoded as NDArrays and others as cell arrays
+  Cell cell = decode_string_and_mixed_array (val, options).cell_value ();
+
+  // Only arrays with sub-arrays of booleans and numericals will return NDArray
+  bool is_bool = cell(0).is_bool_matrix ();
+  dim_vector sub_array_dims = cell(0).dims ();
+  octave_idx_type sub_array_ndims = cell(0).ndims ();
+  octave_idx_type cell_numel = cell.numel ();
+  for (octave_idx_type i = 0; i < cell_numel; ++i)
+    {
+      // If one element is cell return the cell array as at least one of the
+      // sub-arrays area either an array of: strings, objects or mixed array
+      if (cell(i).iscell ())
+        return cell;
+      // If not the same dim of elements or dim = 0, return cell array
+      if (cell(i).dims () != sub_array_dims || sub_array_dims == dim_vector ())
+        return cell;
+      // If not numeric sub-arrays only or bool sub-arrays only,
+      // return cell array
+      if (cell(i).is_bool_matrix () != is_bool)
+        return cell;
+    }
+
+  // Calculate the dims of the output array
+  dim_vector array_dims;
+  array_dims.resize (sub_array_ndims + 1);
+  array_dims(0) = cell_numel;
+  for (auto i = 1; i < sub_array_ndims + 1; i++)
+    array_dims(i) = sub_array_dims(i-1);
+  NDArray array (array_dims);
+
+  // Populate the array with specific order to generate MATLAB-identical output
+  octave_idx_type array_index = 0;
+  for (octave_idx_type i = 0; i < array.numel () / cell_numel; ++i)
+    for (octave_idx_type k = 0; k < cell_numel; ++k)
+      array(array_index++) = cell(k).array_value ()(i);
+
+  if (is_bool)
+    return boolNDArray (array);
+  else
+    return array;
+}
+
+//! Decodes any type of JSON arrays.  This function only serves as an interface
+//! by choosing which function to call from the previous functions.
+//!
+//! @param val JSON value that is guaranteed to be an array.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the output of decoding @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[[1, 2], [3, 4, 5]]");
+//! octave_value array = decode_array (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode_array (const rapidjson::Value& val,
+              const octave::make_valid_name_options& options)
+{
+  // Handle empty arrays
+  if (val.Empty ())
+    return NDArray ();
+
+  // Compare with other elements to know if the array has multiple types
+  rapidjson::Type array_type = val[0].GetType ();
+  // Check if the array is numeric and if it has multiple types
+  bool same_type = true;
+  bool is_numeric = true;
+  for (const auto& elem : val.GetArray ())
+    {
+      rapidjson::Type current_elem_type = elem.GetType ();
+      if (is_numeric && ! (current_elem_type == rapidjson::kNullType
+          || current_elem_type == rapidjson::kNumberType))
+        is_numeric = false;
+      if (same_type && (current_elem_type != array_type))
+        // RapidJSON doesn't have kBoolean Type it has kTrueType and kFalseType
+        if (! ((current_elem_type == rapidjson::kTrueType
+                && array_type == rapidjson::kFalseType)
+            || (current_elem_type == rapidjson::kFalseType
+                && array_type == rapidjson::kTrueType)))
+          same_type = false;
+    }
+
+  if (is_numeric)
+    return decode_numeric_array (val);
+
+  if (same_type && (array_type != rapidjson::kStringType))
+    {
+      if (array_type == rapidjson::kTrueType
+          || array_type == rapidjson::kFalseType)
+        return decode_boolean_array (val);
+      else if (array_type == rapidjson::kObjectType)
+        return decode_object_array (val, options);
+      else if (array_type == rapidjson::kArrayType)
+        return decode_array_of_arrays (val, options);
+      else
+        error ("jsondecode: unidentified type");
+    }
+  else
+    return decode_string_and_mixed_array (val, options);
+}
+
+//! Decodes any JSON value.  This function only serves as an interface
+//! by choosing which function to call from the previous functions.
+//!
+//! @param val JSON value.
+//! @param options @c ReplacementStyle and @c Prefix options with their values.
+//!
+//! @return @ref octave_value that contains the output of decoding @p val.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! rapidjson::Document d;
+//! d.Parse ("[{\"a\":1,\"b\":2},{\"b\":3,\"a\":4}]");
+//! octave_value value = decode (d, octave_value_list ());
+//! @endcode
+
+octave_value
+decode (const rapidjson::Value& val,
+        const octave::make_valid_name_options& options)
+{
+  if (val.IsBool ())
+    return val.GetBool ();
+  else if (val.IsNumber ())
+    return decode_number (val);
+  else if (val.IsString ())
+    return val.GetString ();
+  else if (val.IsObject ())
+    return decode_object (val, options);
+  else if (val.IsNull ())
+    return NDArray ();
+  else if (val.IsArray ())
+    return decode_array (val, options);
+  else
+    error ("jsondecode: unidentified type");
+}
+
+#endif
+
+DEFUN (jsondecode, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{object} =} jsondecode (@var{JSON_txt})
+@deftypefnx {} {@var{object} =} jsondecode (@dots{}, "ReplacementStyle", @var{rs})
+@deftypefnx {} {@var{object} =} jsondecode (@dots{}, "Prefix", @var{pfx})
+
+Decode text that is formatted in JSON.
+
+The input @var{JSON_txt} is a string that contains JSON text.
+
+The output @var{object} is an Octave object that contains the result of
+decoding @var{JSON_txt}.
+
+For more information about the options @qcode{"ReplacementStyle"} and
+@qcode{"Prefix"}, see
+@ref{XREFmatlab_lang_makeValidName,,matlab.lang.makeValidName}.
+
+NOTE: Decoding and encoding JSON text is not guaranteed to reproduce the
+original text as some names may be changed by @code{matlab.lang.makeValidName}.
+
+This table shows the conversions from JSON data types to Octave data types:
+
+@multitable @columnfractions 0.50 0.50
+@headitem JSON data type @tab Octave data type
+@item Boolean @tab scalar logical
+@item Number @tab scalar double
+@item String @tab vector of characters
+@item Object @tab scalar struct (field names of the struct may be different from the keys of the JSON object due to @code{matlab_lang_makeValidName}
+@item null, inside a numeric array @tab @code{NaN}
+@item null, inside a non-numeric array @tab empty double array @code{[]}
+@item Array, of different data types @tab cell array
+@item Array, of Booleans @tab logical array
+@item Array, of Numbers @tab double array
+@item Array, of Strings @tab cell array of character vectors (@code{cellstr})
+@item Array of Objects, same field names @tab struct array
+@item Array of Objects, different field names @tab cell array of scalar structs
+@end multitable
+
+Examples:
+
+@example
+@group
+jsondecode ('[1, 2, null, 3]')
+    @result{} ans =
+
+      1
+      2
+    NaN
+      3
+@end group
+
+@group
+jsondecode ('["foo", "bar", ["foo", "bar"]]')
+    @result{} ans =
+       @{
+         [1,1] = foo
+         [2,1] = bar
+         [3,1] =
+         @{
+           [1,1] = foo
+           [2,1] = bar
+         @}
+
+       @}
+@end group
+
+@group
+jsondecode ('@{"nu#m#ber": 7, "s#tr#ing": "hi"@}', ...
+            'ReplacementStyle', 'delete')
+    @result{} scalar structure containing the fields:
+
+         number = 7
+         string = hi
+@end group
+
+@group
+jsondecode ('@{"1": "one", "2": "two"@}', 'Prefix', 'm_')
+    @result{} scalar structure containing the fields:
+
+         m_1 = one
+         m_2 = two
+@end group
+@end example
+
+@seealso{jsonencode, matlab.lang.makeValidName}
+@end deftypefn */)
+{
+#if defined (HAVE_RAPIDJSON)
+
+  int nargin = args.length ();
+
+  // makeValidName options are pairs, the number of arguments must be odd.
+  if (! (nargin % 2))
+    print_usage ();
+
+  octave::make_valid_name_options options (args.slice (1, nargin - 1));
+
+  if (! args(0).is_string ())
+    error ("jsondecode: JSON_TXT must be a character string");
+
+  std::string json = args(0).string_value ();
+  rapidjson::Document d;
+  // DOM is chosen instead of SAX as SAX publishes events to a handler that
+  // decides what to do depending on the event only.  This will cause a
+  // problem in decoding JSON arrays as the output may be an array or a cell
+  // and that doesn't only depend on the event (startArray) but also on the
+  // types of the elements inside the array.
+  d.Parse <rapidjson::kParseNanAndInfFlag> (json.c_str ());
+
+  if (d.HasParseError ())
+    error ("jsondecode: parse error at offset %u: %s\n",
+           static_cast<unsigned int> (d.GetErrorOffset ()) + 1,
+           rapidjson::GetParseError_En (d.GetParseError ()));
+
+  return decode (d, options);
+
+#else
+
+  octave_unused_parameter (args);
+
+  err_disabled_feature ("jsondecode", "JSON decoding through RapidJSON");
+
+#endif
+}
+
+/*
+Functional BIST tests are located in test/json/jsondecode_BIST.tst
+
+## Input validation tests
+%!testif HAVE_RAPIDJSON
+%! fail ("jsondecode ()");
+%! fail ("jsondecode ('1', 2)");
+%! fail ("jsondecode (1)", "JSON_TXT must be a character string");
+%! fail ("jsondecode ('12-')", "parse error at offset 3");
+
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/jsonencode.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,670 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "builtin-defun-decls.h"
+#include "defun.h"
+#include "error.h"
+#include "errwarn.h"
+#include "oct-string.h"
+#include "ovl.h"
+
+#if defined (HAVE_RAPIDJSON)
+#  include <rapidjson/stringbuffer.h>
+#  include <rapidjson/writer.h>
+#  if defined (HAVE_RAPIDJSON_PRETTYWRITER)
+#    include <rapidjson/prettywriter.h>
+#  endif
+#endif
+
+#if defined (HAVE_RAPIDJSON)
+
+//! Encodes a scalar Octave value into a numerical JSON value.
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj scalar Octave value.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (7);
+//! encode_numeric (writer, obj, true);
+//! @endcode
+
+template <typename T> void
+encode_numeric (T& writer, const octave_value& obj,
+                const bool& ConvertInfAndNaN)
+{
+  double value = obj.scalar_value ();
+
+  if (obj.is_bool_scalar ())
+    writer.Bool (obj.bool_value ());
+  // Any numeric input from the interpreter will be in double type so in order
+  // to detect ints, we will check if the floor of the input and the input are
+  // equal using fabs (A - B) < epsilon method as it is more accurate.
+  // If value > 999999, MATLAB will encode it in scientific notation (double)
+  else if (fabs (floor (value) - value) < std::numeric_limits<double>::epsilon ()
+           && value <= 999999 && value >= -999999)
+    writer.Int64 (value);
+  // Possibly write NULL for non-finite values (-Inf, Inf, NaN, NA)
+  else if (ConvertInfAndNaN && ! octave::math::isfinite (value))
+    writer.Null ();
+  else if (obj.is_double_type ())
+    writer.Double (value);
+  else
+    error ("jsonencode: unsupported type");
+}
+
+//! Encodes character vectors and arrays into JSON strings.
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj character vectors or character arrays.
+//! @param original_dims The original dimensions of the array being encoded.
+//! @param level The level of recursion for the function.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj ("foo");
+//! encode_string (writer, obj, true);
+//! @endcode
+
+template <typename T> void
+encode_string (T& writer, const octave_value& obj,
+               const dim_vector& original_dims, int level = 0)
+{
+  charNDArray array = obj.char_array_value ();
+
+  if (array.isempty ())
+    writer.String ("");
+  else if (array.isvector ())
+    {
+      // Handle the special case where the input is a vector with more than
+      // 2 dimensions (e.g. cat (8, ['a'], ['c'])).  In this case, we don't
+      // split the inner vectors of the input; we merge them into one.
+      if (level == 0)
+        {
+          std::string char_vector = "";
+          for (octave_idx_type i = 0; i < array.numel (); ++i)
+            char_vector += array(i);
+          writer.String (char_vector.c_str ());
+        }
+      else
+        for (octave_idx_type i = 0; i < array.numel () / original_dims(1); ++i)
+          {
+            std::string char_vector = "";
+            for (octave_idx_type k = 0; k < original_dims(1); ++k)
+              char_vector += array(i * original_dims(1) + k);
+            writer.String (char_vector.c_str ());
+          }
+    }
+  else
+    {
+      octave_idx_type idx;
+      octave_idx_type ndims = array.ndims ();
+      dim_vector dims = array.dims ();
+
+      // In this case, we already have a vector. So, we transform it to 2-D
+      // vector in order to be detected by "isvector" in the recursive call
+      if (dims.num_ones () == ndims - 1)
+      {
+        // Handle the special case when the input is a vector with more than
+        // 2 dimensions (e.g. cat (8, ['a'], ['c'])).  In this case, we don't
+        // add dimension brackets and treat it as if it is a vector
+        if (level != 0)
+          // Place an opening and a closing bracket (represents a dimension)
+          // for every dimension that equals 1 until we reach the 2-D vector
+          for (int i = level; i < ndims - 1; ++i)
+            writer.StartArray ();
+
+        encode_string (writer, array.as_row (), original_dims, level);
+
+        if (level != 0)
+          for (int i = level; i < ndims - 1; ++i)
+            writer.EndArray ();
+      }
+      else
+        {
+          // We place an opening and a closing bracket for each dimension
+          // that equals 1 to preserve the number of dimensions when decoding
+          // the array after encoding it.
+          if (original_dims(level) == 1 && level != 1)
+          {
+            writer.StartArray ();
+            encode_string (writer, array, original_dims, level + 1);
+            writer.EndArray ();
+          }
+          else
+            {
+              // The second dimension contains the number of the chars in
+              // the char vector. We want to treat them as a one object,
+              // so we replace it with 1
+              dims(1) = 1;
+
+              for (idx = 0; idx < ndims; ++idx)
+                if (dims(idx) != 1)
+                  break;
+              // Create the dimensions that will be used to call "num2cell"
+              // We called "num2cell" to divide the array to smaller sub-arrays
+              // in order to encode it recursively.
+              // The recursive encoding is necessary to support encoding of
+              // higher-dimensional arrays.
+              RowVector conversion_dims;
+              conversion_dims.resize (ndims - 1);
+              for (octave_idx_type i = 0; i < idx; ++i)
+                conversion_dims(i) = i + 1;
+              for (octave_idx_type i = idx ; i < ndims - 1; ++i)
+                conversion_dims(i) = i + 2;
+
+              octave_value_list args (obj);
+              args.append (conversion_dims);
+
+              Cell sub_arrays = Fnum2cell (args)(0).cell_value ();
+
+              writer.StartArray ();
+
+              for (octave_idx_type i = 0; i < sub_arrays.numel (); ++i)
+                encode_string (writer, sub_arrays(i), original_dims,
+                               level + 1);
+
+              writer.EndArray ();
+            }
+        }
+    }
+}
+
+//! Encodes a struct Octave value into a JSON object or a JSON array depending
+//! on the type of the struct (scalar struct or struct array.)
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj struct Octave value.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (octave_map ());
+//! encode_struct (writer, obj,true);
+//! @endcode
+
+template <typename T> void
+encode_struct (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
+{
+  octave_map struct_array = obj.map_value ();
+  octave_idx_type numel = struct_array.numel ();
+  bool is_array = (numel > 1);
+  string_vector keys = struct_array.keys ();
+
+  if (is_array)
+    writer.StartArray ();
+
+  for (octave_idx_type i = 0; i < numel; ++i)
+    {
+      writer.StartObject ();
+      for (octave_idx_type k = 0; k < keys.numel (); ++k)
+        {
+          writer.Key (keys(k).c_str ());
+          encode (writer, struct_array(i).getfield (keys(k)), ConvertInfAndNaN);
+        }
+      writer.EndObject ();
+    }
+
+  if (is_array)
+    writer.EndArray ();
+}
+
+//! Encodes a Cell Octave value into a JSON array
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj Cell Octave value.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (cell ());
+//! encode_cell (writer, obj,true);
+//! @endcode
+
+template <typename T> void
+encode_cell (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
+{
+  Cell cell = obj.cell_value ();
+
+  writer.StartArray ();
+
+  for (octave_idx_type i = 0; i < cell.numel (); ++i)
+    encode (writer, cell(i), ConvertInfAndNaN);
+
+  writer.EndArray ();
+}
+
+//! Encodes a numeric or logical Octave array into a JSON array
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj numeric or logical Octave array.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//! @param original_dims The original dimensions of the array being encoded.
+//! @param level The level of recursion for the function.
+//! @param is_logical optional @c bool that indicates if the array is logical.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (NDArray ());
+//! encode_array (writer, obj,true);
+//! @endcode
+
+template <typename T> void
+encode_array (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN,
+              const dim_vector& original_dims, int level = 0,
+              bool is_logical = false)
+{
+  NDArray array = obj.array_value ();
+  // is_logical is assigned at level 0.  I think this is better than changing
+  // many places in the code, and it makes the function more modular.
+  if (level == 0)
+    is_logical = obj.islogical ();
+
+  if (array.isempty ())
+    {
+      writer.StartArray ();
+      writer.EndArray ();
+    }
+  else if (array.isvector ())
+    {
+      writer.StartArray ();
+      for (octave_idx_type i = 0; i < array.numel (); ++i)
+        {
+          if (is_logical)
+            encode_numeric (writer, bool (array(i)), ConvertInfAndNaN);
+          else
+            encode_numeric (writer, array(i), ConvertInfAndNaN);
+        }
+      writer.EndArray ();
+    }
+  else
+    {
+      octave_idx_type idx;
+      octave_idx_type ndims = array.ndims ();
+      dim_vector dims = array.dims ();
+
+      // In this case, we already have a vector. So,  we transform it to 2-D
+      // vector in order to be detected by "isvector" in the recursive call
+      if (dims.num_ones () == ndims - 1)
+        {
+          // Handle the special case when the input is a vector with more than
+          // 2 dimensions (e.g. ones ([1 1 1 1 1 6])). In this case, we don't
+          // add dimension brackets and treat it as if it is a vector
+          if (level != 0)
+            // Place an opening and a closing bracket (represents a dimension)
+            // for every dimension that equals 1 till we reach the 2-D vector
+            for (int i = level; i < ndims - 1; ++i)
+              writer.StartArray ();
+
+          encode_array (writer, array.as_row (), ConvertInfAndNaN,
+                        original_dims, level + 1, is_logical);
+
+          if (level != 0)
+            for (int i = level; i < ndims - 1; ++i)
+              writer.EndArray ();
+        }
+      else
+        {
+          // We place an opening and a closing bracket for each dimension
+          // that equals 1 to preserve the number of dimensions when decoding
+          // the array after encoding it.
+          if (original_dims (level) == 1)
+          {
+            writer.StartArray ();
+            encode_array (writer, array, ConvertInfAndNaN,
+                          original_dims, level + 1, is_logical);
+            writer.EndArray ();
+          }
+          else
+            {
+              for (idx = 0; idx < ndims; ++idx)
+                if (dims(idx) != 1)
+                  break;
+
+              // Create the dimensions that will be used to call "num2cell"
+              // We called "num2cell" to divide the array to smaller sub-arrays
+              // in order to encode it recursively.
+              // The recursive encoding is necessary to support encoding of
+              // higher-dimensional arrays.
+              RowVector conversion_dims;
+              conversion_dims.resize (ndims - 1);
+              for (octave_idx_type i = 0; i < idx; ++i)
+                conversion_dims(i) = i + 1;
+              for (octave_idx_type i = idx ; i < ndims - 1; ++i)
+                conversion_dims(i) = i + 2;
+
+              octave_value_list args (obj);
+              args.append (conversion_dims);
+
+              Cell sub_arrays = Fnum2cell (args)(0).cell_value ();
+
+              writer.StartArray ();
+
+              for (octave_idx_type i = 0; i < sub_arrays.numel (); ++i)
+                encode_array (writer, sub_arrays(i), ConvertInfAndNaN,
+                              original_dims, level + 1, is_logical);
+
+              writer.EndArray ();
+            }
+        }
+    }
+}
+
+//! Encodes any Octave object. This function only serves as an interface
+//! by choosing which function to call from the previous functions.
+//!
+//! @param writer RapidJSON's writer that is responsible for generating JSON.
+//! @param obj any @ref octave_value that is supported.
+//! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
+//!
+//! @b Example:
+//!
+//! @code{.cc}
+//! octave_value obj (true);
+//! encode (writer, obj,true);
+//! @endcode
+
+template <typename T> void
+encode (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
+{
+  if (obj.is_real_scalar ())
+    encode_numeric (writer, obj, ConvertInfAndNaN);
+  // As I checked for scalars, this will detect numeric & logical arrays
+  else if (obj.isnumeric () || obj.islogical ())
+    encode_array (writer, obj, ConvertInfAndNaN, obj.dims ());
+  else if (obj.is_string ())
+    encode_string (writer, obj, obj.dims ());
+  else if (obj.isstruct ())
+    encode_struct (writer, obj, ConvertInfAndNaN);
+  else if (obj.iscell ())
+    encode_cell (writer, obj, ConvertInfAndNaN);
+  else if (obj.class_name () == "containers.Map")
+    // To extract the data in containers.Map, convert it to a struct.
+    // The struct will have a "map" field whose value is a struct that
+    // contains the desired data.
+    // To avoid warnings due to that conversion, disable the
+    // "Octave:classdef-to-struct" warning and re-enable it.
+    {
+      octave::unwind_action restore_warning_state
+        ([] (const octave_value_list& old_warning_state)
+         {
+           set_warning_state (old_warning_state);
+         }, set_warning_state ("Octave:classdef-to-struct", "off"));
+
+      encode_struct (writer, obj.scalar_map_value ().getfield ("map"),
+                     ConvertInfAndNaN);
+    }
+  else if (obj.isobject ())
+    {
+      octave::unwind_action restore_warning_state
+        ([] (const octave_value_list& old_warning_state)
+         {
+           set_warning_state (old_warning_state);
+         }, set_warning_state ("Octave:classdef-to-struct", "off"));
+
+      encode_struct (writer, obj.scalar_map_value (), ConvertInfAndNaN);
+    }
+  else
+    error ("jsonencode: unsupported type");
+}
+
+#endif
+
+DEFUN (jsonencode, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{JSON_txt} =} jsonencode (@var{object})
+@deftypefnx {} {@var{JSON_txt} =} jsonencode (@dots{}, "ConvertInfAndNaN", @var{TF})
+@deftypefnx {} {@var{JSON_txt} =} jsonencode (@dots{}, "PrettyPrint", @var{TF})
+
+Encode Octave data types into JSON text.
+
+The input @var{object} is an Octave variable to encode.
+
+The output @var{JSON_txt} is the JSON text that contains the result of encoding
+@var{object}.
+
+If the value of the option @qcode{"ConvertInfAndNaN"} is true then @code{NaN},
+@code{NA}, @code{-Inf}, and @code{Inf} values will be converted to
+@qcode{"null"} in the output.  If it is false then they will remain as their
+original values.  The default value for this option is true.
+
+If the value of the option @qcode{"PrettyPrint"} is true, the output text will
+have indentations and line feeds.  If it is false, the output will be condensed
+and written without whitespace.  The default value for this option is false.
+
+Programming Notes:
+
+@itemize @bullet
+@item
+Complex numbers are not supported.
+
+@item
+classdef objects are first converted to structs and then encoded.
+
+@item
+To preserve escape characters (e.g., @qcode{"@backslashchar{}n"}), use
+single-quoted strings.
+
+@item
+Every character after the null character (@qcode{"@backslashchar{}0"}) in a
+double-quoted string will be dropped during encoding.
+
+@item
+Encoding and decoding an array is not guaranteed to preserve the dimensions
+of the array.  In particular, row vectors will be reshaped to column vectors.
+
+@item
+Encoding and decoding is not guaranteed to preserve the Octave data type
+because JSON supports fewer data types than Octave.  For example, if you
+encode an @code{int8} and then decode it, you will get a @code{double}.
+@end itemize
+
+This table shows the conversions from Octave data types to JSON data types:
+
+@multitable @columnfractions 0.50 0.50
+@headitem Octave data type @tab JSON data type
+@item logical scalar @tab Boolean
+@item logical vector @tab Array of Boolean, reshaped to row vector
+@item logical array  @tab nested Array of Boolean
+@item numeric scalar @tab Number
+@item numeric vector @tab Array of Number, reshaped to row vector
+@item numeric array  @tab nested Array of Number
+@item @code{NaN}, @code{NA}, @code{Inf}, @code{-Inf}@*
+when @qcode{"ConvertInfAndNaN" = true} @tab @qcode{"null"}
+@item @code{NaN}, @code{NA}, @code{Inf}, @code{-Inf}@*
+when @qcode{"ConvertInfAndNaN" = false} @tab @qcode{"NaN"}, @qcode{"NaN"},
+@qcode{"Infinity"}, @qcode{"-Infinity"}
+@item empty array    @tab @qcode{"[]"}
+@item character vector @tab String
+@item character array @tab Array of String
+@item empty character array @tab @qcode{""}
+@item cell scalar @tab Array
+@item cell vector @tab Array, reshaped to row vector
+@item cell array @tab Array, flattened to row vector
+@item struct scalar @tab Object
+@item struct vector @tab Array of Object, reshaped to row vector
+@item struct array  @tab nested Array of Object
+@item classdef object @tab Object
+@end multitable
+
+Examples:
+
+@example
+@group
+jsonencode ([1, NaN; 3, 4])
+@result{} [[1,null],[3,4]]
+@end group
+
+@group
+jsonencode ([1, NaN; 3, 4], "ConvertInfAndNaN", false)
+@result{} [[1,NaN],[3,4]]
+@end group
+
+@group
+## Escape characters inside a single-quoted string
+jsonencode ('\0\a\b\t\n\v\f\r')
+@result{} "\\0\\a\\b\\t\\n\\v\\f\\r"
+@end group
+
+@group
+## Escape characters inside a double-quoted string
+jsonencode ("\a\b\t\n\v\f\r")
+@result{} "\u0007\b\t\n\u000B\f\r"
+@end group
+
+@group
+jsonencode ([true; false], "PrettyPrint", true)
+@result{} ans = [
+     true,
+     false
+   ]
+@end group
+
+@group
+jsonencode (['foo', 'bar'; 'foo', 'bar'])
+@result{} ["foobar","foobar"]
+@end group
+
+@group
+jsonencode (struct ('a', Inf, 'b', [], 'c', struct ()))
+@result{} @{"a":null,"b":[],"c":@{@}@}
+@end group
+
+@group
+jsonencode (struct ('structarray', struct ('a', @{1; 3@}, 'b', @{2; 4@})))
+@result{} @{"structarray":[@{"a":1,"b":2@},@{"a":3,"b":4@}]@}
+@end group
+
+@group
+jsonencode (@{'foo'; 'bar'; @{'foo'; 'bar'@}@})
+@result{} ["foo","bar",["foo","bar"]]
+@end group
+
+@group
+jsonencode (containers.Map(@{'foo'; 'bar'; 'baz'@}, [1, 2, 3]))
+@result{} @{"bar":2,"baz":3,"foo":1@}
+@end group
+@end example
+
+@seealso{jsondecode}
+@end deftypefn */)
+{
+#if defined (HAVE_RAPIDJSON)
+
+  int nargin = args.length ();
+  // jsonencode has two options 'ConvertInfAndNaN' and 'PrettyPrint'
+  if (nargin != 1 && nargin != 3 && nargin != 5)
+    print_usage ();
+
+  // Initialize options with their default values
+  bool ConvertInfAndNaN = true;
+  bool PrettyPrint = false;
+
+  for (octave_idx_type i = 1; i < nargin; ++i)
+    {
+      if (! args(i).is_string ())
+        error ("jsonencode: option must be a string");
+      if (! args(i+1).is_bool_scalar ())
+        error ("jsonencode: option value must be a logical scalar");
+
+      std::string option_name = args(i++).string_value ();
+      if (octave::string::strcmpi (option_name, "ConvertInfAndNaN"))
+        ConvertInfAndNaN = args(i).bool_value ();
+      else if (octave::string::strcmpi (option_name, "PrettyPrint"))
+        PrettyPrint = args(i).bool_value ();
+      else
+        error ("jsonencode: "
+               R"(Valid options are "ConvertInfAndNaN" and "PrettyPrint")");
+    }
+
+# if ! defined (HAVE_RAPIDJSON_PRETTYWRITER)
+  if (PrettyPrint)
+    {
+      warn_disabled_feature ("jsonencode",
+                             R"(the "PrettyPrint" option of RapidJSON)");
+      PrettyPrint = false;
+    }
+# endif
+
+  rapidjson::StringBuffer json;
+  if (PrettyPrint)
+    {
+# if defined (HAVE_RAPIDJSON_PRETTYWRITER)
+      rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>,
+                              rapidjson::UTF8<>, rapidjson::CrtAllocator,
+                              rapidjson::kWriteNanAndInfFlag> writer (json);
+      writer.SetIndent (' ', 2);
+      encode (writer, args(0), ConvertInfAndNaN);
+# endif
+    }
+  else
+    {
+      rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>,
+                        rapidjson::UTF8<>, rapidjson::CrtAllocator,
+                        rapidjson::kWriteNanAndInfFlag> writer (json);
+      encode (writer, args(0), ConvertInfAndNaN);
+    }
+
+  return octave_value (json.GetString ());
+
+#else
+
+  octave_unused_parameter (args);
+
+  err_disabled_feature ("jsonencode", "JSON encoding through RapidJSON");
+
+#endif
+}
+
+/*
+Functional BIST tests are located in test/json/jsonencode_BIST.tst
+
+## Input validation tests
+%!testif HAVE_RAPIDJSON
+%! fail ("jsonencode ()");
+%! fail ("jsonencode (1, 2)");
+%! fail ("jsonencode (1, 2, 3, 4)");
+%! fail ("jsonencode (1, 2, 3, 4, 5, 6)");
+%! fail ("jsonencode (1, 2, true)", "option must be a string");
+%! fail ("jsonencode (1, 'string', ones (2,2))", ...
+%!       "option value must be a logical scalar");
+%! fail ("jsonencode (1, 'foobar', true)", ...
+%!       'Valid options are "ConvertInfAndNaN"');
+
+%!testif HAVE_RAPIDJSON; ! __have_feature__ ("RAPIDJSON_PRETTYWRITER")
+%! fail ("jsonencode (1, 'PrettyPrint', true)", ...
+%!       "warning", 'the "PrettyPrint" option of RapidJSON was unavailable');
+
+*/
--- a/libinterp/corefcn/kron.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/kron.cc	Sun May 16 09:44:35 2021 +0200
@@ -310,7 +310,7 @@
 %!assert (kron (single (1:4), ones (3, 1)), single (z))
 %!assert (kron (sparse (1:4), ones (3, 1)), sparse (z))
 %!assert (kron (complex (1:4), ones (3, 1)), z)
-%!assert (kron (complex (single(1:4)), ones (3, 1)), single(z))
+%!assert (kron (complex (single (1:4)), ones (3, 1)), single (z))
 %!assert (kron (x, y, z), kron (kron (x, y), z))
 %!assert (kron (x, y, z), kron (x, kron (y, z)))
 %!assert (kron (p1, p1), kron (p2, p2))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/latex-text-renderer.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,504 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2021 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/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+
+#include "base-text-renderer.h"
+#include "builtin-defun-decls.h"
+#include "dim-vector.h"
+#include "error.h"
+#include "file-ops.h"
+#include "interpreter.h"
+#include "interpreter-private.h"
+#include "oct-env.h"
+#include "oct-process.h"
+
+namespace octave
+{
+  // FIXME: get rid of this global variable
+  // Store both the generated pixmap and the svg image
+  typedef std::pair<uint8NDArray /*pixels*/, std::string /*svg*/> latex_data;
+  std::unordered_map<std::string, latex_data> latex_cache;
+
+  std::string
+  quote_string (std::string str)
+  {
+    return ('"' + str + '"');
+  }
+
+  class
+  OCTINTERP_API
+  latex_renderer : public base_text_renderer
+ {
+
+  public:
+
+    latex_renderer (void)
+      : m_fontsize (10.0), m_fontname ("cmr"), m_tmp_dir (),
+        m_color (dim_vector (1, 3), 0), m_latex_binary ("latex"),
+        m_dvipng_binary ("dvipng"), m_dvisvg_binary ("dvisvgm"),
+        m_debug (false), m_testing (true)
+      {
+        std::string bin = sys::env::getenv ("OCTAVE_LATEX_BINARY");
+        if (! bin.empty ())
+          m_latex_binary = quote_string (bin);
+
+        bin = sys::env::getenv ("OCTAVE_DVIPNG_BINARY");
+        if (! bin.empty ())
+          m_dvipng_binary = quote_string (bin);
+
+        bin = sys::env::getenv ("OCTAVE_DVISVG_BINARY");
+        if (! bin.empty ())
+          m_dvisvg_binary = quote_string (bin);
+
+        m_debug = ! sys::env::getenv ("OCTAVE_LATEX_DEBUG_FLAG").empty ();
+      }
+
+    ~latex_renderer (void)
+      {
+        if (! m_tmp_dir.empty () && ! m_debug)
+          octave::sys::recursive_rmdir (m_tmp_dir);
+      }
+
+    void set_font (const std::string& /*name*/, const std::string& /*weight*/,
+                   const std::string& /*angle*/, double size)
+    {
+      m_fontsize = size;
+    }
+
+    void set_color (const Matrix& c)
+    {
+      if (c.numel () == 3)
+        {
+          m_color(0) = static_cast<uint8_t> (c (0) * 255);
+          m_color(1) = static_cast<uint8_t> (c (1) * 255);
+          m_color(2) = static_cast<uint8_t> (c (2) * 255);
+        }
+    }
+
+    Matrix get_extent (text_element* /*elt*/, double /*rotation*/)
+    {
+      return Matrix (1, 2, 0.0);
+    }
+
+    Matrix get_extent (const std::string& txt, double rotation,
+                       const caseless_str& interpreter)
+    {
+      Matrix bbox;
+      uint8NDArray pixels;
+      text_to_pixels (txt, pixels, bbox, 0, 0, rotation, interpreter, false);
+      return bbox.extract_n (0, 2, 1, 2);
+    }
+
+    void text_to_strlist (const std::string& txt,
+                          std::list<text_renderer::string>& lst,
+                          Matrix& bbox, int halign, int valign, double rotation,
+                          const caseless_str& interp)
+    {
+      uint8NDArray pixels;
+      text_to_pixels (txt, pixels, bbox, halign, valign, rotation,
+                      interp, false);
+
+      text_renderer::font fnt;
+      text_renderer::string str ("", fnt, 0.0, 0.0);
+      str.set_color (m_color);
+      str.set_svg_element (latex_cache[key (txt, halign)].second);
+      lst.push_back (str);
+    }
+
+    void text_to_pixels (const std::string& txt, uint8NDArray& pxls,
+                         Matrix& bbox, int halign, int valign, double rotation,
+                         const caseless_str& interpreter,
+                         bool handle_rotation);
+
+    void set_anti_aliasing (bool /*val*/) { }
+
+    octave_map get_system_fonts (void) { return octave_map (); }
+
+    bool ok (void);
+
+  private:
+
+    std::string key (const std::string& txt, int halign)
+    {
+      return (txt + ":"
+              + std::to_string (m_fontsize) + ":"
+              + std::to_string (halign) + ":"
+              + std::to_string (m_color(0)) + ":"
+              + std::to_string (m_color(1)) + ":"
+              + std::to_string (m_color(2)));
+    }
+
+    void warn_helper (std::string caller, std::string txt,std::string cmd,
+                      process_execution_result result);
+
+    uint8NDArray render (const std::string& txt, int halign = 0);
+
+    bool read_image (const std::string& png_file, uint8NDArray& data) const;
+
+    std::string write_tex_file (const std::string& txt, int halign);
+
+  private:
+    double m_fontsize;
+    std::string m_fontname;
+    std::string m_tmp_dir;
+    uint8NDArray m_color;
+    std::string m_latex_binary;
+    std::string m_dvipng_binary;
+    std::string m_dvisvg_binary;
+    bool m_debug;
+    bool m_testing;
+
+  };
+
+  bool
+  latex_renderer::ok (void)
+  {
+    // Only run the test once in a session
+    static bool tested = false;
+
+    static bool isok = false;
+
+    if (! tested)
+      {
+        tested = true;
+
+        // For testing, render a questoin mark
+        uint8NDArray pixels = render ("?");
+
+        if (! pixels.isempty ())
+          isok = true;
+        else
+          warning_with_id ("Octave:LaTeX:internal-error",
+                           "latex_renderer: a run-time test failed and the 'latex' interpreter has been disabled.");
+      }
+
+    m_testing = false;
+
+    return isok;
+  }
+
+  std::string
+  latex_renderer::write_tex_file (const std::string& txt, int halign)
+  {
+    if (m_tmp_dir.empty ())
+      {
+        //Create the temporary directory
+        m_tmp_dir = octave::sys::tempnam ("", "latex");
+
+        if (octave::sys::mkdir (m_tmp_dir, 0700) != 0)
+          {
+            warning_with_id ("Octave:LaTeX:internal-error",
+                             "latex_renderer: unable to create temp directory");
+            return std::string ();
+          }
+      }
+
+    std::string base_file_name
+      = octave::sys::file_ops::concat (m_tmp_dir, "default");
+
+    // Duplicate \n characters and align multi-line strings based on
+    // horizontalalignment
+    std::string latex_txt (txt);
+    std::size_t pos = 0;
+
+    while (true)
+      {
+        pos =  txt.find_first_of ("\n", pos);
+
+        if (pos == std::string::npos)
+          break;
+
+        latex_txt.replace (pos, 1, "\n\n");
+
+        pos += 1;
+      }
+
+    std::string env ("flushleft");
+    if (halign == 1)
+      env = "center";
+    else if (halign == 2)
+      env = "flushright";
+
+    latex_txt = std::string ("\\begin{" ) + env + "}\n"
+      + latex_txt + "\n"
+      + "\\end{" + env + "}\n";
+
+    // Write to temporary .tex file
+    std::ofstream file;
+    file.open (base_file_name + ".tex");
+    file << "\\documentclass[10pt, varwidth]{standalone}\n"
+         << "\\usepackage{amsmath}\n"
+         << "\\usepackage[utf8]{inputenc}\n"
+         << "\\begin{document}\n"
+         << latex_txt << "\n"
+         << "\\end{document}";
+    file.close ();
+
+    return base_file_name;
+  }
+
+  bool
+  latex_renderer::read_image (const std::string& png_file,
+                              uint8NDArray& data) const
+  {
+    uint8NDArray alpha;
+    uint8NDArray rgb;
+    int height;
+    int width;
+
+    try
+      {
+        // First get the image size to build the argument to __magick_read__
+        octave_value_list retval = F__magick_ping__ (ovl (png_file), 1);
+
+        octave_scalar_map info
+          = retval(0).xscalar_map_value ("latex_renderer::read_image: "
+                                         "Wrong type for info");
+        height = info.getfield ("rows").int_value ();
+        width = info.getfield ("columns").int_value ();
+        Cell region (dim_vector(1,2));
+        region(0) = range<double> (1.0, height);
+        region(1) = range<double> (1.0, width);
+        info.setfield ("region", region);
+        info.setfield ("index", octave_value (1));
+
+        // Retrieve the alpha map
+        retval = F__magick_read__ (ovl (png_file, info), 3);
+
+        alpha = retval(2).xuint8_array_value ("latex_renderer::read_image: "
+                                              "Wrong type for alpha");
+      }
+    catch (const octave::execution_exception& ee)
+      {
+        warning_with_id ("Octave:LaTeX:internal-error",
+                         "latex_renderer:: failed to read png data. %s",
+                         ee.message ().c_str ());
+
+        octave::interpreter& interp
+          = octave::__get_interpreter__ ("latex_renderer::read_image");
+
+        interp.recover_from_exception ();
+
+        return false;
+      }
+
+    data = uint8NDArray (dim_vector (4, width, height),
+                             static_cast<uint8_t> (0));
+
+    for (int i = 0; i < height; i++)
+      {
+        for (int j = 0; j < width; j++)
+          {
+            data(0, j, i) = m_color(0);
+            data(1, j, i) = m_color(1);
+            data(2, j, i) = m_color(2);
+            data(3, j, i) = alpha(height-i-1,j);
+          }
+      }
+
+    return true;
+  }
+
+  void
+  latex_renderer::warn_helper (std::string caller, std::string txt,
+                               std::string cmd, process_execution_result result)
+  {
+    if (m_testing && ! m_debug)
+      return;
+
+    if (! m_debug)
+      warning_with_id ("Octave:LaTeX:internal-error",
+                       "latex_renderer: unable to compile \"%s\"",
+                       txt.c_str ());
+    else
+      warning_with_id ("Octave:LaTeX:internal-error",
+                       "latex_renderer: %s failed for string \"%s\"\n\
+* Command:\n\t%s\n\n* Error:\n%s\n\n* Stdout:\n%s",
+                       caller.c_str (), txt.c_str (), cmd.c_str (),
+                       result.err_msg ().c_str (),
+                       result.stdout_output ().c_str ());
+  }
+
+  uint8NDArray
+  latex_renderer::render (const std::string& txt, int halign)
+  {
+    // Render if it was not already done
+    auto it = latex_cache.find (key (txt, halign));
+
+    if (it != latex_cache.end ())
+      return it->second.first;
+
+    uint8NDArray data;
+
+    // First write the base .tex file
+    std::string base_file_name = write_tex_file (txt, halign);
+
+    if (base_file_name.empty ())
+      return data;
+
+    // Generate DVI file
+    std::string tex_file = quote_string (base_file_name + ".tex");
+    std::string dvi_file = quote_string (base_file_name + ".dvi");
+    std::string log_file = quote_string (base_file_name + ".log");
+
+    process_execution_result result;
+    std::string cmd = (m_latex_binary + " -interaction=nonstopmode "
+                       + "-output-directory=" + quote_string (m_tmp_dir) + " "
+                       + tex_file);
+
+#if defined (OCTAVE_USE_WINDOWS_API)
+    cmd = quote_string (cmd);
+#endif
+
+    result = run_command_and_return_output (cmd);
+
+    if (result.exit_status () != 0)
+      {
+        warn_helper ("latex", txt, cmd, result);
+
+        if (txt != "?")
+          {
+            write_tex_file ("?", halign);
+
+            result = run_command_and_return_output (cmd);
+            if (result.exit_status () != 0)
+              return data;
+          }
+        else
+          return data;
+      }
+
+    double size_factor = m_fontsize / 10.0;
+
+
+    // Convert DVI to SVG, read file and store its content for later use in
+    // gl2ps_print
+    std::string svg_file = base_file_name + ".svg";
+
+    cmd = (m_dvisvg_binary + " -n "
+           + "-TS" + std::to_string (size_factor) + " "
+           + "-v1 -o " + quote_string (svg_file) + " "
+           + dvi_file);
+
+#if defined (OCTAVE_USE_WINDOWS_API)
+    cmd = quote_string (cmd);
+#endif
+
+    result = run_command_and_return_output (cmd);
+
+    if (result.exit_status () != 0)
+      {
+        warn_helper ("dvisvg", txt, cmd, result);
+        return data;
+      }
+
+    std::ifstream svg_stream (svg_file);
+    std::string svg_string;
+    svg_string.assign (std::istreambuf_iterator<char> (svg_stream),
+                       std::istreambuf_iterator<char> ());
+
+    // Convert DVI to PNG, read file and format pixel data for later use in
+    // OpenGL
+    std::string png_file = base_file_name + ".png";
+
+    cmd = (m_dvipng_binary + " " + dvi_file + " "
+           + "-q -o " + quote_string (png_file) + " "
+           + "-bg Transparent -D "
+           + std::to_string (std::floor (72.0 * size_factor)));
+
+#if defined (OCTAVE_USE_WINDOWS_API)
+    cmd = quote_string (cmd);
+#endif
+
+    result = run_command_and_return_output (cmd);
+
+    if (result.exit_status () != 0)
+      {
+        warn_helper ("dvipng", txt, cmd, result);
+        return data;
+      }
+
+    if (! read_image (png_file, data))
+      return data;
+
+    // Cache pixel and svg data for this string
+    latex_cache[key (txt, halign)] = latex_data (data, svg_string);
+
+    if (m_debug)
+      std::cout << "* Caching " << key (txt, halign)
+                << " (numel: " << latex_cache.size () << ")\n";
+
+    return data;
+  }
+
+  void
+  latex_renderer::text_to_pixels (const std::string& txt, uint8NDArray& pixels,
+                                  Matrix& bbox, int halign, int valign,
+                                  double rotation,
+                                  const caseless_str& /*interpreter*/,
+                                  bool handle_rotation)
+  {
+    // Return early for empty strings
+    if (txt.empty ())
+      return;
+
+    if (ok ())
+      pixels = render (txt, halign);
+    else
+      pixels = uint8NDArray (dim_vector (4, 1, 1), static_cast<uint8_t> (0));
+
+    if (pixels.ndims () < 3 || pixels.isempty ())
+      return;  // nothing to render
+
+    // Store unrotated bbox size
+    bbox = Matrix (1, 4, 0.0);
+    bbox (2) = pixels.dim2 ();
+    bbox (3) = pixels.dim3 ();
+
+    // Now rotate pixels if necessary
+    int rot_mode = rotation_to_mode (rotation);
+
+    if (! pixels.isempty ())
+      rotate_pixels (pixels, rot_mode);
+
+    // Move X0 and Y0 depending on alignments and eventually swap values
+    // for text rotated 90° 180° or 270°
+    fix_bbox_anchor (bbox, halign, valign, rot_mode, handle_rotation);
+  }
+
+  base_text_renderer*
+  make_latex_text_renderer (void)
+  {
+    latex_renderer *renderer = new latex_renderer ();
+
+    return renderer;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/latex-text-renderer.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,38 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2021 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_latex_text_renderer_h)
+#define octave_latex_text_renderer_h 1
+
+#include "octave-config.h"
+
+namespace octave
+{
+  class base_text_renderer;
+
+  extern base_text_renderer * make_latex_text_renderer (void);
+}
+
+#endif
--- a/libinterp/corefcn/load-path.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/load-path.cc	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,7 @@
 #endif
 
 #include <algorithm>
+#include <cctype>
 
 #include "dir-ops.h"
 #include "file-ops.h"
@@ -230,8 +231,8 @@
   load_path::load_path (interpreter& interp)
     : m_interpreter (interp), package_map (), top_level_package (),
       dir_info_list (), init_dirs (), m_command_line_path (),
-      add_hook ([this] (const std::string& dir) { this->execute_pkg_add (dir); }),
-      remove_hook ([this] (const std::string& dir) { this->execute_pkg_del (dir); })
+      add_hook ([=] (const std::string& dir) { this->execute_pkg_add (dir); }),
+      remove_hook ([=] (const std::string& dir) { this->execute_pkg_del (dir); })
   { }
 
   void
@@ -407,8 +408,10 @@
         bool ok = di.update ();
 
         if (! ok)
-          warning ("load-path: update failed for '%s', removing from path",
-                   di.dir_name.c_str ());
+          warning_with_id
+            ("Octave:load-path:update-failed",
+             "load-path: update failed for '%s', removing from path",
+             di.dir_name.c_str ());
         else
           add (di, true, "", true);
       }
@@ -963,8 +966,6 @@
     if (! octave_interpreter_ready)
       return;
 
-    unwind_protect frame;
-
     std::string file = sys::file_ops::concat (dir, script_file);
 
     sys::file_stat fs (file);
@@ -1086,6 +1087,8 @@
           {
             if (fs.is_dir ())
               {
+                read_dir_config (dir);
+
                 dir_info di (dir);
 
                 if (at_end)
@@ -1136,6 +1139,78 @@
       }
   }
 
+  void
+  load_path::read_dir_config (const std::string& dir) const
+  {
+    // read file with directory configuration
+    std::string conf_file = dir + sys::file_ops::dir_sep_str ()
+                            + ".oct-config";
+
+    FILE* cfile = sys::fopen (conf_file, "rb");
+
+    if (! cfile)
+      {
+        // reset directory encoding
+        input_system& input_sys
+          = __get_input_system__ ("load_path::read_dir_config");
+
+        std::string enc_val = "delete";
+        input_sys.set_dir_encoding (dir, enc_val);
+        return;
+      }
+
+    unwind_action close_file ([cfile] (void) { fclose (cfile); });
+
+    // find line with character encoding and read it
+    bool eof = false;
+    const std::string enc_prop = "encoding";
+    while (! eof)
+      {
+        std::string conf_str = octave_fgets (cfile, eof);
+
+        // delete any preceeding whitespace
+        auto it = std::find_if_not (conf_str.begin (), conf_str.end (),
+                                    [] (unsigned char c)
+                                    { return std::isblank (c); });
+        conf_str.erase (conf_str.begin (), it);
+
+        // match identifier
+        if (conf_str.compare (0, enc_prop.size (), enc_prop) == 0)
+          {
+            // skip delimiter characters
+            std::size_t pos = conf_str.find_first_not_of (" \t=:",
+                                                     enc_prop.size ());
+            if (pos == std::string::npos)
+              continue;
+
+            std::string enc_val = conf_str.substr (pos);
+
+            // take alphanumeric and '-' characters
+            it = std::find_if_not (enc_val.begin (), enc_val.end (),
+                                   [] (unsigned char c)
+                                   { return std::isalnum (c) || c == '-'; });
+            enc_val.erase(it, enc_val.end ());
+
+            if (enc_val.empty ())
+              continue;
+
+            // set encoding for this directory in input system
+            input_system& input_sys
+              = __get_input_system__ ("load_path::read_dir_config");
+            input_sys.set_dir_encoding (dir, enc_val);
+            return;
+          }
+      }
+
+    // reset directory encoding
+    input_system& input_sys
+      = __get_input_system__ ("load_path::read_dir_config");
+
+    std::string enc_val = "delete";
+    input_sys.set_dir_encoding (dir, enc_val);
+
+  }
+
   bool
   load_path::is_package (const std::string& name) const
   {
@@ -1259,7 +1334,9 @@
     if (! fs)
       {
         std::string msg = fs.error ();
-        warning ("load_path: %s: %s", dir_name.c_str (), msg.c_str ());
+        warning_with_id ("Octave:load-path:dir-info:update-failed",
+                         "load_path: %s: %s", dir_name.c_str (), msg.c_str ());
+
         return false;
       }
 
--- a/libinterp/corefcn/load-path.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/load-path.h	Sun May 16 09:44:35 2021 +0200
@@ -191,6 +191,8 @@
       remove_hook = f;
     }
 
+    void read_dir_config (const std::string& dir) const;
+
     void execute_pkg_add (const std::string& dir);
     void execute_pkg_del (const std::string& dir);
 
--- a/libinterp/corefcn/load-save.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/load-save.cc	Sun May 16 09:44:35 2021 +0200
@@ -165,8 +165,6 @@
   {
     bool retval = false;
 
-    std::string ascii_fname = sys::get_ASCII_filename (fname);
-
     std::ifstream file = sys::ifstream (fname.c_str (),
                                         std::ios::in | std::ios::binary);
 
@@ -645,6 +643,10 @@
           warning (R"(save: "-tabs" option only has an effect with "-ascii")");
       }
 
+    if (append && use_zlib
+        && (fmt.type () != TEXT && fmt.type () != MAT_ASCII))
+      error ("save: -append and -zip options can only be used together with a text format (-text or -ascii)");
+
     return retval;
   }
 
@@ -1812,6 +1814,103 @@
   return load_save_sys.save (args, nargout);
 }
 
+/*
+## Save and load strings with "-v6"
+%!test
+%! A = A2 = "foobar";  # normal string
+%! B = B2 = "a";  # short string
+%! C = C2 = ["foo"; "bar"];  # character matrix
+%! D = D2 = "ab".';  # short character matrix
+%! E = E2 = {"foo", "bar"};  # cell string
+%! F = F2 = {"Saint Barthélemy", "Saint Kitts and Nevis"};  % non-ASCII
+%! mat_file = [tempname(), ".mat"];
+%! unwind_protect
+%!   save (mat_file, "A", "B", "C", "D", "E", "F", "-v6");
+%!   clear ("A", "B", "C", "D", "E", "F");
+%!   load (mat_file);
+%! unwind_protect_cleanup
+%!   unlink (mat_file);
+%! end_unwind_protect
+%! assert (A, A2);
+%! assert (B, B2);
+%! assert (C, C2);
+%! assert (D, D2);
+%! assert (E, E2);
+%! assert (F, F2);
+
+## Save and load strings with "-v7"
+%!testif HAVE_ZLIB
+%! A = A2 = "foobar";  # normal string
+%! B = B2 = "a";  # short string
+%! C = C2 = ["foo"; "bar"];  # character matrix
+%! D = D2 = "ab".';  # short character matrix
+%! E = E2 = {"foo", "bar"};  # cell string
+%! F = F2 = {"Saint Barthélemy", "Saint Kitts and Nevis"};  # non-ASCII
+%! mat_file = [tempname(), ".mat"];
+%! unwind_protect
+%!   save (mat_file, "A", "B", "C", "D", "E", "F", "-v7");
+%!   clear ("A", "B", "C", "D", "E", "F");
+%!   load (mat_file);
+%! unwind_protect_cleanup
+%!   unlink (mat_file);
+%! end_unwind_protect
+%! assert (A, A2);
+%! assert (B, B2);
+%! assert (C, C2);
+%! assert (D, D2);
+%! assert (E, E2);
+%! assert (F, F2);
+
+## Save and load struct with "-v6"
+%!test
+%! struc.a = "foobar";  # normal string
+%! struc.b = "a";  # short string
+%! struc.c = ["foo"; "bar"];  # character matrix
+%! struc.d = "ab".';  # short character matrix
+%! struc.e = {"foo", "bar"};  # cell string
+%! struc.f = {"Saint Barthélemy", "Saint Kitts and Nevis"};  # non-ASCII
+%! struc.g = [1 2 3];  # double vector
+%! struc.h = 1:5;  # range
+%! struc2 = struc;
+%! mat_file = [tempname(), ".mat"];
+%! unwind_protect
+%!   save (mat_file, "struc", "-v6");
+%!   clear ("struc");
+%!   load (mat_file);
+%! unwind_protect_cleanup
+%!   unlink (mat_file);
+%! end_unwind_protect
+%! assert (struc, struc2);
+
+## Save and load struct with "-v7"
+%!testif HAVE_ZLIB
+%! struc.a = "foobar";  # normal string
+%! struc.b = "a";  # short string
+%! struc.c = ["foo"; "bar"];  # character matrix
+%! struc.d = "ab".';  # short character matrix
+%! struc.e = {"foo", "bar"};  # cell string
+%! struc.f = {"Saint Barthélemy", "Saint Kitts and Nevis"};  # non-ASCII
+%! struc.g = [1 2 3];  # double vector
+%! struc.h = 1:5;  # range
+%! struc2 = struc;
+%! mat_file = [tempname(), ".mat"];
+%! unwind_protect
+%!   save (mat_file, "struc", "-v7");
+%!   clear ("struc");
+%!   load (mat_file);
+%! unwind_protect_cleanup
+%!   unlink (mat_file);
+%! end_unwind_protect
+%! assert (struc, struc2);
+
+## Test input validation
+%!testif HAVE_ZLIB <*59225>
+%! fname = tempname ();
+%! x = 1;
+%! fail ('save ("-append", "-zip", "-binary", fname, "x")',
+%!       "-append and -zip options .* with a text format");
+*/
+
 DEFMETHOD (crash_dumps_octave_core, interp, args, nargout,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {@var{val} =} crash_dumps_octave_core ()
--- a/libinterp/corefcn/load-save.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/load-save.h	Sun May 16 09:44:35 2021 +0200
@@ -73,16 +73,16 @@
         NO_OPTION = 0
       };
 
-    load_save_system (interpreter& interp);
+    OCTINTERP_API load_save_system (interpreter& interp);
 
-    ~load_save_system (void);
+    OCTINTERP_API ~load_save_system (void);
 
     load_save_system (const load_save_system&) = delete;
 
     load_save_system& operator = (const load_save_system&) = delete;
 
-    octave_value crash_dumps_octave_core (const octave_value_list& args,
-                                          int nargout);
+    OCTINTERP_API octave_value
+    crash_dumps_octave_core (const octave_value_list& args, int nargout);
 
     bool crash_dumps_octave_core (void) const
     {
@@ -107,8 +107,8 @@
       return set (m_octave_core_file_limit, limit);
     }
 
-    octave_value octave_core_file_name (const octave_value_list& args,
-                                        int nargout);
+    OCTINTERP_API octave_value
+    octave_core_file_name (const octave_value_list& args, int nargout);
 
     std::string octave_core_file_name (void) const
     {
@@ -120,8 +120,8 @@
       return set (m_octave_core_file_name, file);
     }
 
-    octave_value save_default_options (const octave_value_list& args,
-                                       int nargout);
+    OCTINTERP_API octave_value
+    save_default_options (const octave_value_list& args, int nargout);
 
     std::string save_default_options (void) const
     {
@@ -133,8 +133,8 @@
       return set (m_save_default_options, options);
     }
 
-    octave_value octave_core_file_options (const octave_value_list& args,
-                                           int nargout);
+    OCTINTERP_API octave_value
+    octave_core_file_options (const octave_value_list& args, int nargout);
 
     std::string octave_core_file_options (void) const
     {
@@ -146,8 +146,8 @@
       return set (m_octave_core_file_options, options);
     }
 
-    octave_value save_header_format_string (const octave_value_list& args,
-                                            int nargout);
+    OCTINTERP_API octave_value
+    save_header_format_string (const octave_value_list& args, int nargout);
 
     std::string save_header_format_string (void) const
     {
@@ -159,42 +159,40 @@
       return set (m_save_header_format_string, format);
     }
 
-    static load_save_format get_file_format (const std::string& fname,
-                                             const std::string& orig_fname,
-                                             bool& use_zlib,
-                                             bool quiet = false);
+    static OCTINTERP_API load_save_format
+    get_file_format (const std::string& fname, const std::string& orig_fname,
+                     bool& use_zlib, bool quiet = false);
 
     // FIXME: this is probably not the best public interface for
     // loading and saving variables, but it is what is currently
     // needed for the Fload and Fsave functions.
 
-    octave_value load_vars (std::istream& stream,
-                            const std::string& orig_fname,
-                            const load_save_format& fmt,
-                            mach_info::float_format flt_fmt,
-                            bool list_only, bool swap, bool verbose,
-                            const string_vector& argv, int argv_idx,
-                            int argc, int nargout);
+    OCTINTERP_API octave_value
+    load_vars (std::istream& stream, const std::string& orig_fname,
+               const load_save_format& fmt, mach_info::float_format flt_fmt,
+               bool list_only, bool swap, bool verbose,
+               const string_vector& argv, int argv_idx, int argc, int nargout);
 
-    static string_vector
+    static OCTINTERP_API string_vector
     parse_save_options (const string_vector& argv, load_save_format& fmt,
                         bool& append, bool& save_as_floats, bool& use_zlib);
 
-    static string_vector
+    static OCTINTERP_API string_vector
     parse_save_options (const std::string& arg, load_save_format& fmt,
                         bool& append, bool& save_as_floats, bool& use_zlib);
 
-    void save_vars (const string_vector& argv, int argv_idx, int argc,
-                    std::ostream& os, const load_save_format& fmt,
-                    bool save_as_floats, bool write_header_info);
+    OCTINTERP_API void
+    save_vars (const string_vector& argv, int argv_idx, int argc,
+               std::ostream& os, const load_save_format& fmt,
+               bool save_as_floats, bool write_header_info);
 
-    void dump_octave_core (void);
+    OCTINTERP_API void dump_octave_core (void);
 
-    octave_value_list
+    OCTINTERP_API octave_value_list
     load (const octave_value_list& args = octave_value_list (),
           int nargout = 0);
 
-    octave_value_list
+    OCTINTERP_API octave_value_list
     save (const octave_value_list& args = octave_value_list (),
           int nargout = 0);
 
@@ -225,34 +223,39 @@
     // '#' and contain no newline characters.
     std::string m_save_header_format_string;
 
-    void write_header (std::ostream& os, const load_save_format& fmt);
+    OCTINTERP_API void
+    write_header (std::ostream& os, const load_save_format& fmt);
 
-    std::size_t save_vars (std::ostream& os, const std::string& pattern,
-                           const load_save_format& fmt, bool save_as_floats);
+    OCTINTERP_API std::size_t
+    save_vars (std::ostream& os, const std::string& pattern,
+               const load_save_format& fmt, bool save_as_floats);
 
-    void do_save (std::ostream& os, const octave_value& tc,
-                  const std::string& name, const std::string& help,
-                  bool global, const load_save_format& fmt,
-                  bool save_as_floats);
+    OCTINTERP_API void
+    do_save (std::ostream& os, const octave_value& tc, const std::string& name,
+             const std::string& help, bool global, const load_save_format& fmt,
+             bool save_as_floats);
 
-    void do_save (std::ostream& os, const symbol_info& syminfo,
-                  const load_save_format& fmt, bool save_as_floats);
+    OCTINTERP_API void
+    do_save (std::ostream& os, const symbol_info& syminfo,
+             const load_save_format& fmt, bool save_as_floats);
 
-    std::size_t save_fields (std::ostream& os, const octave_scalar_map& m,
-                             const std::string& pattern,
-                             const load_save_format& fmt, bool save_as_floats);
+    OCTINTERP_API std::size_t
+    save_fields (std::ostream& os, const octave_scalar_map& m,
+                 const std::string& pattern, const load_save_format& fmt,
+                 bool save_as_floats);
 
-    void dump_octave_core (std::ostream& os, const char *fname,
-                           const load_save_format& fmt, bool save_as_floats);
+    OCTINTERP_API void
+    dump_octave_core (std::ostream& os, const char *fname,
+                      const load_save_format& fmt, bool save_as_floats);
 
-    void install_loaded_variable (const std::string& name,
-                                  const octave_value& val,
-                                  bool global, const std::string& /*doc*/);
+    OCTINTERP_API void
+    install_loaded_variable (const std::string& name, const octave_value& val,
+                             bool global, const std::string& /*doc*/);
 
-    static std::string init_save_header_format (void);
+    static OCTINTERP_API std::string init_save_header_format (void);
 
-    static load_save_format get_file_format (std::istream& file,
-                                             const std::string& filename);
+    static OCTINTERP_API load_save_format
+    get_file_format (std::istream& file, const std::string& filename);
 
     template <typename T>
     T set (T& var, const T& new_val)
@@ -290,6 +293,6 @@
   };
 }
 
-extern void dump_octave_core (void);
+extern OCTINTERP_API void dump_octave_core (void);
 
 #endif
--- a/libinterp/corefcn/lookup.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/lookup.cc	Sun May 16 09:44:35 2021 +0200
@@ -120,7 +120,7 @@
               idx.xelem (i) = std::max (zero, std::min (j, n-2));
             }
 
-          retval = idx_vector (idx);
+          retval = octave::idx_vector (idx);
         }
       else if (left_inf)
         {
@@ -132,7 +132,7 @@
               idx.xelem (i) = std::max (zero, j);
             }
 
-          retval = idx_vector (idx);
+          retval = octave::idx_vector (idx);
         }
       else if (right_inf)
         {
--- a/libinterp/corefcn/ls-hdf5.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ls-hdf5.h	Sun May 16 09:44:35 2021 +0200
@@ -53,13 +53,13 @@
 
   ~hdf5_fstreambase () { close (); }
 
-  hdf5_fstreambase (const char *name, int mode, int /* prot */ = 0);
+  OCTINTERP_API hdf5_fstreambase (const char *name, int mode, int /* prot */ = 0);
 
-  void close (void);
+  OCTINTERP_API void close (void);
 
-  void open (const char *name, int mode, int);
+  OCTINTERP_API void open (const char *name, int mode, int);
 
-  void open_create (const char *name, int mode);
+  OCTINTERP_API void open_create (const char *name, int mode);
 };
 
 // input and output streams, subclassing istream and ostream
--- a/libinterp/corefcn/ls-mat-ascii.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ls-mat-ascii.cc	Sun May 16 09:44:35 2021 +0200
@@ -154,7 +154,7 @@
                 {
                   std::istringstream tmp_stream (buf.substr (beg, end-beg));
 
-                  octave_read_double (tmp_stream);
+                  octave::read_value<double> (tmp_stream);
 
                   if (tmp_stream.fail ())
                     {
@@ -285,7 +285,7 @@
         {
           octave_quit ();
 
-          d = octave_read_value<double> (tmp_stream);
+          d = octave::read_value<double> (tmp_stream);
 
           if (! tmp_stream && ! tmp_stream.eof ())
             error ("load: failed to read matrix from file '%s'",
@@ -354,7 +354,7 @@
     {
       m = val.matrix_value (true);
     }
-  catch (const octave::execution_exception& e)
+  catch (const octave::execution_exception&)
     {
       octave::interpreter& interp
         = octave::__get_interpreter__ ("save_mat_ascii_data");
@@ -381,7 +381,7 @@
                 {
                   // Omit leading tabs.
                   if (j != 0) os << '\t';
-                  octave_write_double (os, m(i, j));
+                  octave::write_value<double> (os, m(i, j));
                 }
               os << "\n";
             }
--- a/libinterp/corefcn/ls-mat-ascii.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ls-mat-ascii.h	Sun May 16 09:44:35 2021 +0200
@@ -33,15 +33,15 @@
 
 class octave_value;
 
-extern std::string
+extern OCTINTERP_API std::string
 read_mat_ascii_data (std::istream& is, const std::string& filename,
                      octave_value& tc);
 
-extern bool
+extern OCTINTERP_API bool
 save_mat_ascii_data (std::ostream& os, const octave_value& val_arg,
                      int precision, bool tabs = false);
 
-extern bool looks_like_mat_ascii_file (std::istream& is,
-                                       const std::string& filename);
+extern OCTINTERP_API bool
+looks_like_mat_ascii_file (std::istream& is, const std::string& filename);
 
 #endif
--- a/libinterp/corefcn/ls-mat4.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ls-mat4.cc	Sun May 16 09:44:35 2021 +0200
@@ -430,7 +430,7 @@
       int32_t imag = (tc.iscomplex () ? 1 : 0);
       os.write (reinterpret_cast<char *> (&imag), 4);
 
-      len = nr * nc;
+      len = static_cast<octave_idx_type> (nr) * nc;
     }
 
   // LEN includes the terminating character, and the file is also
@@ -465,9 +465,9 @@
     }
   else if (tc.is_range ())
     {
-      Range r = tc.range_value ();
+      octave::range<double> r = tc.range_value ();
       double base = r.base ();
-      double inc = r.inc ();
+      double inc = r.increment ();
       octave_idx_type nel = r.numel ();
       for (octave_idx_type i = 0; i < nel; i++)
         {
--- a/libinterp/corefcn/ls-mat4.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ls-mat4.h	Sun May 16 09:44:35 2021 +0200
@@ -34,22 +34,22 @@
 
 class octave_value;
 
-extern octave::mach_info::float_format
+extern OCTINTERP_API octave::mach_info::float_format
 mopt_digit_to_float_format (int mach);
 
-extern int
+extern OCTINTERP_API int
 float_format_to_mopt_digit (octave::mach_info::float_format flt_fmt);
 
-extern int
+extern OCTINTERP_API int
 read_mat_file_header (std::istream& is, bool& swap, int32_t& mopt,
                       int32_t& nr, int32_t& nc, int32_t& imag,
                       int32_t& len, int quiet = 0);
 
-extern std::string
+extern OCTINTERP_API std::string
 read_mat_binary_data (std::istream& is, const std::string& filename,
                       octave_value& tc);
 
-extern bool
+extern OCTINTERP_API bool
 save_mat_binary_data (std::ostream& os, const octave_value& tc,
                       const std::string& name);
 
--- a/libinterp/corefcn/ls-mat5.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ls-mat5.cc	Sun May 16 09:44:35 2021 +0200
@@ -50,6 +50,7 @@
 #include "oct-time.h"
 #include "quit.h"
 #include "str-vec.h"
+#include "unistr-wrappers.h"
 
 #include "Cell.h"
 #include "defaults.h"
@@ -528,9 +529,10 @@
       // We uncompress the first 8 bytes of the header to get the buffer length
       // This will fail with an error Z_MEM_ERROR
       uLongf destLen = 8;
+      uLongf elt_len = element_length;
       OCTAVE_LOCAL_BUFFER (unsigned int, tmp, 2);
-      if (uncompress (reinterpret_cast<Bytef *> (tmp), &destLen,
-                      reinterpret_cast<Bytef *> (inbuf), element_length)
+      if (uncompress2 (reinterpret_cast<Bytef *> (tmp), &destLen,
+                       reinterpret_cast<Bytef *> (inbuf), &elt_len)
           == Z_MEM_ERROR)
         error ("load: error probing size of compressed data element");
 
@@ -543,10 +545,19 @@
 
       // FIXME: find a way to avoid casting away const here!
 
-      int err = uncompress (reinterpret_cast<Bytef *>
-                            (const_cast<char *> (outbuf.c_str ())),
-                            &destLen, reinterpret_cast<Bytef *> (inbuf),
-                            element_length);
+      elt_len = element_length;
+      int err = uncompress2 (reinterpret_cast<Bytef *>
+                             (const_cast<char *> (outbuf.c_str ())),
+                             &destLen, reinterpret_cast<Bytef *> (inbuf),
+                             &elt_len);
+
+      // Ignore buffer error if we have consumed all the input buffer
+      // and uncompressing the data generated as many bytes of output as
+      // we were expecting given the data element size that was stored
+      // in the Matlab data element header.
+      if (err == Z_BUF_ERROR && destLen == tmp[1] + 8
+          && elt_len == static_cast<uLongf> (element_length))
+        err = Z_OK;
 
       if (err != Z_OK)
         {
@@ -1417,58 +1428,84 @@
 
             tc = ctmp;
           }
-        else
+        else if (arrayclass == MAT_FILE_CHAR_CLASS)
           {
-            if (arrayclass == MAT_FILE_CHAR_CLASS)
+            bool converted = false;
+            if (re.isvector () && (type == miUTF16 || type == miUINT16))
               {
-                if (type == miUTF16 || type == miUTF32)
-                  {
-                    bool found_big_char = false;
-                    for (octave_idx_type i = 0; i < n; i++)
-                      {
-                        if (re(i) > 127)
-                          {
-                            re(i) = '?';
-                            found_big_char = true;
-                          }
-                      }
-
-                    if (found_big_char)
-                      warning_with_id ("Octave:load:unsupported-utf-char",
-                               "load: can not read non-ASCII portions of UTF characters; replacing unreadable characters with '?'");
-                  }
-                else if (type == miUTF8)
+                uint16NDArray u16 = re;
+                const uint16_t *u16_str
+                  = reinterpret_cast<const uint16_t *> (u16.data ());
+
+                // Convert to UTF-8.
+                std::size_t n8;
+                uint8_t *u8_str = octave_u16_to_u8_wrapper (u16_str,
+                                                            u16.numel (),
+                                                            nullptr, &n8);
+                if (u8_str)
                   {
-                    // Search for multi-byte encoded UTF8 characters and
-                    // replace with 0x3F for '?'...  Give the user a warning
-
-                    bool utf8_multi_byte = false;
-                    for (octave_idx_type i = 0; i < n; i++)
+                    // FIXME: Is there a better way to construct a charMatrix
+                    // from a non zero terminated buffer?
+                    tc = charMatrix (std::string (reinterpret_cast<char *> (u8_str), n8));
+                    free (u8_str);
+                    converted = true;
+                  }
+              }
+            else if (re.isvector () && (type == miUTF32 || type == miUINT32))
+              {
+                uint32NDArray u32 = re;
+                const uint32_t *u32_str
+                  = reinterpret_cast<const uint32_t *> (u32.data ());
+
+                // Convert to UTF-8.
+                std::size_t n8;
+                uint8_t *u8_str = octave_u32_to_u8_wrapper (u32_str,
+                                                            u32.numel (),
+                                                            nullptr, &n8);
+                if (u8_str)
+                  {
+                    // FIXME: Is there a better way to construct a charMatrix
+                    // from a non zero terminated buffer?
+                    tc = charMatrix (std::string (reinterpret_cast<char *> (u8_str), n8));
+                    free (u8_str);
+                    converted = true;
+                  }
+              }
+            else if (type == miUTF8 || type == miUINT8)
+              {
+                // Octave's internal encoding is UTF-8.  So we should be
+                // able to use this natively.
+                tc = re;
+                tc = tc.convert_to_str (false, true, '\'');
+                converted = true;
+              }
+
+            if (! converted)
+              {
+                // Fall back to manually replacing non-ASCII
+                // characters by "?".
+                bool found_big_char = false;
+                for (octave_idx_type i = 0; i < n; i++)
+                  {
+                    if (re(i) > 127)
                       {
-                        unsigned char a = static_cast<unsigned char> (re(i));
-                        if (a > 0x7f)
-                          utf8_multi_byte = true;
-                      }
-
-                    if (utf8_multi_byte)
-                      {
-                        warning_with_id ("Octave:load:unsupported-utf-char",
-                                         "load: can not read multi-byte encoded UTF8 characters; replacing unreadable characters with '?'");
-                        for (octave_idx_type i = 0; i < n; i++)
-                          {
-                            unsigned char a
-                              = static_cast<unsigned char> (re(i));
-                            if (a > 0x7f)
-                              re(i) = '?';
-                          }
+                        re(i) = '?';
+                        found_big_char = true;
                       }
                   }
+
+                if (found_big_char)
+                  warning_with_id ("Octave:load:unsupported-utf-char",
+                    "load: failed to convert from input to UTF-8; "
+                    "replacing non-ASCII characters with '?'");
+
                 tc = re;
                 tc = tc.convert_to_str (false, true, '\'');
               }
-            else
-              tc = re;
+
           }
+        else
+          tc = re;
       }
     }
 
@@ -2070,6 +2107,24 @@
   return ret;
 }
 
+static uint16_t *
+maybe_convert_to_u16 (const charNDArray& chm, std::size_t& n16_str)
+{
+  uint16_t *u16_str;
+  dim_vector dv = chm.dims ();
+
+  if (chm.ndims () == 2 && dv(0) == 1)
+    {
+      const uint8_t *u8_str = reinterpret_cast<const uint8_t *> (chm.data ());
+      u16_str = octave_u8_to_u16_wrapper (u8_str, chm.numel (),
+                                          nullptr, &n16_str);
+    }
+  else
+    u16_str = nullptr;
+
+  return u16_str;
+}
+
 int
 save_mat5_element_length (const octave_value& tc, const std::string& name,
                           bool save_as_floats, bool mat7_format)
@@ -2087,9 +2142,25 @@
   if (tc.is_string ())
     {
       charNDArray chm = tc.char_array_value ();
+      // convert to UTF-16
+      std::size_t n16_str;
+      uint16_t *u16_str = maybe_convert_to_u16 (chm, n16_str);
       ret += 8;
-      if (chm.numel () > 2)
-        ret += PAD (2 * chm.numel ());
+
+      octave_idx_type str_len;
+      std::size_t sz_of = 1;
+      if (u16_str)
+        {
+          free (u16_str);
+          // Count number of elements in converted string
+          str_len = n16_str;
+          sz_of = 2;
+        }
+      else
+        str_len = chm.numel ();
+
+      if (str_len > 2)
+        ret += PAD (sz_of * str_len);
     }
   else if (tc.issparse ())
     {
@@ -2206,7 +2277,6 @@
 
       for (octave_idx_type j = 0; j < nel; j++)
         {
-
           for (auto i = m.begin (); i != m.end (); i++)
             {
               const Cell elts = m.contents (i);
@@ -2414,15 +2484,36 @@
 
   write_mat5_tag (os, miINT32, dim_len);
 
-  for (int i = 0; i < nd; i++)
+  // Strings need to be converted here (or dim-vector will be off).
+  charNDArray chm;
+  uint16_t *u16_str;
+  std::size_t n16_str;
+  bool conv_u16 = false;
+  if (tc.is_string ())
     {
-      int32_t n = dv(i);
+      chm = tc.char_array_value ();
+      u16_str = maybe_convert_to_u16 (chm, n16_str);
+
+      if (u16_str)
+        conv_u16 = true;
+    }
+
+  if (conv_u16)
+    {
+      int32_t n = 1;
       os.write (reinterpret_cast<char *> (&n), 4);
+      os.write (reinterpret_cast<char *> (&n16_str), 4);
     }
+  else
+    for (int i = 0; i < nd; i++)
+      {
+        int32_t n = dv(i);
+        os.write (reinterpret_cast<char *> (&n), 4);
+      }
 
   if (PAD (dim_len) > dim_len)
     {
-      static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
+      static char buf[9] = "\x00\x00\x00\x00\x00\x00\x00\x00";
       os.write (buf, PAD (dim_len) - dim_len);
     }
 
@@ -2445,24 +2536,35 @@
   // data element
   if (tc.is_string ())
     {
-      charNDArray chm = tc.char_array_value ();
-      octave_idx_type nel = chm.numel ();
-      octave_idx_type len = nel*2;
-      octave_idx_type paddedlength = PAD (len);
-
-      OCTAVE_LOCAL_BUFFER (int16_t, buf, nel+3);
-      write_mat5_tag (os, miUINT16, len);
-
-      const char *s = chm.data ();
-
-      for (octave_idx_type i = 0; i < nel; i++)
-        buf[i] = *s++ & 0x00FF;
-
-      os.write (reinterpret_cast<char *> (buf), len);
+      octave_idx_type len;
+      octave_idx_type paddedlength;
+
+      if (conv_u16)
+        {
+          // converted UTF-16
+          len = n16_str*2;
+          paddedlength = PAD (len);
+
+          write_mat5_tag (os, miUTF16, len);
+
+          os.write (reinterpret_cast<char *> (u16_str), len);
+
+          free (u16_str);
+        }
+      else
+        {
+          // write as UTF-8
+          len = chm.numel ();
+          paddedlength = PAD (len);
+
+          write_mat5_tag (os, miUTF8, len);
+
+          os.write (chm.data (), len);
+        }
 
       if (paddedlength > len)
         {
-          static char padbuf[9]="\x00\x00\x00\x00\x00\x00\x00\x00";
+          static char padbuf[9] = "\x00\x00\x00\x00\x00\x00\x00\x00";
           os.write (padbuf, paddedlength - len);
         }
     }
--- a/libinterp/corefcn/ls-mat5.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ls-mat5.h	Sun May 16 09:44:35 2021 +0200
@@ -55,14 +55,14 @@
   miUTF32                     // Unicode UTF-32 Encoded Character Data
 };
 
-extern int
+extern OCTINTERP_API int
 read_mat5_binary_file_header (std::istream& is, bool& swap,
                               bool quiet = false,
                               const std::string& filename = "");
-extern std::string
+extern OCTINTERP_API std::string
 read_mat5_binary_element (std::istream& is, const std::string& filename,
                           bool swap, bool& global, octave_value& tc);
-extern bool
+extern OCTINTERP_API bool
 save_mat5_binary_element (std::ostream& os,
                           const octave_value& tc, const std::string& name,
                           bool mark_global, bool mat7_format,
--- a/libinterp/corefcn/ls-utils.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ls-utils.h	Sun May 16 09:44:35 2021 +0200
@@ -30,10 +30,10 @@
 
 #include "data-conv.h"
 
-extern save_type
+extern OCTINTERP_API save_type
 get_save_type (double max_val, double min_val);
 
-extern save_type
+extern OCTINTERP_API save_type
 get_save_type (float max_val, float min_val);
 
 #endif
--- a/libinterp/corefcn/lsode.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/lsode.cc	Sun May 16 09:44:35 2021 +0200
@@ -79,9 +79,9 @@
         {
           tmp = octave::feval (lsode_fcn, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "lsode");
+          err_user_supplied_eval (ee, "lsode");
         }
 
       if (tmp.empty () || ! tmp(0).is_defined ())
@@ -119,9 +119,9 @@
         {
           tmp = octave::feval (lsode_jac, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "lsode");
+          err_user_supplied_eval (ee, "lsode");
         }
 
       if (tmp.empty () || ! tmp(0).is_defined ())
@@ -269,9 +269,7 @@
   warned_fcn_imaginary = false;
   warned_jac_imaginary = false;
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/lu.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/lu.cc	Sun May 16 09:44:35 2021 +0200
@@ -801,15 +801,15 @@
 %! [L,U,P] = lu (A);
 %! [~,ordcols] = max (P,[],1);
 %! [~,ordrows] = max (P,[],2);
-%! P1 = eye (size(P))(:,ordcols);
-%! P2 = eye (size(P))(ordrows,:);
-%! assert(P1 == P);
-%! assert(P2 == P);
+%! P1 = eye (size (P))(:,ordcols);
+%! P2 = eye (size (P))(ordrows,:);
+%! assert (P1 == P);
+%! assert (P2 == P);
 %! [L,U,P] = luupdate (L,U,P,u,v);
 %! [L,U,P1] = luupdate (L,U,P1,u,v);
 %! [L,U,P2] = luupdate (L,U,P2,u,v);
-%! assert(P1 == P);
-%! assert(P2 == P);
+%! assert (P1 == P);
+%! assert (P2 == P);
 %!
 %!testif HAVE_QRUPDATE_LUU
 %! [L,U,P] = lu (Ac);
--- a/libinterp/corefcn/mappers.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/mappers.cc	Sun May 16 09:44:35 2021 +0200
@@ -133,7 +133,7 @@
 %! v = [0, pi, pi/2, pi/2];
 %! assert (real (acos (x)), v);
 
-%!xtest <52627>
+%!test <52627>
 %! ## Same test code as above, but intended only for test statistics on Mac and
 %! ## Windows.  Their trig/hyperbolic functions have huge tolerances.
 %! if (! ismac () && ! ispc ()), return; endif
@@ -164,7 +164,7 @@
 %! v = [0, pi/2*i, pi*i, pi/2*i];
 %! assert (acosh (x), v, sqrt (eps));
 
-%!xtest <*52627>
+%!test <52627>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! ## Mac trig/hyperbolic functions have huge tolerances.
 %! if (! ismac ()), return; endif
@@ -187,7 +187,7 @@
 %! v = single ([0, pi/2*i, pi*i, pi/2*i]);
 %! assert (acosh (x), v, sqrt (eps ("single")));
 
-%!xtest <*52627>
+%!test <52627>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! ## Mac trig/hyperbolic functions have huge tolerances.
 %! if (! ismac ()), return; endif
@@ -208,7 +208,7 @@
 %! v = [0, pi, pi/2, -pi/2];
 %! assert (imag (acosh (x)), v);
 
-%!xtest <52627>
+%!test <52627>
 %! ## Same test code as above, but intended only for test statistics on Mac and
 %! ## Windows.  Their trig/hyperbolic functions have huge tolerances.
 %! if (! ismac () && ! ispc ()), return; endif
@@ -223,7 +223,7 @@
 DEFUN (angle, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} angle (@var{z})
-See @code{arg}.
+@xref{XREFarg,,@code{arg}}.
 @seealso{arg}
 @end deftypefn */)
 {
@@ -336,7 +336,7 @@
 %! v = [pi/2, -pi/2, 0, -0];
 %! assert (real (asin (x)), v);
 
-%!xtest <52627>
+%!test <52627>
 %! ## Same test code as above, but intended only for test statistics on Mac and
 %! ## Windows. Their trig/hyperbolic functions have huge tolerances.
 %! if (! ismac () && ! ispc ()), return; endif
@@ -379,7 +379,7 @@
 %! v = [0, 0, pi/2, -pi/2];
 %! assert (imag (asinh (x)), v);
 
-%!xtest <52627>
+%!test <52627>
 %! ## Same test code as above, but intended only for test statistics on Mac and
 %! ## Windows.  Their trig/hyperbolic functions have huge tolerances.
 %! if (! ismac () && ! ispc ()), return; endif
@@ -841,7 +841,7 @@
 
 %!test
 %! x = [1+2i,-1+2i,1e-6+2e-6i,0+2i];
-%! assert (erfcx (x), exp (x.^2) .* erfc(x), -1.e-10);
+%! assert (erfcx (x), exp (x.^2) .* erfc (x), -1.e-10);
 
 %!test
 %! x = [100, 100+20i];
@@ -883,7 +883,7 @@
 
 %!test
 %! x = [-0.1, 0.1, 1, 1+2i,-1+2i,1e-6+2e-6i,0+2i];
-%! assert (erfi (x), -i * erf(i*x), -1.e-10);
+%! assert (erfi (x), -i * erf (i*x), -1.e-10);
 
 %!error erfi ()
 %!error erfi (1, 2)
@@ -1216,7 +1216,7 @@
 %! result(double ("0":"9") + 1) = true;
 %! result(double ("a":"z") + 1) = true;
 %! assert (isalnum (charset), result);
-%!assert (isalnum(["Ä8Aa?"; "(Uß ;"]), logical ([1 1 1 1 1 0; 0 1 1 1 0 0]));
+%!assert (isalnum(["Ä8Aa?"; "(Uß ;"]), logical ([1 1 1 1 1 0; 0 1 1 1 0 0]))
 
 %!error isalnum ()
 %!error isalnum (1, 2)
@@ -1245,7 +1245,7 @@
 %! result(double ("A":"Z") + 1) = true;
 %! result(double ("a":"z") + 1) = true;
 %! assert (isalpha (charset), result);
-%!assert (isalpha("Ä8Aa(Uß ;"), logical ([1 1 0 1 1 0 1 1 1 0 0]));
+%!assert (isalpha("Ä8Aa(Uß ;"), logical ([1 1 0 1 1 0 1 1 1 0 0]))
 
 %!error isalpha ()
 %!error isalpha (1, 2)
@@ -1321,7 +1321,7 @@
 %! result = false (1, 128);
 %! result(double ("0":"9") + 1) = true;
 %! assert (isdigit (charset), result);
-%!assert (isdigit("Ä8Aa(Uß ;"), logical ([0 0 1 0 0 0 0 0 0 0 0]));
+%!assert (isdigit("Ä8Aa(Uß ;"), logical ([0 0 1 0 0 0 0 0 0 0 0]))
 
 %!error isdigit ()
 %!error isdigit (1, 2)
@@ -1388,7 +1388,7 @@
 %! result = false (1, 128);
 %! result(34:127) = true;
 %! assert (isgraph (charset), result);
-%!assert (isgraph("Ä8Aa(Uß ;"), logical ([1 1 1 1 1 1 1 1 1 0 1]));
+%!assert (isgraph("Ä8Aa(Uß ;"), logical ([1 1 1 1 1 1 1 1 1 0 1]))
 
 %!error isgraph ()
 %!error isgraph (1, 2)
@@ -1414,7 +1414,7 @@
 %! result = false (1, 128);
 %! result(double ("a":"z") + 1) = true;
 %! assert (islower (charset), result);
-%!assert (islower("Ä8Aa(Uß ;"), logical ([0 0 0 0 1 0 0 1 1 0 0]));
+%!assert (islower("Ä8Aa(Uß ;"), logical ([0 0 0 0 1 0 0 1 1 0 0]))
 
 %!error islower ()
 %!error islower (1, 2)
@@ -1521,7 +1521,7 @@
 %! result = false (1, 128);
 %! result(33:127) = true;
 %! assert (isprint (charset), result);
-%!assert (isprint("Ä8Aa(Uß ;"), logical ([1 1 1 1 1 1 1 1 1 1 1]));
+%!assert (isprint("Ä8Aa(Uß ;"), logical ([1 1 1 1 1 1 1 1 1 1 1]))
 
 %!error isprint ()
 %!error isprint (1, 2)
@@ -1550,7 +1550,7 @@
 %! result(92:97) = true;
 %! result(124:127) = true;
 %! assert (ispunct (charset), result);
-%!assert (ispunct("Ä8Aa(Uß ;"), logical ([0 0 0 0 0 1 0 0 0 0 1]));
+%!assert (ispunct("Ä8Aa(Uß ;"), logical ([0 0 0 0 0 1 0 0 0 0 1]))
 
 %!error ispunct ()
 %!error ispunct (1, 2)
@@ -1577,7 +1577,7 @@
 %! result = false (1, 128);
 %! result(double (" \f\n\r\t\v") + 1) = true;
 %! assert (isspace (charset), result);
-%!assert (isspace("Ä8Aa(Uß ;"), logical ([0 0 0 0 0 0 0 0 0 1 0]));
+%!assert (isspace("Ä8Aa(Uß ;"), logical ([0 0 0 0 0 0 0 0 0 1 0]))
 
 %!error isspace ()
 %!error isspace (1, 2)
@@ -1603,7 +1603,7 @@
 %! result = false (1, 128);
 %! result(double ("A":"Z") + 1) = true;
 %! assert (isupper (charset), result);
-%!assert (isupper("Ä8Aa(Uß ;"), logical ([1 1 0 1 0 0 1 0 0 0 0]));
+%!assert (isupper("Ä8Aa(Uß ;"), logical ([1 1 0 1 0 0 1 0 0 0 0]))
 
 %!error isupper ()
 %!error isupper (1, 2)
@@ -1631,7 +1631,7 @@
 %! result(double ("0":"9") + 1) = true;
 %! result(double ("a":"f") + 1) = true;
 %! assert (isxdigit (charset), result);
-%!assert (isxdigit("Ä8Aa(Uß ;"), logical ([0 0 1 1 1 0 0 0 0 0 0]));
+%!assert (isxdigit("Ä8Aa(Uß ;"), logical ([0 0 1 1 1 0 0 0 0 0 0]))
 
 %!error isxdigit ()
 %!error isxdigit (1, 2)
--- a/libinterp/corefcn/matrix_type.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/matrix_type.cc	Sun May 16 09:44:35 2021 +0200
@@ -540,10 +540,10 @@
 %! a = matrix_type (spdiags (randn (10,3),[-1,0,1],10,10), "Singular");
 %! assert (matrix_type (a), "Singular");
 
-%!assert (matrix_type (triu (ones(10,10))), "Upper")
-%!assert (matrix_type (triu (ones(10,10),-1)), "Full")
-%!assert (matrix_type (tril (ones(10,10))), "Lower")
-%!assert (matrix_type (tril (ones(10,10),1)), "Full")
+%!assert (matrix_type (triu (ones (10,10))), "Upper")
+%!assert (matrix_type (triu (ones (10,10),-1)), "Full")
+%!assert (matrix_type (tril (ones (10,10))), "Lower")
+%!assert (matrix_type (tril (ones (10,10),1)), "Full")
 %!assert (matrix_type (10*eye (10,10) + ones (10,10)), "Positive Definite")
 %!assert (matrix_type (ones (11,10)), "Rectangular")
 %!test
--- a/libinterp/corefcn/max.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/max.cc	Sun May 16 09:44:35 2021 +0200
@@ -269,7 +269,7 @@
           {
             if (arg.is_range () && (dim == -1 || dim == 1))
               {
-                Range range = arg.range_value ();
+                octave::range<double> range = arg.range_value ();
                 if (range.numel () < 1)
                   {
                     retval(0) = arg;
@@ -281,14 +281,14 @@
                     retval(0) = range.min ();
                     if (nargout > 1)
                       retval(1) = static_cast<double>
-                                  (range.inc () < 0 ? range.numel () : 1);
+                                  (range.increment () < 0 ? range.numel () : 1);
                   }
                 else
                   {
                     retval(0) = range.max ();
                     if (nargout > 1)
                       retval(1) = static_cast<double>
-                                  (range.inc () >= 0 ? range.numel () : 1);
+                                  (range.increment () >= 0 ? range.numel () : 1);
                   }
               }
             else if (arg.issparse ())
--- a/libinterp/corefcn/mex.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/mex.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,6 +62,197 @@
 #include "variables.h"
 #include "graphics.h"
 
+// These must be declared extern "C" but may be omitted from the set of
+// symbols declared in mexproto.h, so we declare them here as well.
+
+extern "C"
+{
+  extern OCTINTERP_API const mxArray *
+  mexGet_interleaved (double handle, const char *property);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCellArray (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCellMatrix (mwSize m, mwSize n);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCharArray (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCharMatrixFromStrings (mwSize m, const char **str);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateDoubleMatrix (mwSize nr, mwSize nc, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateDoubleScalar (double val);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalArray (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalMatrix (mwSize m, mwSize n);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalScalar (mxLogical val);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id,
+                        mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id,
+                         mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateUninitNumericArray (mwSize ndims, const mwSize *dims,
+                              mxClassID class_id, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateUninitNumericMatrix (mwSize m, mwSize n, mxClassID class_id,
+                               mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateString (const char *str);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys,
+                       const char **keys);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateStructMatrix (mwSize rows, mwSize cols, int num_keys,
+                        const char **keys);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCellArray_interleaved (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCellMatrix_interleaved (mwSize m, mwSize n);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCharArray_interleaved (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateCharMatrixFromStrings_interleaved (mwSize m, const char **str);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateDoubleMatrix_interleaved (mwSize nr, mwSize nc, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateDoubleScalar_interleaved (double val);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalArray_interleaved (mwSize ndims, const mwSize *dims);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalMatrix_interleaved (mwSize m, mwSize n);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateLogicalScalar_interleaved (mxLogical val);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateNumericArray_interleaved (mwSize ndims, const mwSize *dims,
+                                    mxClassID class_id, mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateNumericMatrix_interleaved (mwSize m, mwSize n, mxClassID class_id,
+                                     mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateUninitNumericArray_interleaved (mwSize ndims, const mwSize *dims,
+                                          mxClassID class_id,
+                                          mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateUninitNumericMatrix_interleaved (mwSize m, mwSize n,
+                                           mxClassID class_id,
+                                           mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateSparse_interleaved (mwSize m, mwSize n, mwSize nzmax,
+                              mxComplexity flag);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateSparseLogicalMatrix_interleaved (mwSize m, mwSize n, mwSize nzmax);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateString_interleaved (const char *str);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateStructArray_interleaved (mwSize ndims, const mwSize *dims,
+                                   int num_keys, const char **keys);
+
+  extern OCTINTERP_API mxArray *
+  mxCreateStructMatrix_interleaved (mwSize rows, mwSize cols, int num_keys,
+                                    const char **keys);
+
+  extern OCTINTERP_API int mxMakeArrayReal (mxArray *ptr);
+  extern OCTINTERP_API int mxMakeArrayComplex (mxArray *ptr);
+
+  extern OCTINTERP_API mxDouble * mxGetDoubles (const mxArray *p);
+  extern OCTINTERP_API mxSingle * mxGetSingles (const mxArray *p);
+  extern OCTINTERP_API mxInt8 * mxGetInt8s (const mxArray *p);
+  extern OCTINTERP_API mxInt16 * mxGetInt16s (const mxArray *p);
+  extern OCTINTERP_API mxInt32 * mxGetInt32s (const mxArray *p);
+  extern OCTINTERP_API mxInt64 * mxGetInt64s (const mxArray *p);
+  extern OCTINTERP_API mxUint8 * mxGetUint8s (const mxArray *p);
+  extern OCTINTERP_API mxUint16 * mxGetUint16s (const mxArray *p);
+  extern OCTINTERP_API mxUint32 * mxGetUint32s (const mxArray *p);
+  extern OCTINTERP_API mxUint64 * mxGetUint64s (const mxArray *p);
+
+  extern OCTINTERP_API mxComplexDouble * mxGetComplexDoubles (const mxArray *p);
+  extern OCTINTERP_API mxComplexSingle * mxGetComplexSingles (const mxArray *p);
+#if 0
+  /* We don't have these yet. */
+  extern OCTINTERP_API mxComplexInt8 * mxGetComplexInt8s (const mxArray *p);
+  extern OCTINTERP_API mxComplexInt16 * mxGetComplexInt16s (const mxArray *p);
+  extern OCTINTERP_API mxComplexInt32 * mxGetComplexInt32s (const mxArray *p);
+  extern OCTINTERP_API mxComplexInt64 * mxGetComplexInt64s (const mxArray *p);
+  extern OCTINTERP_API mxComplexUint8 * mxGetComplexUint8s (const mxArray *p);
+  extern OCTINTERP_API mxComplexUint16 * mxGetComplexUint16s (const mxArray *p);
+  extern OCTINTERP_API mxComplexUint32 * mxGetComplexUint32s (const mxArray *p);
+  extern OCTINTERP_API mxComplexUint64 * mxGetComplexUint64s (const mxArray *p);
+#endif
+
+  extern OCTINTERP_API double * mxGetPi (const mxArray *ptr);
+  extern OCTINTERP_API void * mxGetImagData (const mxArray *ptr);
+
+  extern OCTINTERP_API int mxSetDoubles (mxArray *p, mxDouble *d);
+  extern OCTINTERP_API int mxSetSingles (mxArray *p, mxSingle *d);
+  extern OCTINTERP_API int mxSetInt8s (mxArray *p, mxInt8 *d);
+  extern OCTINTERP_API int mxSetInt16s (mxArray *p, mxInt16 *d);
+  extern OCTINTERP_API int mxSetInt32s (mxArray *p, mxInt32 *d);
+  extern OCTINTERP_API int mxSetInt64s (mxArray *p, mxInt64 *d);
+  extern OCTINTERP_API int mxSetUint8s (mxArray *p, mxUint8 *d);
+  extern OCTINTERP_API int mxSetUint16s (mxArray *p, mxUint16 *d);
+  extern OCTINTERP_API int mxSetUint32s (mxArray *p, mxUint32 *d);
+  extern OCTINTERP_API int mxSetUint64s (mxArray *p, mxUint64 *d);
+
+  extern OCTINTERP_API int mxSetComplexDoubles (mxArray *p, mxComplexDouble *d);
+  extern OCTINTERP_API int mxSetComplexSingles (mxArray *p, mxComplexSingle *d);
+#if 0
+  /* We don't have these yet. */
+  extern OCTINTERP_API int mxSetComplexInt8s (mxArray *p, mxComplexInt8 *d);
+  extern OCTINTERP_API int mxSetComplexInt16s (mxArray *p, mxComplexInt16 *d);
+  extern OCTINTERP_API int mxSetComplexInt32s (mxArray *p, mxComplexInt32 *d);
+  extern OCTINTERP_API int mxSetComplexInt64s (mxArray *p, mxComplexInt64 *d);
+  extern OCTINTERP_API int mxSetComplexUint8s (mxArray *p, mxComplexUint8 *d);
+  extern OCTINTERP_API int mxSetComplexUint16s (mxArray *p, mxComplexUint16 *d);
+  extern OCTINTERP_API int mxSetComplexUint32s (mxArray *p, mxComplexUint32 *d);
+  extern OCTINTERP_API int mxSetComplexUint64s (mxArray *p, mxComplexUint64 *d);
+#endif
+
+  extern OCTINTERP_API void mxSetPi (mxArray *ptr, double *pi);
+  extern OCTINTERP_API void mxSetImagData (mxArray *ptr, void *pi);
+}
+
 // #define DEBUG 1
 
 static void
@@ -112,6 +303,10 @@
 
 // ------------------------------------------------------------------
 
+mxArray_base::mxArray_base (bool interleaved)
+  : m_interleaved (interleaved)
+{ }
+
 static mwIndex
 calc_single_subscript_internal (mwSize ndims, const mwSize *dims,
                                 mwSize nsubs, const mwIndex *subs)
@@ -157,13 +352,26 @@
 
 static inline void * maybe_mark_foreign (void *ptr);
 
+#define VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST)        \
+  void FCN_NAME ARG_LIST { request_mutation (); }
+
+#define CONST_VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST)  \
+  void FCN_NAME ARG_LIST const { request_mutation (); }
+
+#define MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL)          \
+  RET_TYPE FCN_NAME ARG_LIST { request_mutation (); return RET_VAL; }
+
+#define CONST_MUTATION_METHOD(RET_TYPE, FCN_NAME, ARG_LIST, RET_VAL)    \
+  RET_TYPE FCN_NAME ARG_LIST const { request_mutation (); return RET_VAL; }
+
 class mxArray_octave_value : public mxArray_base
 {
 public:
 
-  mxArray_octave_value (const octave_value& ov)
-    : mxArray_base (), val (ov), mutate_flag (false),
-      id (mxUNKNOWN_CLASS), class_name (nullptr), ndims (-1), dims (nullptr) { }
+  mxArray_octave_value (bool interleaved, const octave_value& ov)
+    : mxArray_base (interleaved), val (ov), mutate_flag (false),
+      id (mxUNKNOWN_CLASS), class_name (nullptr), ndims (-1), dims (nullptr)
+  { }
 
   // No assignment!  FIXME: should this be implemented?  Note that we
   // do have a copy constructor.
@@ -174,7 +382,7 @@
 
   mxArray * as_mxArray (void) const
   {
-    mxArray *retval = val.as_mxArray ();
+    mxArray *retval = val.as_mxArray (m_interleaved);
 
     // RETVAL is assumed to be an mxArray_matlab object.  Should we
     // assert that condition here?
@@ -303,16 +511,10 @@
     return ndims;
   }
 
-  void set_m (mwSize /*m*/) { request_mutation (); }
-
-  void set_n (mwSize /*n*/) { request_mutation (); }
-
-  int set_dimensions (mwSize * /*dims_arg*/, mwSize /*ndims_arg*/)
-  {
-    request_mutation ();
-
-    return 0;
-  }
+  VOID_MUTATION_METHOD (set_m, (mwSize))
+  VOID_MUTATION_METHOD (set_n, (mwSize))
+
+  MUTATION_METHOD (int, set_dimensions, (mwSize *, mwSize), 0)
 
   mwSize get_number_of_elements (void) const { return val.numel (); }
 
@@ -378,7 +580,7 @@
   }
 
   // Not allowed.
-  void set_class_name (const char * /*name_arg*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_class_name, (const char *))
 
   mxArray * get_property (mwIndex idx, const char *pname) const
   {
@@ -393,7 +595,7 @@
             octave_value pval = ov_cdef->get_property (idx, pname);
 
             if (pval.is_defined())
-              retval = new mxArray (pval);
+              retval = new mxArray (m_interleaved, pval);
           }
       }
 
@@ -410,17 +612,13 @@
           ov_cdef->set_property (idx, pname, pval->as_octave_value ());
       }
     else
-      err_invalid_type ();
+      err_invalid_type ("set_property");
   }
 
-  mxArray * get_cell (mwIndex /*idx*/) const
-  {
-    request_mutation ();
-    return nullptr;
-  }
+  CONST_MUTATION_METHOD (mxArray *, get_cell, (mwIndex), nullptr)
 
   // Not allowed.
-  void set_cell (mwIndex /*idx*/, mxArray * /*val*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_cell, (mwIndex, mxArray *))
 
   double get_scalar (void) const
   {
@@ -454,6 +652,61 @@
     return retval;
   }
 
+  template <typename T>
+  T * get_data (mxClassID class_id, mxComplexity complexity) const
+  {
+    T *retval = static_cast<T *> (val.mex_get_data (class_id, complexity));
+
+    if (retval)
+      maybe_mark_foreign (retval);
+    else
+      request_mutation ();
+
+    return retval;
+  }
+
+  CONST_MUTATION_METHOD (mxDouble *, get_doubles, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxSingle *, get_singles, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxInt8 *, get_int8s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxInt16 *, get_int16s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxInt32 *, get_int32s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxInt64 *, get_int64s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxUint8 *, get_uint8s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxUint16 *, get_uint16s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxUint32 *, get_uint32s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxUint64 *, get_uint64s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexDouble *, get_complex_doubles, (void), nullptr);
+  CONST_MUTATION_METHOD (mxComplexSingle *, get_complex_singles, (void), nullptr);
+
+#if 0
+  /* We don't have these yet. */
+  CONST_MUTATION_METHOD (mxComplexInt8 *, get_complex_int8s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexInt16 *, get_complex_int16s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexInt32 *, get_complex_int32s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexInt64 *, get_complex_int64s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexUint8 *, get_complex_uint8s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexUint16 *, get_complex_uint16s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexUint32 *, get_complex_uint32s, (void), nullptr);
+
+  CONST_MUTATION_METHOD (mxComplexUint64 *, get_complex_uint64s, (void), nullptr);
+#endif
+
   void * get_imag_data (void) const
   {
     void *retval = nullptr;
@@ -467,10 +720,35 @@
   }
 
   // Not allowed.
-  void set_data (void * /*pr*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_data, (void *))
+
+  MUTATION_METHOD (int, set_doubles, (mxDouble *), 0)
+  MUTATION_METHOD (int, set_singles, (mxSingle *), 0)
+  MUTATION_METHOD (int, set_int8s, (mxInt8 *), 0)
+  MUTATION_METHOD (int, set_int16s, (mxInt16 *), 0)
+  MUTATION_METHOD (int, set_int32s, (mxInt32 *), 0)
+  MUTATION_METHOD (int, set_int64s, (mxInt64 *), 0)
+  MUTATION_METHOD (int, set_uint8s, (mxUint8 *), 0)
+  MUTATION_METHOD (int, set_uint16s, (mxUint16 *), 0)
+  MUTATION_METHOD (int, set_uint32s, (mxUint32 *), 0)
+  MUTATION_METHOD (int, set_uint64s, (mxUint64 *), 0)
+
+  MUTATION_METHOD (int, set_complex_doubles, (mxComplexDouble *), 0)
+  MUTATION_METHOD (int, set_complex_singles, (mxComplexSingle *), 0)
+#if 0
+  /* We don't have these yet. */
+  MUTATION_METHOD (int, set_complex_int8s, (mxComplexInt8 *), 0)
+  MUTATION_METHOD (int, set_complex_int16s, (mxComplexInt16 *), 0)
+  MUTATION_METHOD (int, set_complex_int32s, (mxComplexInt32 *), 0)
+  MUTATION_METHOD (int, set_complex_int64s, (mxComplexInt64 *), 0)
+  MUTATION_METHOD (int, set_complex_uint8s, (mxComplexUint8 *), 0)
+  MUTATION_METHOD (int, set_complex_uint16s, (mxComplexUint16 *), 0)
+  MUTATION_METHOD (int, set_complex_uint32s, (mxComplexUint32 *), 0)
+  MUTATION_METHOD (int, set_complex_uint64s, (mxComplexUint64 *), 0)
+#endif
 
   // Not allowed.
-  void set_imag_data (void * /*pi*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_imag_data, (void *))
 
   mwIndex * get_ir (void) const
   {
@@ -485,50 +763,30 @@
   mwSize get_nzmax (void) const { return val.nzmax (); }
 
   // Not allowed.
-  void set_ir (mwIndex * /*ir*/) { request_mutation (); }
-
-  // Not allowed.
-  void set_jc (mwIndex * /*jc*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_ir, (mwIndex *))
 
   // Not allowed.
-  void set_nzmax (mwSize /*nzmax*/) { request_mutation (); }
+  VOID_MUTATION_METHOD (set_jc, (mwIndex *))
 
   // Not allowed.
-  int add_field (const char * /*key*/)
-  {
-    request_mutation ();
-    return 0;
-  }
+  VOID_MUTATION_METHOD (set_nzmax, (mwSize))
+
+  // Not allowed.
+  MUTATION_METHOD (int, add_field, (const char *), 0)
 
   // Not allowed.
-  void remove_field (int /*key_num*/) { request_mutation (); }
-
-  mxArray * get_field_by_number (mwIndex /*index*/, int /*key_num*/) const
-  {
-    request_mutation ();
-    return nullptr;
-  }
+  VOID_MUTATION_METHOD (remove_field, (int))
+
+  CONST_MUTATION_METHOD (mxArray *, get_field_by_number, (mwIndex, int), nullptr)
 
   // Not allowed.
-  void set_field_by_number (mwIndex /*index*/, int /*key_num*/,
-                            mxArray * /*val*/)
-  {
-    request_mutation ();
-  }
+  VOID_MUTATION_METHOD (set_field_by_number, (mwIndex, int, mxArray *))
 
   int get_number_of_fields (void) const { return val.nfields (); }
 
-  const char * get_field_name_by_number (int /*key_num*/) const
-  {
-    request_mutation ();
-    return nullptr;
-  }
-
-  int get_field_number (const char * /*key*/) const
-  {
-    request_mutation ();
-    return 0;
-  }
+  CONST_MUTATION_METHOD (const char *, get_field_name_by_number, (int), nullptr)
+
+  CONST_MUTATION_METHOD (int, get_field_number, (const char *), 0)
 
   int get_string (char *buf, mwSize buflen) const
   {
@@ -596,21 +854,21 @@
 
     switch (id)
       {
-      case mxDOUBLE_CLASS: return sizeof (double);
-      case mxSINGLE_CLASS: return sizeof (float);
-      case mxCHAR_CLASS: return sizeof (mxChar);
-      case mxLOGICAL_CLASS: return sizeof (mxLogical);
       case mxCELL_CLASS: return sizeof (mxArray *);
       case mxSTRUCT_CLASS: return sizeof (mxArray *);
+      case mxLOGICAL_CLASS: return sizeof (mxLogical);
+      case mxCHAR_CLASS: return sizeof (mxChar);
+      case mxDOUBLE_CLASS: return get_numeric_element_size (sizeof (mxDouble));
+      case mxSINGLE_CLASS: return get_numeric_element_size (sizeof (mxSingle));
+      case mxINT8_CLASS: return get_numeric_element_size (sizeof (mxInt8));
+      case mxUINT8_CLASS: return get_numeric_element_size (sizeof (mxUint8));
+      case mxINT16_CLASS: return get_numeric_element_size (sizeof (mxInt16));
+      case mxUINT16_CLASS: return get_numeric_element_size (sizeof (mxUint16));
+      case mxINT32_CLASS: return get_numeric_element_size (sizeof (mxInt32));
+      case mxUINT32_CLASS: return get_numeric_element_size (sizeof (mxUint32));
+      case mxINT64_CLASS: return get_numeric_element_size (sizeof (mxInt64));
+      case mxUINT64_CLASS: return get_numeric_element_size (sizeof (mxUint64));
       case mxFUNCTION_CLASS: return 0;
-      case mxINT8_CLASS: return 1;
-      case mxUINT8_CLASS: return 1;
-      case mxINT16_CLASS: return 2;
-      case mxUINT16_CLASS: return 2;
-      case mxINT32_CLASS: return 4;
-      case mxUINT32_CLASS: return 4;
-      case mxINT64_CLASS: return 8;
-      case mxUINT64_CLASS: return 8;
       // FIXME: user-defined objects need their own class ID.
       //        What should they return, size of pointer?
       default: return 0;
@@ -637,9 +895,9 @@
     : mxArray_base (arg), val (arg.val), mutate_flag (arg.mutate_flag),
       id (arg.id), class_name (mxArray::strsave (arg.class_name)),
       ndims (arg.ndims),
-      dims (ndims > 0 ? static_cast<mwSize *>
-                         (mxArray::malloc (ndims * sizeof (mwSize)))
-                      : nullptr)
+      dims (ndims > 0
+            ? static_cast<mwSize *> (mxArray::malloc (ndims * sizeof (mwSize)))
+            : nullptr)
   {
     if (dims)
       {
@@ -671,13 +929,14 @@
 {
 protected:
 
-  mxArray_matlab (mxClassID id_arg = mxUNKNOWN_CLASS)
-    : mxArray_base (), class_name (nullptr), id (id_arg), ndims (0),
+  mxArray_matlab (bool interleaved, mxClassID id_arg = mxUNKNOWN_CLASS)
+    : mxArray_base (interleaved), class_name (nullptr), id (id_arg), ndims (0),
       dims (nullptr)
   { }
 
-  mxArray_matlab (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg)
-    : mxArray_base (), class_name (nullptr), id (id_arg),
+  mxArray_matlab (bool interleaved, mxClassID id_arg, mwSize ndims_arg,
+                  const mwSize *dims_arg)
+    : mxArray_base (interleaved), class_name (nullptr), id (id_arg),
       ndims (ndims_arg < 2 ? 2 : ndims_arg),
       dims (static_cast<mwSize *> (mxArray::malloc (ndims * sizeof (mwSize))))
   {
@@ -704,8 +963,8 @@
       }
   }
 
-  mxArray_matlab (mxClassID id_arg, const dim_vector& dv)
-    : mxArray_base (), class_name (nullptr), id (id_arg),
+  mxArray_matlab (bool interleaved, mxClassID id_arg, const dim_vector& dv)
+    : mxArray_base (interleaved), class_name (nullptr), id (id_arg),
       ndims (dv.ndims ()),
       dims (static_cast<mwSize *> (mxArray::malloc (ndims * sizeof (mwSize))))
   {
@@ -721,8 +980,8 @@
       }
   }
 
-  mxArray_matlab (mxClassID id_arg, mwSize m, mwSize n)
-    : mxArray_base (), class_name (nullptr), id (id_arg), ndims (2),
+  mxArray_matlab (bool interleaved, mxClassID id_arg, mwSize m, mwSize n)
+    : mxArray_base (interleaved), class_name (nullptr), id (id_arg), ndims (2),
       dims (static_cast<mwSize *> (mxArray::malloc (ndims * sizeof (mwSize))))
   {
     dims[0] = m;
@@ -900,98 +1159,304 @@
 
   mxArray * get_cell (mwIndex /*idx*/) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_cell");
   }
 
   void set_cell (mwIndex /*idx*/, mxArray * /*val*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_cell");
   }
 
   double get_scalar (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_scalar");
   }
 
   void * get_data (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_data");
+  }
+
+  mxDouble * get_doubles (void) const
+  {
+    err_invalid_type ("get_doubles");
+  }
+
+  mxSingle * get_singles (void) const
+  {
+    err_invalid_type ("get_singles");
+  }
+
+  mxInt8 * get_int8s (void) const
+  {
+    err_invalid_type ("get_int8s");
+  }
+
+  mxInt16 * get_int16s (void) const
+  {
+    err_invalid_type ("get_int16s");
+  }
+
+  mxInt32 * get_int32s (void) const
+  {
+    err_invalid_type ("get_int32s");
+  }
+
+  mxInt64 * get_int64s (void) const
+  {
+    err_invalid_type ("get_int64s");
+  }
+
+  mxUint8 * get_uint8s (void) const
+  {
+    err_invalid_type ("get_uint8s");
+  }
+
+  mxUint16 * get_uint16s (void) const
+  {
+    err_invalid_type ("get_uint16s");
+  }
+
+  mxUint32 * get_uint32s (void) const
+  {
+    err_invalid_type ("get_uint32s");
+  }
+
+  mxUint64 * get_uint64s (void) const
+  {
+    err_invalid_type ("get_uint64s");
   }
 
+  mxComplexDouble * get_complex_doubles (void) const
+  {
+    err_invalid_type ("get_complex_doubles");
+  }
+
+  mxComplexSingle * get_complex_singles (void) const
+  {
+    err_invalid_type ("get_complex_singles");
+  }
+
+#if 0
+  /* We don't have these yet. */
+  mxComplexInt8 * get_complex_int8s (void) const
+  {
+    err_invalid_type ("get_complex_int8s");
+  }
+
+  mxComplexInt16 * get_complex_int16s (void) const
+  {
+    err_invalid_type ("get_complex_int16s");
+  }
+
+  mxComplexInt32 * get_complex_int32s (void) const
+  {
+    err_invalid_type ("get_complex_int32s");
+  }
+
+  mxComplexInt64 * get_complex_int64s (void) const
+  {
+    err_invalid_type ("get_complex_int64s");
+  }
+
+  mxComplexUint8 * get_complex_uint8s (void) const
+  {
+    err_invalid_type ("get_complex_uint8s");
+  }
+
+  mxComplexUint16 * get_complex_uint16s (void) const
+  {
+    err_invalid_type ("get_complex_uint16s");
+  }
+
+  mxComplexUint32 * get_complex_uint32s (void) const
+  {
+    err_invalid_type ("get_complex_uint32s");
+  }
+
+  mxComplexUint64 * get_complex_uint64s (void) const
+  {
+    err_invalid_type ("get_complex_uint64s");
+  }
+#endif
+
   void * get_imag_data (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_imag_data");
   }
 
   void set_data (void * /*pr*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_data");
+  }
+
+  int set_doubles (mxDouble *)
+  {
+    err_invalid_type ("set_doubles");
+  }
+
+  int set_singles (mxSingle *)
+  {
+    err_invalid_type ("set_singles");
+  }
+
+  int set_int8s (mxInt8 *)
+  {
+    err_invalid_type ("set_int8s");
+  }
+
+  int set_int16s (mxInt16 *)
+  {
+    err_invalid_type ("set_int16s");
+  }
+
+  int set_int32s (mxInt32 *)
+  {
+    err_invalid_type ("set_int32s");
+  }
+
+  int set_int64s (mxInt64 *)
+  {
+    err_invalid_type ("set_int64s");
+  }
+
+  int set_uint8s (mxUint8 *)
+  {
+    err_invalid_type ("set_uint8s");
+  }
+
+  int set_uint16s (mxUint16 *)
+  {
+    err_invalid_type ("set_uint16s");
+  }
+
+  int set_uint32s (mxUint32 *)
+  {
+    err_invalid_type ("set_uint32s");
+  }
+
+  int set_uint64s (mxUint64 *)
+  {
+    err_invalid_type ("set_uint64s");
   }
 
+  int set_complex_doubles (mxComplexDouble *)
+  {
+    err_invalid_type ("set_complex_doubles");
+  }
+
+  int set_complex_singles (mxComplexSingle *)
+  {
+    err_invalid_type ("set_complex_singles");
+  }
+
+#if 0
+  /* We don't have these yet. */
+  int set_complex_int8s (mxComplexInt8 *)
+  {
+    err_invalid_type ("set_complex_int8s");
+  }
+
+  int set_complex_int16s (mxComplexInt16 *)
+  {
+    err_invalid_type ("set_complex_int16s");
+  }
+
+  int set_complex_int32s (mxComplexInt32 *)
+  {
+    err_invalid_type ("set_complex_int32s");
+  }
+
+  int set_complex_int64s (mxComplexInt64 *)
+  {
+    err_invalid_type ("set_complex_int64s");
+  }
+
+  int set_complex_uint8s (mxComplexUint8 *)
+  {
+    err_invalid_type ("set_complex_uint8s");
+  }
+
+  int set_complex_uint16s (mxComplexUint16 *)
+  {
+    err_invalid_type ("set_complex_uint16s");
+  }
+
+  int set_complex_uint32s (mxComplexUint32 *)
+  {
+    err_invalid_type ("set_complex_uint32s");
+  }
+
+  int set_complex_uint64s (mxComplexUint64 *)
+  {
+    err_invalid_type ("set_complex_uint64s");
+  }
+#endif
+
   void set_imag_data (void * /*pi*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_imag_data");
   }
 
   mwIndex * get_ir (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_ir");
   }
 
   mwIndex * get_jc (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_jc");
   }
 
   mwSize get_nzmax (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_nzmax");
   }
 
   void set_ir (mwIndex * /*ir*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_ir");
   }
 
   void set_jc (mwIndex * /*jc*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_jc");
   }
 
   void set_nzmax (mwSize /*nzmax*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_nzmax");
   }
 
   int add_field (const char * /*key*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("add_field");
   }
 
   void remove_field (int /*key_num*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("remove_field");
   }
 
   mxArray * get_field_by_number (mwIndex /*index*/, int /*key_num*/) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_field_by_number");
   }
 
   void set_field_by_number (mwIndex /*index*/, int /*key_num*/,
                             mxArray * /*val*/)
   {
-    err_invalid_type ();
+    err_invalid_type ("set_field_by_number");
   }
 
   int get_number_of_fields (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_number_of_fields");
   }
 
   const char * get_field_name_by_number (int /*key_num*/) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_field_name_by_number");
   }
 
   int get_field_number (const char * /*key*/) const
@@ -1001,12 +1466,12 @@
 
   int get_string (char * /*buf*/, mwSize /*buflen*/) const
   {
-    err_invalid_type ();
+    err_invalid_type ("get_string");
   }
 
   char * array_to_string (void) const
   {
-    err_invalid_type ();
+    err_invalid_type ("array_to_string");
   }
 
   mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
@@ -1022,16 +1487,16 @@
       case mxSTRUCT_CLASS: return sizeof (mxArray *);
       case mxLOGICAL_CLASS: return sizeof (mxLogical);
       case mxCHAR_CLASS: return sizeof (mxChar);
-      case mxDOUBLE_CLASS: return sizeof (double);
-      case mxSINGLE_CLASS: return sizeof (float);
-      case mxINT8_CLASS: return 1;
-      case mxUINT8_CLASS: return 1;
-      case mxINT16_CLASS: return 2;
-      case mxUINT16_CLASS: return 2;
-      case mxINT32_CLASS: return 4;
-      case mxUINT32_CLASS: return 4;
-      case mxINT64_CLASS: return 8;
-      case mxUINT64_CLASS: return 8;
+      case mxDOUBLE_CLASS: return get_numeric_element_size (sizeof (mxDouble));
+      case mxSINGLE_CLASS: return get_numeric_element_size (sizeof (mxSingle));
+      case mxINT8_CLASS: return get_numeric_element_size (sizeof (mxInt8));
+      case mxUINT8_CLASS: return get_numeric_element_size (sizeof (mxUint8));
+      case mxINT16_CLASS: return get_numeric_element_size (sizeof (mxInt16));
+      case mxUINT16_CLASS: return get_numeric_element_size (sizeof (mxUint16));
+      case mxINT32_CLASS: return get_numeric_element_size (sizeof (mxInt32));
+      case mxUINT32_CLASS: return get_numeric_element_size (sizeof (mxUint32));
+      case mxINT64_CLASS: return get_numeric_element_size (sizeof (mxInt64));
+      case mxUINT64_CLASS: return get_numeric_element_size (sizeof (mxUint64));
       case mxFUNCTION_CLASS: return 0;
       // FIXME: user-defined objects need their own class ID.
       //        What should they return, size of pointer?
@@ -1065,59 +1530,79 @@
 
   mwSize ndims;
   mwSize *dims;
-
-  OCTAVE_NORETURN void err_invalid_type (void) const
-  {
-    error ("invalid type for operation");
-  }
 };
 
+
 // Matlab-style numeric, character, and logical data.
 
+#define TYPED_GET_METHOD(TYPE, FCN_NAME)        \
+  TYPE FCN_NAME (void) const                    \
+  {                                             \
+    if (! m_interleaved)                        \
+      panic_impossible ();                      \
+                                                \
+    return static_cast<TYPE> (pr);              \
+  }
+
+#define TYPED_SET_METHOD(TYPE, FCN_NAME)        \
+  int FCN_NAME (TYPE d)                         \
+  {                                             \
+    if (! m_interleaved)                        \
+      panic_impossible ();                      \
+                                                \
+    pr = d;                                     \
+    return 0;                                   \
+  }
+
 class mxArray_number : public mxArray_matlab
 {
 public:
 
-  mxArray_number (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg,
-                  mxComplexity flag = mxREAL, bool init = true)
-    : mxArray_matlab (id_arg, ndims_arg, dims_arg),
-      pr (init ? mxArray::calloc (get_number_of_elements (),
-                                  get_element_size ())
-               : mxArray::malloc (get_number_of_elements ()
-                                  * get_element_size ())),
-      pi (flag == mxCOMPLEX
-            ? (init ? mxArray::calloc (get_number_of_elements (),
-                                       get_element_size ())
-                    : mxArray::malloc (get_number_of_elements ()
-                                       * get_element_size ()))
-            : nullptr) { }
-
-  mxArray_number (mxClassID id_arg, const dim_vector& dv,
+  mxArray_number (bool interleaved, mxClassID id_arg, mwSize ndims_arg,
+                  const mwSize *dims_arg, mxComplexity flag = mxREAL,
+                  bool init = true)
+    : mxArray_matlab (interleaved, id_arg, ndims_arg, dims_arg),
+      m_complex (flag == mxCOMPLEX),
+      pr (init
+          ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+          : mxArray::malloc (get_number_of_elements () * get_element_size ())),
+      pi (m_interleaved
+          ? nullptr
+          : (m_complex
+             ? (init
+                ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+                : mxArray::malloc (get_number_of_elements () * get_element_size ()))
+             : nullptr))
+  { }
+
+  mxArray_number (bool interleaved, mxClassID id_arg, const dim_vector& dv,
                   mxComplexity flag = mxREAL)
-    : mxArray_matlab (id_arg, dv),
+    : mxArray_matlab (interleaved, id_arg, dv), m_complex (flag == mxCOMPLEX),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
-      pi (flag == mxCOMPLEX ? mxArray::calloc (get_number_of_elements (),
-                                               get_element_size ())
-                            : nullptr)
+      pi (m_interleaved
+          ? nullptr
+          : (m_complex
+             ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+             : nullptr))
   { }
 
-  mxArray_number (mxClassID id_arg, mwSize m, mwSize n,
+  mxArray_number (bool interleaved, mxClassID id_arg, mwSize m, mwSize n,
                   mxComplexity flag = mxREAL, bool init = true)
-    : mxArray_matlab (id_arg, m, n),
-      pr (init ? mxArray::calloc (get_number_of_elements (),
-                                  get_element_size ())
-               : mxArray::malloc (get_number_of_elements ()
-                                  * get_element_size ())),
-      pi (flag == mxCOMPLEX
-            ? (init ? mxArray::calloc (get_number_of_elements (),
-                                       get_element_size ())
-                    : mxArray::malloc (get_number_of_elements ()
-                                       * get_element_size ()))
-            : nullptr)
+    : mxArray_matlab (interleaved, id_arg, m, n), m_complex (flag == mxCOMPLEX),
+      pr (init
+          ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+          : mxArray::malloc (get_number_of_elements () * get_element_size ())),
+      pi (m_interleaved
+          ? nullptr
+          : (m_complex
+             ? (init
+                ? mxArray::calloc (get_number_of_elements (), get_element_size ())
+                : mxArray::malloc (get_number_of_elements () * get_element_size ()))
+             : nullptr))
   { }
 
-  mxArray_number (mxClassID id_arg, double val)
-    : mxArray_matlab (id_arg, 1, 1),
+  mxArray_number (bool interleaved, mxClassID id_arg, double val)
+    : mxArray_matlab (interleaved, id_arg, 1, 1), m_complex (false),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1125,8 +1610,8 @@
     dpr[0] = val;
   }
 
-  mxArray_number (mxClassID id_arg, mxLogical val)
-    : mxArray_matlab (id_arg, 1, 1),
+  mxArray_number (bool interleaved, mxClassID id_arg, mxLogical val)
+    : mxArray_matlab (interleaved, id_arg, 1, 1), m_complex (false),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1134,10 +1619,11 @@
     lpr[0] = val;
   }
 
-  mxArray_number (const char *str)
-    : mxArray_matlab (mxCHAR_CLASS,
+  mxArray_number (bool interleaved, const char *str)
+    : mxArray_matlab (interleaved, mxCHAR_CLASS,
                       str ? (strlen (str) ? 1 : 0) : 0,
                       str ? strlen (str) : 0),
+      m_complex (false),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1148,8 +1634,9 @@
   }
 
   // FIXME: ???
-  mxArray_number (mwSize m, const char **str)
-    : mxArray_matlab (mxCHAR_CLASS, m, max_str_len (m, str)),
+  mxArray_number (bool interleaved, mwSize m, const char **str)
+    : mxArray_matlab (interleaved, mxCHAR_CLASS, m, max_str_len (m, str)),
+      m_complex (false),
       pr (mxArray::calloc (get_number_of_elements (), get_element_size ())),
       pi (nullptr)
   {
@@ -1176,11 +1663,13 @@
 protected:
 
   mxArray_number (const mxArray_number& val)
-    : mxArray_matlab (val),
+    : mxArray_matlab (val), m_complex (val.m_complex),
       pr (mxArray::malloc (get_number_of_elements () * get_element_size ())),
-      pi (val.pi ? mxArray::malloc (get_number_of_elements ()
-                                    * get_element_size ())
-                 : nullptr)
+      pi (m_interleaved
+          ? nullptr
+          : (val.pi
+             ? mxArray::malloc (get_number_of_elements () * get_element_size ())
+             : nullptr))
   {
     std::size_t nbytes = get_number_of_elements () * get_element_size ();
 
@@ -1198,7 +1687,10 @@
 
   mxArray_number& operator = (const mxArray_number&);
 
-  mxArray_base * dup (void) const { return new mxArray_number (*this); }
+  mxArray_base * dup (void) const
+  {
+    return new mxArray_number (*this);
+  }
 
   ~mxArray_number (void)
   {
@@ -1206,10 +1698,15 @@
     mxFree (pi);
   }
 
-  int is_complex (void) const { return pi != nullptr; }
+  int is_complex (void) const
+  {
+    return m_interleaved ? m_complex : (pi != nullptr);
+  }
 
   double get_scalar (void) const
   {
+    // FIXME: how does this work for interleaved complex arrays?
+
     double retval = 0;
 
     switch (get_class_id ())
@@ -1271,11 +1768,73 @@
 
   void * get_data (void) const { return pr; }
 
-  void * get_imag_data (void) const { return pi; }
+  void * get_imag_data (void) const
+  {
+    if (m_interleaved)
+      panic_impossible ();
+
+    return pi;
+  }
 
   void set_data (void *pr_arg) { pr = pr_arg; }
 
-  void set_imag_data (void *pi_arg) { pi = pi_arg; }
+  void set_imag_data (void *pi_arg)
+  {
+    if (m_interleaved)
+      panic_impossible ();
+
+    pi = pi_arg;
+  }
+
+  TYPED_GET_METHOD (mxDouble *, get_doubles)
+  TYPED_GET_METHOD (mxSingle *, get_singles)
+  TYPED_GET_METHOD (mxInt8 *, get_int8s)
+  TYPED_GET_METHOD (mxInt16 *, get_int16s)
+  TYPED_GET_METHOD (mxInt32 *, get_int32s)
+  TYPED_GET_METHOD (mxInt64 *, get_int64s)
+  TYPED_GET_METHOD (mxUint8 *, get_uint8s)
+  TYPED_GET_METHOD (mxUint16 *, get_uint16s)
+  TYPED_GET_METHOD (mxUint32 *, get_uint32s)
+  TYPED_GET_METHOD (mxUint64 *, get_uint64s)
+
+  TYPED_GET_METHOD (mxComplexDouble *, get_complex_doubles)
+  TYPED_GET_METHOD (mxComplexSingle *, get_complex_singles)
+#if 0
+  /* We don't have these yet. */
+  TYPED_GET_METHOD (mxComplexInt8 *, get_complex_int8s)
+  TYPED_GET_METHOD (mxComplexInt16 *, get_complex_int16s)
+  TYPED_GET_METHOD (mxComplexInt32 *, get_complex_int32s)
+  TYPED_GET_METHOD (mxComplexInt64 *, get_complex_int64s)
+  TYPED_GET_METHOD (mxComplexUint8 *, get_complex_uint8s)
+  TYPED_GET_METHOD (mxComplexUint16 *, get_complex_uint16s)
+  TYPED_GET_METHOD (mxComplexUint32 *, get_complex_uint32s)
+  TYPED_GET_METHOD (mxComplexUint64 *, get_complex_uint64s)
+#endif
+
+  TYPED_SET_METHOD (mxDouble *, set_doubles)
+  TYPED_SET_METHOD (mxSingle *, set_singles)
+  TYPED_SET_METHOD (mxInt8 *, set_int8s)
+  TYPED_SET_METHOD (mxInt16 *, set_int16s)
+  TYPED_SET_METHOD (mxInt32 *, set_int32s)
+  TYPED_SET_METHOD (mxInt64 *, set_int64s)
+  TYPED_SET_METHOD (mxUint8 *, set_uint8s)
+  TYPED_SET_METHOD (mxUint16 *, set_uint16s)
+  TYPED_SET_METHOD (mxUint32 *, set_uint32s)
+  TYPED_SET_METHOD (mxUint64 *, set_uint64s)
+
+  TYPED_SET_METHOD (mxComplexDouble *, set_complex_doubles)
+  TYPED_SET_METHOD (mxComplexSingle *, set_complex_singles)
+#if 0
+  /* We don't have these yet. */
+  TYPED_SET_METHOD (mxComplexInt8 *, set_complex_int8s)
+  TYPED_SET_METHOD (mxComplexInt16 *, set_complex_int16s)
+  TYPED_SET_METHOD (mxComplexInt32 *, set_complex_int32s)
+  TYPED_SET_METHOD (mxComplexInt64 *, set_complex_int64s)
+  TYPED_SET_METHOD (mxComplexUint8 *, set_complex_uint8s)
+  TYPED_SET_METHOD (mxComplexUint16 *, set_complex_uint16s)
+  TYPED_SET_METHOD (mxComplexUint32 *, set_complex_uint32s)
+  TYPED_SET_METHOD (mxComplexUint64 *, set_complex_uint64s)
+#endif
 
   int get_string (char *buf, mwSize buflen) const
   {
@@ -1336,23 +1895,40 @@
         {
           mwSize nel = get_number_of_elements ();
 
-          double *ppr = static_cast<double *> (pr);
-
-          if (pi)
+          if (is_complex ())
             {
-              ComplexNDArray val (dv);
-
-              Complex *ptr = val.fortran_vec ();
-
-              double *ppi = static_cast<double *> (pi);
-
-              for (mwIndex i = 0; i < nel; i++)
-                ptr[i] = Complex (ppr[i], ppi[i]);
-
-              retval = val;
+              if (m_interleaved)
+                {
+                  Complex *ppr = static_cast<Complex *> (pr);
+
+                  ComplexNDArray val (dv);
+                  Complex *ptr = val.fortran_vec ();
+
+                  for (mwIndex i = 0; i < nel; i++)
+                    ptr[i] = ppr[i];
+
+                  retval = val;
+                }
+              else
+                {
+                  double *ppr = static_cast<double *> (pr);
+
+                  ComplexNDArray val (dv);
+
+                  Complex *ptr = val.fortran_vec ();
+
+                  double *ppi = static_cast<double *> (pi);
+
+                  for (mwIndex i = 0; i < nel; i++)
+                    ptr[i] = Complex (ppr[i], ppi[i]);
+
+                  retval = val;
+                }
             }
           else
             {
+              double *ppr = static_cast<double *> (pr);
+
               NDArray val (dv);
 
               double *ptr = val.fortran_vec ();
@@ -1369,23 +1945,40 @@
         {
           mwSize nel = get_number_of_elements ();
 
-          float *ppr = static_cast<float *> (pr);
-
-          if (pi)
+          if (is_complex ())
             {
-              FloatComplexNDArray val (dv);
-
-              FloatComplex *ptr = val.fortran_vec ();
-
-              float *ppi = static_cast<float *> (pi);
-
-              for (mwIndex i = 0; i < nel; i++)
-                ptr[i] = FloatComplex (ppr[i], ppi[i]);
-
-              retval = val;
+              if (m_interleaved)
+                {
+                  FloatComplex *ppr = static_cast<FloatComplex *> (pr);
+
+                  FloatComplexNDArray val (dv);
+                  FloatComplex *ptr = val.fortran_vec ();
+
+                  for (mwIndex i = 0; i < nel; i++)
+                    ptr[i] = ppr[i];
+
+                  retval = val;
+                }
+              else
+                {
+                  float *ppr = static_cast<float *> (pr);
+
+                  FloatComplexNDArray val (dv);
+
+                  FloatComplex *ptr = val.fortran_vec ();
+
+                  float *ppi = static_cast<float *> (pi);
+
+                  for (mwIndex i = 0; i < nel; i++)
+                    ptr[i] = FloatComplex (ppr[i], ppi[i]);
+
+                  retval = val;
+                }
             }
           else
             {
+              float *ppr = static_cast<float *> (pr);
+
               FloatNDArray val (dv);
 
               float *ptr = val.fortran_vec ();
@@ -1464,7 +2057,7 @@
   octave_value
   int_to_ov (const dim_vector& dv) const
   {
-    if (pi)
+    if (is_complex ())
       error ("complex integer types are not supported");
 
     mwSize nel = get_number_of_elements ();
@@ -1483,7 +2076,17 @@
 
 private:
 
+  // Flag to identify complex object if using interleaved data and PI is
+  // always nullptr.
+  bool m_complex;
+
+  // If using interleaved complex storage, this is the pointer to data
+  // (real, complex, or logical).  Otherwise, it is the pointer to the
+  // real part of the data.
   void *pr;
+
+  // If using non-interleaved complex storage, this is the pointer to
+  // the imaginary part of the data.  Othrwise is is always nullptr.
   void *pi;
 };
 
@@ -1493,24 +2096,31 @@
 {
 public:
 
-  mxArray_sparse (mxClassID id_arg, mwSize m, mwSize n, mwSize nzmax_arg,
-                  mxComplexity flag = mxREAL)
-    : mxArray_matlab (id_arg, m, n)
-  {
-    nzmax = (nzmax_arg > 0 ? nzmax_arg : 1);
-    pr = mxArray::calloc (nzmax, get_element_size ());
-    pi = (flag == mxCOMPLEX ? mxArray::calloc (nzmax, get_element_size ())
-                            : nullptr);
-    ir = (static_cast<mwIndex *> (mxArray::calloc (nzmax, sizeof (mwIndex))));
-    jc = (static_cast<mwIndex *> (mxArray::calloc (n + 1, sizeof (mwIndex))));
-  }
+  mxArray_sparse (bool interleaved, mxClassID id_arg, mwSize m, mwSize n,
+                  mwSize nzmax_arg, mxComplexity flag = mxREAL)
+    : mxArray_matlab (interleaved, id_arg, m, n), m_complex (flag == mxCOMPLEX),
+
+      nzmax (nzmax_arg > 0 ? nzmax_arg : 1),
+      pr (mxArray::calloc (nzmax, get_element_size ())),
+      pi (m_interleaved
+          ? nullptr
+          : (m_complex
+             ? mxArray::calloc (nzmax, get_element_size ())
+             : nullptr)),
+      ir (static_cast<mwIndex *> (mxArray::calloc (nzmax, sizeof (mwIndex)))),
+      jc (static_cast<mwIndex *> (mxArray::calloc (n + 1, sizeof (mwIndex))))
+  { }
 
 private:
 
   mxArray_sparse (const mxArray_sparse& val)
     : mxArray_matlab (val), nzmax (val.nzmax),
       pr (mxArray::malloc (nzmax * get_element_size ())),
-      pi (val.pi ? mxArray::malloc (nzmax * get_element_size ()) : nullptr),
+      pi (m_interleaved
+          ? nullptr
+          : (val.pi
+             ? mxArray::malloc (nzmax * get_element_size ())
+             : nullptr)),
       ir (static_cast<mwIndex *> (mxArray::malloc (nzmax * sizeof (mwIndex)))),
       jc (static_cast<mwIndex *> (mxArray::malloc (nzmax * sizeof (mwIndex))))
   {
@@ -1536,7 +2146,10 @@
 
   mxArray_sparse& operator = (const mxArray_sparse&);
 
-  mxArray_base * dup (void) const { return new mxArray_sparse (*this); }
+  mxArray_base * dup (void) const
+  {
+    return new mxArray_sparse (*this);
+  }
 
   ~mxArray_sparse (void)
   {
@@ -1546,17 +2159,38 @@
     mxFree (jc);
   }
 
-  int is_complex (void) const { return pi != nullptr; }
+  int is_complex (void) const
+  {
+    return m_interleaved ? m_complex : (pi != nullptr);
+  }
 
   int is_sparse (void) const { return 1; }
 
   void * get_data (void) const { return pr; }
 
-  void * get_imag_data (void) const { return pi; }
+  void * get_imag_data (void) const
+  {
+    if (m_interleaved)
+      panic_impossible ();
+
+    return pi;
+  }
 
   void set_data (void *pr_arg) { pr = pr_arg; }
 
-  void set_imag_data (void *pi_arg) { pi = pi_arg; }
+  void set_imag_data (void *pi_arg)
+  {
+    if (m_interleaved)
+      panic_impossible ();
+
+    pi = pi_arg;
+  }
+
+  TYPED_GET_METHOD (mxDouble *, get_doubles)
+  TYPED_GET_METHOD (mxComplexDouble *, get_complex_doubles)
+
+  TYPED_SET_METHOD (mxDouble *, set_doubles)
+  TYPED_SET_METHOD (mxComplexDouble *, set_complex_doubles)
 
   mwIndex * get_ir (void) const { return ir; }
 
@@ -1584,24 +2218,45 @@
       {
       case mxDOUBLE_CLASS:
         {
-          if (pi)
+          if (is_complex ())
             {
-              double *ppr = static_cast<double *> (pr);
-              double *ppi = static_cast<double *> (pi);
-
-              SparseComplexMatrix val (get_m (), get_n (),
-                                       static_cast<octave_idx_type> (nzmax));
-
-              for (mwIndex i = 0; i < nzmax; i++)
+              if (m_interleaved)
                 {
-                  val.xdata (i) = Complex (ppr[i], ppi[i]);
-                  val.xridx (i) = ir[i];
+                  Complex *ppr = static_cast<Complex *> (pr);
+
+                  SparseComplexMatrix val (get_m (), get_n (),
+                                           static_cast<octave_idx_type> (nzmax));
+
+                  for (mwIndex i = 0; i < nzmax; i++)
+                    {
+                      val.xdata (i) = ppr[i];
+                      val.xridx (i) = ir[i];
+                    }
+
+                  for (mwIndex i = 0; i < get_n () + 1; i++)
+                    val.xcidx (i) = jc[i];
+
+                  retval = val;
                 }
-
-              for (mwIndex i = 0; i < get_n () + 1; i++)
-                val.xcidx (i) = jc[i];
-
-              retval = val;
+              else
+                {
+                  double *ppr = static_cast<double *> (pr);
+                  double *ppi = static_cast<double *> (pi);
+
+                  SparseComplexMatrix val (get_m (), get_n (),
+                                           static_cast<octave_idx_type> (nzmax));
+
+                  for (mwIndex i = 0; i < nzmax; i++)
+                    {
+                      val.xdata (i) = Complex (ppr[i], ppi[i]);
+                      val.xridx (i) = ir[i];
+                    }
+
+                  for (mwIndex i = 0; i < get_n () + 1; i++)
+                    val.xcidx (i) = jc[i];
+
+                  retval = val;
+                }
             }
           else
             {
@@ -1646,7 +2301,6 @@
 
       case mxSINGLE_CLASS:
         error ("single precision sparse data type not supported");
-        break;
 
       default:
         panic_impossible ();
@@ -1657,10 +2311,23 @@
 
 private:
 
+  // Flag to identify complex object if using interleaved data and PI is
+  // always nullptr.
+  bool m_complex;
+
+  // Maximun number of nonzero elements.
   mwSize nzmax;
 
+  // If using interleaved complex storage, this is the pointer to data
+  // (real, complex, or logical).  Otherwise, it is the pointer to the
+  // real part of the data.
   void *pr;
+
+  // If using non-interleaved complex storage, this is the pointer to
+  // the imaginary part of the data.  Othrwise is is always nullptr.
   void *pi;
+
+  // Sparse storage indexing arrays.
   mwIndex *ir;
   mwIndex *jc;
 };
@@ -1671,9 +2338,9 @@
 {
 public:
 
-  mxArray_struct (mwSize ndims_arg, const mwSize *dims_arg, int num_keys_arg,
-                  const char **keys)
-    : mxArray_matlab (mxSTRUCT_CLASS, ndims_arg, dims_arg),
+  mxArray_struct (bool interleaved, mwSize ndims_arg, const mwSize *dims_arg,
+                  int num_keys_arg, const char **keys)
+    : mxArray_matlab (interleaved, mxSTRUCT_CLASS, ndims_arg, dims_arg),
       nfields (num_keys_arg),
       fields (static_cast<char **> (mxArray::calloc (nfields,
                                                      sizeof (char *)))),
@@ -1684,8 +2351,9 @@
     init (keys);
   }
 
-  mxArray_struct (const dim_vector& dv, int num_keys_arg, const char **keys)
-    : mxArray_matlab (mxSTRUCT_CLASS, dv), nfields (num_keys_arg),
+  mxArray_struct (bool interleaved, const dim_vector& dv, int num_keys_arg,
+                  const char **keys)
+    : mxArray_matlab (interleaved, mxSTRUCT_CLASS, dv), nfields (num_keys_arg),
       fields (static_cast<char **> (mxArray::calloc (nfields,
                                                      sizeof (char *)))),
       data (static_cast<mxArray **> (mxArray::calloc (nfields *
@@ -1695,8 +2363,10 @@
     init (keys);
   }
 
-  mxArray_struct (mwSize m, mwSize n, int num_keys_arg, const char **keys)
-    : mxArray_matlab (mxSTRUCT_CLASS, m, n), nfields (num_keys_arg),
+  mxArray_struct (bool interleaved, mwSize m, mwSize n, int num_keys_arg,
+                  const char **keys)
+    : mxArray_matlab (interleaved, mxSTRUCT_CLASS, m, n),
+      nfields (num_keys_arg),
       fields (static_cast<char **> (mxArray::calloc (nfields,
                                                      sizeof (char *)))),
       data (static_cast<mxArray **> (mxArray::calloc (nfields *
@@ -1937,18 +2607,18 @@
 {
 public:
 
-  mxArray_cell (mwSize ndims_arg, const mwSize *dims_arg)
-    : mxArray_matlab (mxCELL_CLASS, ndims_arg, dims_arg),
+  mxArray_cell (bool interleaved, mwSize ndims_arg, const mwSize *dims_arg)
+    : mxArray_matlab (interleaved, mxCELL_CLASS, ndims_arg, dims_arg),
       data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (),
                                      sizeof (mxArray *)))) { }
 
-  mxArray_cell (const dim_vector& dv)
-    : mxArray_matlab (mxCELL_CLASS, dv),
+  mxArray_cell (bool interleaved, const dim_vector& dv)
+    : mxArray_matlab (interleaved, mxCELL_CLASS, dv),
       data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (),
                                      sizeof (mxArray *)))) { }
 
-  mxArray_cell (mwSize m, mwSize n)
-    : mxArray_matlab (mxCELL_CLASS, m, n),
+  mxArray_cell (bool interleaved, mwSize m, mwSize n)
+    : mxArray_matlab (interleaved, mxCELL_CLASS, m, n),
       data (static_cast<mxArray **> (mxArray::calloc (get_number_of_elements (),
                                      sizeof (mxArray *)))) { }
 
@@ -2021,54 +2691,76 @@
 
 // ------------------------------------------------------------------
 
-mxArray::mxArray (const octave_value& ov)
-  : rep (new mxArray_octave_value (ov)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, mwSize ndims, const mwSize *dims,
-                  mxComplexity flag, bool init)
-  : rep (new mxArray_number (id, ndims, dims, flag, init)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag)
-  : rep (new mxArray_number (id, dv, flag)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, mwSize m, mwSize n,
+mxArray::mxArray (bool interleaved, const octave_value& ov)
+  : rep (create_rep (interleaved, ov)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, mwSize ndims,
+                  const mwSize *dims, mxComplexity flag, bool init)
+  : rep (create_rep (interleaved, id, ndims, dims, flag, init)),
+    name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, const dim_vector& dv,
+                  mxComplexity flag)
+  : rep (create_rep (interleaved, id, dv, flag)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
                   mxComplexity flag, bool init)
-  : rep (new mxArray_number (id, m, n, flag, init)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, double val)
-  : rep (new mxArray_number (id, val)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, mxLogical val)
-  : rep (new mxArray_number (id, val)), name (nullptr) { }
-
-mxArray::mxArray (const char *str)
-  : rep (new mxArray_number (str)), name (nullptr) { }
-
-mxArray::mxArray (mwSize m, const char **str)
-  : rep (new mxArray_number (m, str)), name (nullptr) { }
-
-mxArray::mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax,
-                  mxComplexity flag)
-  : rep (new mxArray_sparse (id, m, n, nzmax, flag)), name (nullptr) { }
-
-mxArray::mxArray (mwSize ndims, const mwSize *dims, int num_keys,
+  : rep (create_rep (interleaved, id, m, n, flag, init)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, double val)
+  : rep (create_rep (interleaved, id, val)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, mxLogical val)
+  : rep (create_rep (interleaved, id, val)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, const char *str)
+  : rep (create_rep (interleaved, str)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize m, const char **str)
+  : rep (create_rep (interleaved, m, str)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
+                  mwSize nzmax, mxComplexity flag)
+  : rep (create_rep (interleaved, id, m, n, nzmax, flag)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize ndims, const mwSize *dims,
+                  int num_keys,
                   const char **keys)
-  : rep (new mxArray_struct (ndims, dims, num_keys, keys)), name (nullptr) { }
-
-mxArray::mxArray (const dim_vector& dv, int num_keys, const char **keys)
-  : rep (new mxArray_struct (dv, num_keys, keys)), name (nullptr) { }
-
-mxArray::mxArray (mwSize m, mwSize n, int num_keys, const char **keys)
-  : rep (new mxArray_struct (m, n, num_keys, keys)), name (nullptr) { }
-
-mxArray::mxArray (mwSize ndims, const mwSize *dims)
-  : rep (new mxArray_cell (ndims, dims)), name (nullptr) { }
-
-mxArray::mxArray (const dim_vector& dv)
-  : rep (new mxArray_cell (dv)), name (nullptr) { }
-
-mxArray::mxArray (mwSize m, mwSize n)
-  : rep (new mxArray_cell (m, n)), name (nullptr) { }
+  : rep (new mxArray_struct (interleaved, ndims, dims, num_keys, keys)),
+    name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, const dim_vector& dv, int num_keys,
+                  const char **keys)
+  : rep (new mxArray_struct (interleaved, dv, num_keys, keys)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize m, mwSize n, int num_keys,
+                  const char **keys)
+  : rep (new mxArray_struct (interleaved, m, n, num_keys, keys)),
+    name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize ndims, const mwSize *dims)
+  : rep (new mxArray_cell (interleaved, ndims, dims)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, const dim_vector& dv)
+  : rep (new mxArray_cell (interleaved, dv)), name (nullptr)
+{ }
+
+mxArray::mxArray (bool interleaved, mwSize m, mwSize n)
+  : rep (new mxArray_cell (interleaved, m, n)), name (nullptr)
+{ }
 
 mxArray::~mxArray (void)
 {
@@ -2100,6 +2792,64 @@
   return rep->as_octave_value ();
 }
 
+mxArray_base *
+mxArray::create_rep (bool interleaved, const octave_value& ov)
+{
+  return new mxArray_octave_value (interleaved, ov);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, mwSize ndims,
+                     const mwSize *dims, mxComplexity flag, bool init)
+{
+  return new mxArray_number (interleaved, id, ndims, dims, flag, init);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, const dim_vector& dv,
+                     mxComplexity flag)
+{
+  return new mxArray_number (interleaved, id, dv, flag);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
+                     mxComplexity flag, bool init)
+{
+  return new mxArray_number (interleaved, id, m, n, flag, init);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, double val)
+{
+  return new mxArray_number (interleaved, id, val);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, mxLogical val)
+{
+  return new mxArray_number (interleaved, id, val);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, const char *str)
+{
+  return new mxArray_number (interleaved, str);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mwSize m, const char **str)
+{
+  return new mxArray_number (interleaved, m, str);
+}
+
+mxArray_base *
+mxArray::create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
+                     mwSize nzmax, mxComplexity flag)
+{
+  return new mxArray_sparse (interleaved, id, m, n, nzmax, flag);
+}
+
 void
 mxArray::maybe_mutate (void) const
 {
@@ -2130,7 +2880,7 @@
 {
 public:
 
-  mex (octave_mex_function *f)
+  mex (octave_mex_function& f)
     : curr_mex_fcn (f), memlist (), arraylist (), fname (nullptr) { }
 
   // No copying!
@@ -2363,7 +3113,9 @@
   // freed on exit unless marked as persistent.
   mxArray * make_value (const octave_value& ov)
   {
-    return mark_array (new mxArray (ov));
+    bool interleaved = curr_mex_fcn.use_interleaved_complex ();
+
+    return mark_array (new mxArray (interleaved, ov));
   }
 
   // Free an array and its contents.
@@ -2387,7 +3139,7 @@
     return inlist;
   }
 
-  octave_mex_function * current_mex_function (void) const
+  octave_mex_function& current_mex_function (void) const
   {
     return curr_mex_fcn;
   }
@@ -2398,7 +3150,7 @@
 private:
 
   // Pointer to the mex function that corresponds to this mex context.
-  octave_mex_function *curr_mex_fcn;
+  octave_mex_function& curr_mex_fcn;
 
   // List of memory resources that need to be freed upon exit.
   std::set<void *> memlist;
@@ -2438,7 +3190,6 @@
     else
       warning ("%s: value not marked", function_name ());
 #endif
-
   }
 };
 
@@ -2478,8 +3229,9 @@
   return ptr;
 }
 
-static inline void *
-maybe_unmark (void *ptr)
+template <typename T>
+static inline T *
+maybe_unmark (T *ptr)
 {
   if (mex_context)
     mex_context->unmark (ptr);
@@ -2580,116 +3332,235 @@
 
 // Constructors.
 mxArray *
+mxCreateCellArray_interleaved (mwSize ndims, const mwSize *dims)
+{
+  return maybe_mark_array (new mxArray (true, ndims, dims));
+}
+
+mxArray *
 mxCreateCellArray (mwSize ndims, const mwSize *dims)
 {
-  return maybe_mark_array (new mxArray (ndims, dims));
+  return maybe_mark_array (new mxArray (false, ndims, dims));
+}
+
+mxArray *
+mxCreateCellMatrix_interleaved (mwSize m, mwSize n)
+{
+  return maybe_mark_array (new mxArray (true, m, n));
 }
 
 mxArray *
 mxCreateCellMatrix (mwSize m, mwSize n)
 {
-  return maybe_mark_array (new mxArray (m, n));
+  return maybe_mark_array (new mxArray (false, m, n));
+}
+
+mxArray *
+mxCreateCharArray_interleaved (mwSize ndims, const mwSize *dims)
+{
+  return maybe_mark_array (new mxArray (true, mxCHAR_CLASS, ndims, dims));
 }
 
 mxArray *
 mxCreateCharArray (mwSize ndims, const mwSize *dims)
 {
-  return maybe_mark_array (new mxArray (mxCHAR_CLASS, ndims, dims));
+  return maybe_mark_array (new mxArray (false, mxCHAR_CLASS, ndims, dims));
+}
+
+mxArray *
+mxCreateCharMatrixFromStrings_interleaved (mwSize m, const char **str)
+{
+  return maybe_mark_array (new mxArray (true, m, str));
 }
 
 mxArray *
 mxCreateCharMatrixFromStrings (mwSize m, const char **str)
 {
-  return maybe_mark_array (new mxArray (m, str));
+  return maybe_mark_array (new mxArray (false, m, str));
+}
+
+mxArray *
+mxCreateDoubleMatrix_interleaved (mwSize m, mwSize n, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, m, n, flag));
 }
 
 mxArray *
 mxCreateDoubleMatrix (mwSize m, mwSize n, mxComplexity flag)
 {
-  return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, flag));
+  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, m, n, flag));
+}
+
+mxArray *
+mxCreateDoubleScalar_interleaved (double val)
+{
+  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, val));
 }
 
 mxArray *
 mxCreateDoubleScalar (double val)
 {
-  return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, val));
+  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, val));
+}
+
+mxArray *
+mxCreateLogicalArray_interleaved (mwSize ndims, const mwSize *dims)
+{
+  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, ndims, dims));
 }
 
 mxArray *
 mxCreateLogicalArray (mwSize ndims, const mwSize *dims)
 {
-  return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, ndims, dims));
+  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, ndims, dims));
+}
+
+mxArray *
+mxCreateLogicalMatrix_interleaved (mwSize m, mwSize n)
+{
+  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, m, n));
 }
 
 mxArray *
 mxCreateLogicalMatrix (mwSize m, mwSize n)
 {
-  return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n));
+  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, m, n));
+}
+
+mxArray *
+mxCreateLogicalScalar_interleaved (mxLogical val)
+{
+  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, val));
 }
 
 mxArray *
 mxCreateLogicalScalar (mxLogical val)
 {
-  return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, val));
+  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, val));
+}
+
+mxArray *
+mxCreateNumericArray_interleaved (mwSize ndims, const mwSize *dims,
+                                  mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, class_id, ndims, dims, flag));
 }
 
 mxArray *
-mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id,
-                      mxComplexity flag)
-{
-  return maybe_mark_array (new mxArray (class_id, ndims, dims, flag));
+mxCreateNumericArray (mwSize ndims, const mwSize *dims,
+                               mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (false, class_id, ndims, dims, flag));
+}
+
+mxArray *
+mxCreateNumericMatrix_interleaved (mwSize m, mwSize n, mxClassID class_id,
+                                   mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, class_id, m, n, flag));
 }
 
 mxArray *
 mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id,
-                       mxComplexity flag)
-{
-  return maybe_mark_array (new mxArray (class_id, m, n, flag));
+                                mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (false, class_id, m, n, flag));
+}
+
+mxArray *
+mxCreateUninitNumericArray_interleaved (mwSize ndims, const mwSize *dims,
+                                        mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, class_id, ndims, dims, flag,
+                                        false));
 }
 
 mxArray *
 mxCreateUninitNumericArray (mwSize ndims, const mwSize *dims,
-                            mxClassID class_id, mxComplexity flag)
-{
-  return maybe_mark_array (new mxArray (class_id, ndims, dims, flag, false));
+                                     mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (false, class_id, ndims, dims, flag,
+                                        false));
+}
+
+mxArray *
+mxCreateUninitNumericMatrix_interleaved (mwSize m, mwSize n,
+                                         mxClassID class_id, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, class_id, m, n, flag, false));
 }
 
 mxArray *
 mxCreateUninitNumericMatrix (mwSize m, mwSize n, mxClassID class_id,
-                             mxComplexity flag)
-{
-  return maybe_mark_array (new mxArray (class_id, m, n, flag, false));
+                                      mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (false, class_id, m, n, flag, false));
+}
+
+mxArray *
+mxCreateSparse_interleaved (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag)
+{
+  return maybe_mark_array (new mxArray (true, mxDOUBLE_CLASS, m, n, nzmax,
+                                        flag));
 }
 
 mxArray *
 mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag)
 {
-  return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, nzmax, flag));
+  return maybe_mark_array (new mxArray (false, mxDOUBLE_CLASS, m, n, nzmax,
+                                        flag));
+}
+
+mxArray *
+mxCreateSparseLogicalMatrix_interleaved (mwSize m, mwSize n, mwSize nzmax)
+{
+  return maybe_mark_array (new mxArray (true, mxLOGICAL_CLASS, m, n, nzmax));
 }
 
 mxArray *
 mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax)
 {
-  return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n, nzmax));
+  return maybe_mark_array (new mxArray (false, mxLOGICAL_CLASS, m, n, nzmax));
+}
+
+mxArray *
+mxCreateString_interleaved (const char *str)
+{
+  return maybe_mark_array (new mxArray (true, str));
 }
 
 mxArray *
 mxCreateString (const char *str)
 {
-  return maybe_mark_array (new mxArray (str));
+  return maybe_mark_array (new mxArray (false, str));
+}
+
+mxArray *
+mxCreateStructArray_interleaved (mwSize ndims, const mwSize *dims,
+                                 int num_keys, const char **keys)
+{
+  return maybe_mark_array (new mxArray (true, ndims, dims, num_keys, keys));
 }
 
 mxArray *
 mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys,
-                     const char **keys)
-{
-  return maybe_mark_array (new mxArray (ndims, dims, num_keys, keys));
+                              const char **keys)
+{
+  return maybe_mark_array (new mxArray (false, ndims, dims, num_keys, keys));
 }
 
 mxArray *
-mxCreateStructMatrix (mwSize m, mwSize n, int num_keys, const char **keys)
-{
-  return maybe_mark_array (new mxArray (m, n, num_keys, keys));
+mxCreateStructMatrix_interleaved (mwSize m, mwSize n, int num_keys,
+                                  const char **keys)
+{
+  return maybe_mark_array (new mxArray (true, m, n, num_keys, keys));
+}
+
+mxArray *
+mxCreateStructMatrix (mwSize m, mwSize n, int num_keys,
+                               const char **keys)
+{
+  return maybe_mark_array (new mxArray (false, m, n, num_keys, keys));
 }
 
 // Copy constructor.
@@ -2918,12 +3789,6 @@
   return static_cast<double *> (ptr->get_data ());
 }
 
-double *
-mxGetPi (const mxArray *ptr)
-{
-  return static_cast<double *> (ptr->get_imag_data ());
-}
-
 double
 mxGetScalar (const mxArray *ptr)
 {
@@ -2951,12 +3816,121 @@
   return ptr->get_data ();
 }
 
+double *
+mxGetPi (const mxArray *ptr)
+{
+  return static_cast<double *> (ptr->get_imag_data ());
+}
+
 void *
 mxGetImagData (const mxArray *ptr)
 {
   return ptr->get_imag_data ();
 }
 
+mxDouble * mxGetDoubles (const mxArray *ptr)
+{
+  return ptr->get_doubles ();
+}
+
+mxSingle * mxGetSingles (const mxArray *ptr)
+{
+  return ptr->get_singles ();
+}
+
+mxInt8 * mxGetInt8s (const mxArray *ptr)
+{
+  return ptr->get_int8s ();
+}
+
+mxInt16 * mxGetInt16s (const mxArray *ptr)
+{
+  return ptr->get_int16s ();
+}
+
+mxInt32 * mxGetInt32s (const mxArray *ptr)
+{
+  return ptr->get_int32s ();
+}
+
+mxInt64 * mxGetInt64s (const mxArray *ptr)
+{
+  return ptr->get_int64s ();
+}
+
+mxUint8 * mxGetUint8s (const mxArray *ptr)
+{
+  return ptr->get_uint8s ();
+}
+
+mxUint16 * mxGetUint16s (const mxArray *ptr)
+{
+  return ptr->get_uint16s ();
+}
+
+mxUint32 * mxGetUint32s (const mxArray *ptr)
+{
+  return ptr->get_uint32s ();
+}
+
+mxUint64 * mxGetUint64s (const mxArray *ptr)
+{
+  return ptr->get_uint64s ();
+}
+
+mxComplexDouble * mxGetComplexDoubles (const mxArray *ptr)
+{
+  return ptr->get_complex_doubles ();
+}
+
+mxComplexSingle * mxGetComplexSingles (const mxArray *ptr)
+{
+  return ptr->get_complex_singles ();
+}
+
+#if 0
+/* We don't have these yet. */
+mxComplexInt8 * mxGetComplexInt8s (const mxArray *ptr)
+{
+  return ptr->get_complex_int8s ();
+}
+
+mxComplexInt16 * mxGetComplexInt16s (const mxArray *ptr)
+{
+  return ptr->get_complex_int16s ();
+}
+
+mxComplexInt32 * mxGetComplexInt32s (const mxArray *ptr)
+{
+  return ptr->get_complex_int32s ();
+}
+
+mxComplexInt64 * mxGetComplexInt64s (const mxArray *ptr)
+{
+  return ptr->get_complex_int64s ();
+}
+
+mxComplexUint8 * mxGetComplexUint8s (const mxArray *ptr)
+{
+  return ptr->get_complex_uint8s ();
+}
+
+mxComplexUint16 * mxGetComplexUint16s (const mxArray *ptr)
+{
+  return ptr->get_complex_uint16s ();
+}
+
+mxComplexUint32 * mxGetComplexUint32s (const mxArray *ptr)
+{
+  return ptr->get_complex_uint32s ();
+}
+
+mxComplexUint64 * mxGetComplexUint64s (const mxArray *ptr)
+{
+  return ptr->get_complex_uint64s ();
+}
+#endif
+
 // Data setters.
 void
 mxSetPr (mxArray *ptr, double *pr)
@@ -2965,18 +3939,121 @@
 }
 
 void
+mxSetData (mxArray *ptr, void *pr)
+{
+  ptr->set_data (maybe_unmark (pr));
+}
+
+int mxSetDoubles (mxArray *ptr, mxDouble *data)
+{
+  return ptr->set_doubles (maybe_unmark (data));
+}
+
+int mxSetSingles (mxArray *ptr, mxSingle *data)
+{
+  return ptr->set_singles (maybe_unmark (data));
+}
+
+int mxSetInt8s (mxArray *ptr, mxInt8 *data)
+{
+  return ptr->set_int8s (maybe_unmark (data));
+}
+
+int mxSetInt16s (mxArray *ptr, mxInt16 *data)
+{
+  return ptr->set_int16s (maybe_unmark (data));
+}
+
+int mxSetInt32s (mxArray *ptr, mxInt32 *data)
+{
+  return ptr->set_int32s (maybe_unmark (data));
+}
+
+int mxSetInt64s (mxArray *ptr, mxInt64 *data)
+{
+  return ptr->set_int64s (maybe_unmark (data));
+}
+
+int mxSetUint8s (mxArray *ptr, mxUint8 *data)
+{
+  return ptr->set_uint8s (maybe_unmark (data));
+}
+
+int mxSetUint16s (mxArray *ptr, mxUint16 *data)
+{
+  return ptr->set_uint16s (maybe_unmark (data));
+}
+
+int mxSetUint32s (mxArray *ptr, mxUint32 *data)
+{
+  return ptr->set_uint32s (maybe_unmark (data));
+}
+
+int mxSetUint64s (mxArray *ptr, mxUint64 *data)
+{
+  return ptr->set_uint64s (maybe_unmark (data));
+}
+
+int mxSetComplexDoubles (mxArray *ptr, mxComplexDouble *data)
+{
+  return ptr->set_complex_doubles (maybe_unmark (data));
+}
+
+int mxSetComplexSingles (mxArray *ptr, mxComplexSingle *data)
+{
+  return ptr->set_complex_singles (maybe_unmark (data));
+}
+
+#if 0
+/* We don't have these yet. */
+int mxSetComplexInt8s (mxArray *ptr, mxComplexInt8 *data)
+{
+  return ptr->set_complex_int8s (maybe_unmark (data));
+}
+
+int mxSetComplexInt16s (mxArray *ptr, mxComplexInt16 *data)
+{
+  return ptr->set_complex_int16s (maybe_unmark (data));
+}
+
+int mxSetComplexInt32s (mxArray *ptr, mxComplexInt32 *data)
+{
+  return ptr->set_complex_int32s (maybe_unmark (data));
+}
+
+int mxSetComplexInt64s (mxArray *ptr, mxComplexInt64 *data)
+{
+  return ptr->set_complex_int64s (maybe_unmark (data));
+}
+
+int mxSetComplexUint8s (mxArray *ptr, mxComplexUint8 *data)
+{
+  return ptr->set_complex_uint8s (maybe_unmark (data));
+}
+
+int mxSetComplexUint16s (mxArray *ptr, mxComplexUint16 *data)
+{
+  return ptr->set_complex_uint16s (maybe_unmark (data));
+}
+
+int mxSetComplexUint32s (mxArray *ptr, mxComplexUint32 *data)
+{
+  return ptr->set_complex_uint32s (maybe_unmark (data));
+}
+
+int mxSetComplexUint64s (mxArray *ptr, mxComplexUint64 *data)
+{
+  return ptr->set_complex_uint64s (maybe_unmark (data));
+}
+#endif
+
+void
 mxSetPi (mxArray *ptr, double *pi)
 {
   ptr->set_imag_data (maybe_unmark (pi));
 }
 
 void
-mxSetData (mxArray *ptr, void *pr)
-{
-  ptr->set_data (maybe_unmark (pr));
-}
-
-void
 mxSetImagData (mxArray *ptr, void *pi)
 {
   ptr->set_imag_data (maybe_unmark (pi));
@@ -3172,12 +4249,10 @@
   for (int i = 0; i < nout; i++)
     argout[i] = nullptr;
 
-  octave::unwind_protect_safe frame;
-
   // Save old mex pointer.
-  frame.protect_var (mex_context);
-
-  mex context (&mex_fcn);
+  octave::unwind_protect_var<mex *> restore_var (mex_context);
+
+  mex context (mex_fcn);
 
   for (int i = 0; i < nargin; i++)
     argin[i] = context.make_value (args(i));
@@ -3532,8 +4607,8 @@
             {
               octave::tree_evaluator& tw = interp.get_evaluator ();
 
-              frame.add_method (tw, &octave::tree_evaluator::restore_frame,
-                                tw.current_call_stack_frame_number ());
+              frame.add (&octave::tree_evaluator::restore_frame, &tw,
+                         tw.current_call_stack_frame_number ());
 
               tw.goto_base_frame ();
             }
@@ -3597,8 +4672,8 @@
             {
               octave::tree_evaluator& tw = interp.get_evaluator ();
 
-              frame.add_method (tw, &octave::tree_evaluator::restore_frame,
-                                tw.current_call_stack_frame_number ());
+              frame.add (&octave::tree_evaluator::restore_frame, &tw,
+                         tw.current_call_stack_frame_number ());
 
               tw.goto_base_frame ();
             }
@@ -3629,17 +4704,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;
@@ -3647,7 +4733,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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/mexproto.h	Sun May 16 09:44:35 2021 +0200
@@ -62,10 +62,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);
 
@@ -99,8 +108,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);
 
@@ -132,6 +145,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);
@@ -228,20 +262,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	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#! /bin/sh
-
-########################################################################
-##
-## Copyright (C) 2016-2021 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	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,34 @@
+#! /bin/sh
+
+########################################################################
+##
+## Copyright (C) 2016-2021 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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -46,6 +46,7 @@
   %reldir%/hook-fcn.h \
   %reldir%/input.h \
   %reldir%/interpreter.h \
+  %reldir%/latex-text-renderer.h \
   %reldir%/load-path.h \
   %reldir%/load-save.h \
   %reldir%/ls-ascii-helper.h \
@@ -58,6 +59,8 @@
   %reldir%/ls-utils.h \
   %reldir%/mex.h \
   %reldir%/mexproto.h \
+  %reldir%/mx-type-traits.h \
+  %reldir%/mxarray.h \
   %reldir%/oct-errno.h \
   %reldir%/oct-fstrm.h \
   %reldir%/oct-handle.h \
@@ -89,7 +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 \
@@ -123,6 +125,7 @@
   %reldir%/__qp__.cc \
   %reldir%/amd.cc \
   %reldir%/balance.cc \
+  %reldir%/base-text-renderer.cc \
   %reldir%/besselj.cc \
   %reldir%/bitfcns.cc \
   %reldir%/bsxfun.cc \
@@ -185,7 +188,10 @@
   %reldir%/interpreter-private.cc \
   %reldir%/interpreter.cc \
   %reldir%/inv.cc \
+  %reldir%/jsondecode.cc \
+  %reldir%/jsonencode.cc \
   %reldir%/kron.cc \
+  %reldir%/latex-text-renderer.cc \
   %reldir%/load-path.cc \
   %reldir%/load-save.cc \
   %reldir%/lookup.cc \
@@ -218,6 +224,7 @@
   %reldir%/oct-tex-lexer.ll \
   %reldir%/oct-tex-parser.h \
   %reldir%/oct-tex-parser.yy \
+  %reldir%/ordqz.cc \
   %reldir%/ordschur.cc \
   %reldir%/pager.cc \
   %reldir%/pinv.cc \
@@ -298,8 +305,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 && \
@@ -333,11 +340,11 @@
   %reldir%/genprops.awk \
   %reldir%/graphics.in.h \
   %reldir%/mk-errno-list.sh \
-  %reldir%/mk-mxarray-h.in.sh \
-  %reldir%/mxarray.in.h \
+  %reldir%/mk-mxtypes-h.in.sh \
+  %reldir%/mxtypes.in.h \
   %reldir%/oct-errno.in.cc \
   %reldir%/oct-tex-lexer.in.ll \
   %reldir%/oct-tex-symbols.in
 
 GEN_CONFIG_SHELL += \
-  %reldir%/mk-mxarray-h.sh
+  %reldir%/mk-mxtypes-h.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/mx-type-traits.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,151 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_mx_type_traits_h)
+#define octave_mx_type_traits_h 1
+
+#include "octave-config.h"
+
+#include "mxtypes.h"
+#include "oct-inttypes.h"
+
+template <typename T>
+class
+mx_type_traits
+{
+public:
+  static const mxClassID mx_class;
+  typedef T mx_type;
+};
+
+template <>
+class
+mx_type_traits<bool>
+{
+public:
+  static const mxClassID mx_class = mxLOGICAL_CLASS;
+  typedef mxDouble mx_type;
+};
+
+template <>
+class
+mx_type_traits<char>
+{
+public:
+  static const mxClassID mx_class = mxCHAR_CLASS;
+  typedef mxChar mx_type;
+};
+
+template <>
+class
+mx_type_traits<double>
+{
+public:
+  static const mxClassID mx_class = mxDOUBLE_CLASS;
+  typedef mxDouble mx_type;
+};
+
+template <>
+class
+mx_type_traits<float>
+{
+public:
+  static const mxClassID mx_class = mxSINGLE_CLASS;
+  typedef mxSingle mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_int8>
+{
+public:
+  static const mxClassID mx_class = mxINT8_CLASS;
+  typedef mxInt8 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_uint8>
+{
+public:
+  static const mxClassID mx_class = mxUINT8_CLASS;
+  typedef mxUint8 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_int16>
+{
+public:
+  static const mxClassID mx_class = mxINT16_CLASS;
+  typedef mxInt16 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_uint16>
+{
+public:
+  static const mxClassID mx_class = mxUINT16_CLASS;
+  typedef mxUint16 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_int32>
+{
+public:
+  static const mxClassID mx_class = mxINT32_CLASS;
+  typedef mxInt32 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_uint32>
+{
+public:
+  static const mxClassID mx_class = mxUINT32_CLASS;
+  typedef mxUint32 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_int64>
+{
+public:
+  static const mxClassID mx_class = mxINT64_CLASS;
+  typedef mxInt64 mx_type;
+};
+
+template <>
+class
+mx_type_traits<octave_uint64>
+{
+public:
+  static const mxClassID mx_class = mxUINT64_CLASS;
+  typedef mxUint64 mx_type;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/mxarray.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,747 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2021 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 OCTINTERP_API mxArray;
+
+// A class to provide the default implementation of some of the
+// virtual functions declared in the mxArray class.
+
+class OCTINTERP_API mxArray_base
+{
+protected:
+
+  OCTINTERP_API 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 std::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;
+
+  std::size_t get_numeric_element_size (std::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:
+
+  OCTINTERP_API mxArray (bool interleaved, const octave_value& ov);
+
+  OCTINTERP_API mxArray (bool interleaved, mxClassID id, mwSize ndims,
+                         const mwSize *dims, mxComplexity flag = mxREAL,
+                         bool init = true);
+
+  OCTINTERP_API mxArray (bool interleaved, mxClassID id, const dim_vector& dv,
+                         mxComplexity flag = mxREAL);
+
+  OCTINTERP_API mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
+                         mxComplexity flag = mxREAL, bool init = true);
+
+  OCTINTERP_API mxArray (bool interleaved, mxClassID id, double val);
+
+  OCTINTERP_API mxArray (bool interleaved, mxClassID id, mxLogical val);
+
+  OCTINTERP_API mxArray (bool interleaved, const char *str);
+
+  OCTINTERP_API mxArray (bool interleaved, mwSize m, const char **str);
+
+  OCTINTERP_API mxArray (bool interleaved, mxClassID id, mwSize m, mwSize n,
+                         mwSize nzmax, mxComplexity flag = mxREAL);
+
+  OCTINTERP_API mxArray (bool interleaved, mwSize ndims, const mwSize *dims,
+                         int num_keys, const char **keys);
+
+  OCTINTERP_API mxArray (bool interleaved, const dim_vector& dv, int num_keys,
+                         const char **keys);
+
+  OCTINTERP_API mxArray (bool interleaved, mwSize m, mwSize n, int num_keys,
+                         const char **keys);
+
+  OCTINTERP_API mxArray (bool interleaved, mwSize ndims, const mwSize *dims);
+
+  OCTINTERP_API mxArray (bool interleaved, const dim_vector& dv);
+
+  OCTINTERP_API 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;
+
+  OCTINTERP_API ~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; }
+
+  OCTINTERP_API 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); }
+
+  std::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 OCTINTERP_API void * malloc (std::size_t n);
+
+  static OCTINTERP_API void * calloc (std::size_t n, std::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 OCTINTERP_API octave_value
+  as_octave_value (const mxArray *ptr, bool null_is_empty = true);
+
+  OCTINTERP_API 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 OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, const octave_value& ov);
+
+  static OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, mxClassID id, mwSize ndims,
+              const mwSize *dims, mxComplexity flag, bool init);
+
+  static OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, mxClassID id, const dim_vector& dv,
+              mxComplexity flag);
+
+  static OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
+              mxComplexity flag, bool init);
+
+  static OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, mxClassID id, double val);
+
+  static OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, mxClassID id, mxLogical val);
+
+  static OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, const char *str);
+
+  static OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, mwSize m, const char **str);
+
+  static OCTINTERP_API mxArray_base *
+  create_rep (bool interleaved, mxClassID id, mwSize m, mwSize n,
+              mwSize nzmax, mxComplexity flag);
+
+  OCTINTERP_API void maybe_mutate (void) const;
+};
+
+#undef DO_MUTABLE_METHOD
+#undef DO_VOID_MUTABLE_METHOD
+
+#endif
+#endif
--- a/libinterp/corefcn/mxarray.in.h	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,570 +0,0 @@
-// %NO_EDIT_WARNING%
-
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2001-2021 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 std::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); }
-
-  std::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 (std::size_t n);
-
-  static void * calloc (std::size_t n, std::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	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,128 @@
+// %NO_EDIT_WARNING%
+
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001-2021 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-handle.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-handle.h	Sun May 16 09:44:35 2021 +0200
@@ -52,9 +52,9 @@
           {
             val = a.double_value ();
           }
-        catch (octave::execution_exception& e)
+        catch (octave::execution_exception& ee)
           {
-            error (e, "invalid handle");
+            error (ee, "invalid handle");
           }
       }
   }
--- a/libinterp/corefcn/oct-hist.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-hist.cc	Sun May 16 09:44:35 2021 +0200
@@ -261,12 +261,6 @@
     return name;
   }
 
-  static void
-  unlink_cleanup (const char *file)
-  {
-    octave_unlink_wrapper (file);
-  }
-
   history_system::history_system (interpreter& interp)
     : m_interpreter (interp), m_input_from_tmp_file (false),
       m_timestamp_format_string (default_timestamp_format ())
@@ -327,12 +321,14 @@
   {
     bool numbered_output = nargout == 0;
 
-    unwind_protect frame;
+    unwind_action restore_history_filename
+      ([] (const std::string& old_filename)
+       {
+         command_history::set_file (old_filename);
+       }, command_history::file ());
 
     string_vector hlist;
 
-    frame.add_fcn (command_history::set_file, command_history::file ());
-
     int nargin = args.length ();
 
     // Number of history lines to show (-1 = all)
@@ -467,7 +463,7 @@
     volatile interrupt_handler old_interrupt_handler
       = ignore_interrupts ();
 
-    int status = system (cmd.c_str ());
+    int status = octave::sys::system (cmd);
 
     set_interrupt_handler (old_interrupt_handler);
 
@@ -500,12 +496,9 @@
 
     file.close ();
 
-    unwind_protect frame;
-
-    frame.add_fcn (unlink_cleanup, name.c_str ());
-    frame.protect_var (m_input_from_tmp_file);
-
-    m_input_from_tmp_file = true;
+    int(*unlink_fptr)(const std::string&) = octave::sys::unlink;
+    unwind_action unlink_action (unlink_fptr, name);
+    unwind_protect_var<bool> upv (m_input_from_tmp_file, true);
 
     // FIXME: instead of sourcing a file, we should just iterate through
     // the list of commands, parsing and executing them one at a time as
@@ -521,12 +514,9 @@
     if (name.empty ())
       return;
 
-    unwind_protect frame;
-
-    frame.add_fcn (unlink_cleanup, name.c_str ());
-    frame.protect_var (m_input_from_tmp_file);
-
-    m_input_from_tmp_file = true;
+    int(*unlink_fptr)(const std::string&) = octave::sys::unlink;
+    unwind_action unlink_action (unlink_fptr, name);
+    unwind_protect_var<bool> upv (m_input_from_tmp_file, true);
 
     // FIXME: instead of sourcing a file, we should just iterate through
     // the list of commands, parsing and executing them one at a time as
@@ -545,8 +535,18 @@
       file = env_file;
 
     if (file.empty ())
-      file = sys::file_ops::concat (sys::env::get_home_directory (),
-                                    ".octave_hist");
+      {
+        // Default to $DATA/octave/history, where $DATA is the platform-
+        // dependent location for (roaming) user data files.
+
+        std::string user_data_dir = sys::env::get_user_data_directory ();
+
+        std::string hist_dir = user_data_dir + sys::file_ops::dir_sep_str ()
+                               + "octave";
+
+        file = sys::env::make_absolute ("history", hist_dir);
+      }
+
 
     return file;
   }
@@ -819,8 +819,11 @@
 All future commands issued during the current Octave session will be written to
 this new file (if the current setting of @code{history_save} allows for this).
 
-The default value is @file{~/.octave_hist}, but may be overridden by the
-environment variable @w{@env{OCTAVE_HISTFILE}}.
+The default value is @file{@w{@env{$DATA}}/octave/history}, where
+@w{@env{$DATA}} is the platform-specific location for (roaming) user data files
+(e.g. @w{@env{$XDG_DATA_HOME}} or, if that is not set, @file{~/.local/share} on
+Unix-like operating systems or @w{@env{%APPDATA%}} on Windows).  The default
+value may be overridden by the environment variable @w{@env{OCTAVE_HISTFILE}}.
 
 Programming Notes:
 
--- a/libinterp/corefcn/oct-hist.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-hist.h	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 {
   class interpreter;
 
-  class history_system
+  class OCTINTERP_API history_system
   {
   public:
 
--- a/libinterp/corefcn/oct-map.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-map.cc	Sun May 16 09:44:35 2021 +0200
@@ -564,8 +564,8 @@
 %! reshape (x, 3, 8, 1, 1);
 
 %!test <*46385>
-%! M = repmat (struct ('a', ones(100), 'b', true), 1, 2);
-%! M = repmat(M, 1, 2);
+%! M = repmat (struct ('a', ones (100), 'b', true), 1, 2);
+%! M = repmat (M, 1, 2);
 %! assert (size (M), [1, 4]);
 
 libinterp/corefcn/oct-map.cc
@@ -680,9 +680,9 @@
                                      new_map_list[i], perm);
         }
     }
-  catch (octave::execution_exception& e)
+  catch (octave::execution_exception& ee)
     {
-      error (e, "cat: field names mismatch in concatenating structs");
+      error (ee, "cat: field names mismatch in concatenating structs");
     }
 }
 
@@ -845,7 +845,7 @@
 */
 
 octave_map
-octave_map::index (const idx_vector& i, bool resize_ok) const
+octave_map::index (const octave::idx_vector& i, bool resize_ok) const
 {
   octave_map retval (xkeys);
   octave_idx_type nf = nfields ();
@@ -869,7 +869,7 @@
 }
 
 octave_map
-octave_map::index (const idx_vector& i, const idx_vector& j,
+octave_map::index (const octave::idx_vector& i, const octave::idx_vector& j,
                    bool resize_ok) const
 {
   octave_map retval (xkeys);
@@ -894,7 +894,7 @@
 }
 
 octave_map
-octave_map::index (const Array<idx_vector>& ia, bool resize_ok) const
+octave_map::index (const Array<octave::idx_vector>& ia, bool resize_ok) const
 {
   octave_map retval (xkeys);
   octave_idx_type nf = nfields ();
@@ -935,7 +935,7 @@
         {
         case 1:
           {
-            idx_vector i = idx(0).index_vector ();
+            octave::idx_vector i = idx(0).index_vector ();
 
             retval = index (i, resize_ok);
           }
@@ -943,10 +943,10 @@
 
         case 2:
           {
-            idx_vector i = idx(0).index_vector ();
+            octave::idx_vector i = idx(0).index_vector ();
 
             k = 1;
-            idx_vector j = idx(1).index_vector ();
+            octave::idx_vector j = idx(1).index_vector ();
 
             retval = index (i, j, resize_ok);
           }
@@ -954,7 +954,7 @@
 
         default:
           {
-            Array<idx_vector> ia (dim_vector (n_idx, 1));
+            Array<octave::idx_vector> ia (dim_vector (n_idx, 1));
 
             for (k = 0; k < n_idx; k++)
               ia(k) = idx(k).index_vector ();
@@ -964,10 +964,10 @@
           break;
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (n_idx, k+1);
+      ie.set_pos_if_unset (n_idx, k+1);
       throw;
     }
 
@@ -978,20 +978,20 @@
 octave_map
 octave_map::column (octave_idx_type k) const
 {
-  return index (idx_vector::colon, k);
+  return index (octave::idx_vector::colon, k);
 }
 
 octave_map
 octave_map::page (octave_idx_type k) const
 {
-  static Array<idx_vector> ia (dim_vector (3, 1), idx_vector::colon);
+  static Array<octave::idx_vector> ia (dim_vector (3, 1), octave::idx_vector::colon);
 
   ia(2) = k;
   return index (ia);
 }
 
 void
-octave_map::assign (const idx_vector& i, const octave_map& rhs)
+octave_map::assign (const octave::idx_vector& i, const octave_map& rhs)
 {
   if (rhs.xkeys.is_same (xkeys))
     {
@@ -1027,9 +1027,9 @@
         {
           rhs1 = rhs.orderfields (*this, perm);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          error (e, "incompatible fields in struct assignment");
+          error (ee, "incompatible fields in struct assignment");
         }
 
       assert (rhs1.xkeys.is_same (xkeys));
@@ -1038,7 +1038,7 @@
 }
 
 void
-octave_map::assign (const idx_vector& i, const idx_vector& j,
+octave_map::assign (const octave::idx_vector& i, const octave::idx_vector& j,
                     const octave_map& rhs)
 {
   if (rhs.xkeys.is_same (xkeys))
@@ -1075,9 +1075,9 @@
         {
           rhs1 = rhs.orderfields (*this, perm);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          error (e, "incompatible fields in struct assignment");
+          error (ee, "incompatible fields in struct assignment");
         }
 
       assert (rhs1.xkeys.is_same (xkeys));
@@ -1086,7 +1086,7 @@
 }
 
 void
-octave_map::assign (const Array<idx_vector>& ia,
+octave_map::assign (const Array<octave::idx_vector>& ia,
                     const octave_map& rhs)
 {
   if (rhs.xkeys.is_same (xkeys))
@@ -1123,9 +1123,9 @@
         {
           rhs1 = rhs.orderfields (*this, perm);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          error (e, "incompatible fields in struct assignment");
+          error (ee, "incompatible fields in struct assignment");
         }
 
       assert (rhs1.xkeys.is_same (xkeys));
@@ -1150,7 +1150,7 @@
         {
         case 1:
           {
-            idx_vector i = idx(0).index_vector ();
+            octave::idx_vector i = idx(0).index_vector ();
 
             assign (i, rhs);
           }
@@ -1158,10 +1158,10 @@
 
         case 2:
           {
-            idx_vector i = idx(0).index_vector ();
+            octave::idx_vector i = idx(0).index_vector ();
 
             k = 1;
-            idx_vector j = idx(1).index_vector ();
+            octave::idx_vector j = idx(1).index_vector ();
 
             assign (i, j, rhs);
           }
@@ -1169,7 +1169,7 @@
 
         default:
           {
-            Array<idx_vector> ia (dim_vector (n_idx, 1));
+            Array<octave::idx_vector> ia (dim_vector (n_idx, 1));
 
             for (k = 0; k < n_idx; k++)
               ia(k) = idx(k).index_vector ();
@@ -1179,10 +1179,10 @@
           break;
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (n_idx, k+1);
+      ie.set_pos_if_unset (n_idx, k+1);
       throw;
     }
 }
@@ -1226,7 +1226,7 @@
 */
 
 void
-octave_map::delete_elements (const idx_vector& i)
+octave_map::delete_elements (const octave::idx_vector& i)
 {
   octave_idx_type nf = nfields ();
   for (octave_idx_type k = 0; k < nf; k++)
@@ -1246,7 +1246,7 @@
 }
 
 void
-octave_map::delete_elements (int dim, const idx_vector& i)
+octave_map::delete_elements (int dim, const octave::idx_vector& i)
 {
   octave_idx_type nf = nfields ();
   for (octave_idx_type k = 0; k < nf; k++)
@@ -1266,7 +1266,7 @@
 }
 
 void
-octave_map::delete_elements (const Array<idx_vector>& ia)
+octave_map::delete_elements (const Array<octave::idx_vector>& ia)
 {
   octave_idx_type nf = nfields ();
   for (octave_idx_type k = 0; k < nf; k++)
@@ -1290,7 +1290,7 @@
 {
   octave_idx_type n_idx = idx.length ();
 
-  Array<idx_vector> ia (dim_vector (n_idx, 1));
+  Array<octave::idx_vector> ia (dim_vector (n_idx, 1));
 
   for (octave_idx_type i = 0; i < n_idx; i++)
     {
@@ -1298,10 +1298,10 @@
         {
           ia(i) = idx(i).index_vector ();
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
           // Rethrow to allow more info to be reported later.
-          e.set_pos_if_unset (n_idx, i+1);
+          ie.set_pos_if_unset (n_idx, i+1);
           throw;
         }
     }
--- a/libinterp/corefcn/oct-map.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-map.h	Sun May 16 09:44:35 2021 +0200
@@ -443,12 +443,12 @@
   static octave_map
   cat (int dim, octave_idx_type n, const octave_map *map_list);
 
-  octave_map index (const idx_vector& i, bool resize_ok = false) const;
+  octave_map index (const octave::idx_vector& i, bool resize_ok = false) const;
 
-  octave_map index (const idx_vector& i, const idx_vector& j,
+  octave_map index (const octave::idx_vector& i, const octave::idx_vector& j,
                     bool resize_ok = false) const;
 
-  octave_map index (const Array<idx_vector>& ia,
+  octave_map index (const Array<octave::idx_vector>& ia,
                     bool resize_ok = false) const;
 
   octave_map index (const octave_value_list&, bool resize_ok = false) const;
@@ -456,22 +456,23 @@
   octave_map column (octave_idx_type k) const;
   octave_map page (octave_idx_type k) const;
 
-  void assign (const idx_vector& i, const octave_map& rhs);
+  void assign (const octave::idx_vector& i, const octave_map& rhs);
 
-  void assign (const idx_vector& i, const idx_vector& j, const octave_map& rhs);
+  void assign (const octave::idx_vector& i, const octave::idx_vector& j,
+               const octave_map& rhs);
 
-  void assign (const Array<idx_vector>& ia, const octave_map& rhs);
+  void assign (const Array<octave::idx_vector>& ia, const octave_map& rhs);
 
   void assign (const octave_value_list&, const octave_map& rhs);
 
   void assign (const octave_value_list& idx, const std::string& k,
                const Cell& rhs);
 
-  void delete_elements (const idx_vector& i);
+  void delete_elements (const octave::idx_vector& i);
 
-  void delete_elements (int dim, const idx_vector& i);
+  void delete_elements (int dim, const octave::idx_vector& i);
 
-  void delete_elements (const Array<idx_vector>& ia);
+  void delete_elements (const Array<octave::idx_vector>& ia);
 
   void delete_elements (const octave_value_list&);
 
--- a/libinterp/corefcn/oct-process.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-process.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,6 @@
 
 namespace octave
 {
-  OCTINTERP_API
   process_execution_result
   process_execution_result::of_success (int exit_status,
                                         const std::string& stdout_output)
@@ -41,7 +40,6 @@
     return process_execution_result (0, exit_status, stdout_output, "");
   }
 
-  OCTINTERP_API
   process_execution_result
   process_execution_result::of_error (int status, const std::string& err_msg)
   {
@@ -49,7 +47,6 @@
   }
 
   // Execute a shell command, returning results as a C++ object
-  OCTINTERP_API
   process_execution_result
   run_command_and_return_output (const std::string& cmd_str)
   {
--- a/libinterp/corefcn/oct-process.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-process.h	Sun May 16 09:44:35 2021 +0200
@@ -32,7 +32,6 @@
 
 namespace octave
 {
-  OCTINTERP_API
   class
   process_execution_result
   {
@@ -49,10 +48,10 @@
         m_stdout_output (stdout_output)
     { }
 
-    static process_execution_result
+    static OCTINTERP_API process_execution_result
     of_success (int exit_status, const std::string& stdout_output);
 
-    static process_execution_result
+    static OCTINTERP_API process_execution_result
     of_error (int status, const std::string& err_msg);
 
     int status (void) const { return m_status; }
--- a/libinterp/corefcn/oct-stream.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-stream.cc	Sun May 16 09:44:35 2021 +0200
@@ -97,8 +97,7 @@
       }
     catch (const execution_exception&)
       {
-        octave::interpreter& interp
-          = __get_interpreter__ ("convert_to_valid_int");
+        interpreter& interp = __get_interpreter__ ("convert_to_valid_int");
 
         interp.recover_from_exception ();
 
@@ -1513,7 +1512,7 @@
   {
     char *retval;
 
-    if (eob  - idx > size)
+    if (eob - idx > size)
       {
         retval = idx;
         idx += size;
@@ -1914,7 +1913,7 @@
 
     bool match_literal (delimited_stream& isp, const textscan_format_elt& elem);
 
-    int skip_whitespace (delimited_stream& is, bool EOLstop = false);
+    int skip_whitespace (delimited_stream& is, bool EOLstop = true);
 
     int skip_delim (delimited_stream& is);
 
@@ -2472,7 +2471,7 @@
     while (! ds.eof ())
       {
         bool already_skipped_delim = false;
-        ts.skip_whitespace (ds);
+        ts.skip_whitespace (ds, false);
         ds.progress_benchmark ();
         ts.scan_complex (ds, *fmt_elts[0], val);
         if (ds.fail ())
@@ -2714,8 +2713,8 @@
               dv = dim_vector (std::max (valid_rows - 1, 0), 1);
 
             ra_idx(1) = i;
-            retval = do_cat_op (retval, octave_value (Cell (col.resize (dv,0))),
-                                ra_idx);
+            retval = cat_op (retval, octave_value (Cell (col.resize (dv,0))),
+                             ra_idx);
             i++;
           }
       }
@@ -2734,8 +2733,7 @@
                 if (prev_type != -1)
                   {
                     ra_idx(1) = i++;
-                    retval = do_cat_op (retval, octave_value (Cell (cur)),
-                                        ra_idx);
+                    retval = cat_op (retval, octave_value (Cell (cur)), ra_idx);
                   }
                 cur = octave_value (col.resize (dv,0));
                 group_size = 1;
@@ -2744,12 +2742,11 @@
             else
               {
                 ra_idx(1) = group_size++;
-                cur = do_cat_op (cur, octave_value (col.resize (dv,0)),
-                                 ra_idx);
+                cur = cat_op (cur, octave_value (col.resize (dv,0)), ra_idx);
               }
           }
         ra_idx(1) = i;
-        retval = do_cat_op (retval, octave_value (Cell (cur)), ra_idx);
+        retval = cat_op (retval, octave_value (Cell (cur)), ra_idx);
       }
 
     return retval;
@@ -2960,7 +2957,7 @@
       {
         char *pos = is.tellg ();
         std::ios::iostate state = is.rdstate ();
-        //re = octave_read_value<double> (is);
+        //re = read_value<double> (is);
         re = read_double (is, fmt);
 
         // check for "treat as empty" string
@@ -3025,7 +3022,7 @@
                 pos   = is.tellg ();
                 state = is.rdstate ();
 
-                //im = octave_read_value<double> (is);
+                //im = read_value<double> (is);
                 im = read_double (is, fmt);
                 if (is.fail ())
                   im = 1;
@@ -3276,7 +3273,7 @@
                     else
                       {
                         if (ov.isreal ())  // cat does type conversion
-                          ov = do_cat_op (ov, octave_value (v), row);
+                          ov = cat_op (ov, octave_value (v), row);
                         else
                           ov.internal_rep ()->fast_elem_insert (row(0), v);
                       }
@@ -3289,7 +3286,7 @@
                     else
                       {
                         if (ov.isreal ())  // cat does type conversion
-                          ov = do_cat_op (ov, octave_value (v), row);
+                          ov = cat_op (ov, octave_value (v), row);
                         else
                           ov.internal_rep ()->fast_elem_insert (row(0),
                                                                 FloatComplex (v));
@@ -3374,7 +3371,7 @@
           }
 
         if (is.fail () & ! fmt.discard)
-          ov = do_cat_op (ov, empty_value, row);
+          ov = cat_op (ov, empty_value, row);
       }
     else
       {
@@ -3500,11 +3497,12 @@
         elem = fmt_list.next ();
         char *pos = is.tellg ();
 
-        // FIXME: these conversions "ignore delimiters".  Should they include
-        // delimiters at the start of the conversion, or can those be skipped?
-        if (elem->type != textscan_format_elt::literal_conversion
-            // && elem->type != '[' && elem->type != '^' && elem->type != 'c'
-           )
+        // Skip delimiter before reading the next fmt conversion,
+        // unless the fmt is a string literal which begins with a delimiter,
+        // in which case the literal must match everything.  Bug #58008
+        if (elem->type != textscan_format_elt::literal_conversion)
+          skip_delim (is);
+        else if (! is_delim (elem->text[0]))
           skip_delim (is);
 
         if (is.eof ())
@@ -3892,8 +3890,8 @@
   int
   textscan::skip_delim (delimited_stream& is)
   {
-    int c1 = skip_whitespace (is, true);  // 'true': stop once EOL is read
-    if (delim_list.numel () == 0)         // single character delimiter
+    int c1 = skip_whitespace (is);  // Stop once EOL is read
+    if (delim_list.numel () == 0)   // single character delimiter
       {
         if (is_delim (c1) || c1 == eol1 || c1 == eol2)
           {
@@ -3943,7 +3941,7 @@
                 int prev = -1;
                 // skip multiple delims.
                 // Increment lines for each end-of-line seen; for \r\n, decrement
-                while (is && ((c1 = skip_whitespace (is, true))
+                while (is && ((c1 = skip_whitespace (is))
                               != std::istream::traits_type::eof ())
                        && (((c1 == eol1 || c1 == eol2) && ++lines)
                            || -1 != lookahead (is, delim_list, delim_len)))
@@ -4369,7 +4367,7 @@
             {
               is.putback (c1);
 
-              ref = octave_read_value<double> (is);
+              ref = read_value<double> (is);
             }
         }
         break;
@@ -5459,10 +5457,10 @@
   private:
 
     const octave_value_list values;
-    int val_idx;
-    int elt_idx;
-    int n_vals;
-    int n_elts;
+    octave_idx_type val_idx;
+    octave_idx_type elt_idx;
+    octave_idx_type n_vals;
+    octave_idx_type n_elts;
     bool have_data;
     octave_value curr_val;
     state curr_state;
@@ -5715,7 +5713,7 @@
         // Easier than dispatching here...
 
         octave_value ov_is_ge_zero
-          = do_binary_op (octave_value::op_ge, val, octave_value (0.0));
+          = binary_op (octave_value::op_ge, val, octave_value (0.0));
 
         return ov_is_ge_zero.is_true ();
       }
@@ -6340,36 +6338,6 @@
       m_rep->close ();
   }
 
-  // FIXME: maybe these should be defined in lo-ieee.h?
-
-  template <typename T>
-  static inline bool
-  is_old_NA (T)
-  {
-    return false;
-  }
-
-  template <>
-  inline bool
-  is_old_NA<double> (double val)
-  {
-    return __lo_ieee_is_old_NA (val);
-  }
-
-  template <typename T>
-  static inline T
-  replace_old_NA (T val)
-  {
-    return val;
-  }
-
-  template <>
-  inline double
-  replace_old_NA<double> (double val)
-  {
-    return __lo_ieee_replace_old_NA (val);
-  }
-
   template <typename SRC_T, typename DST_T>
   static octave_value
   convert_and_copy (std::list<void *>& input_buf_list,
@@ -6405,12 +6373,14 @@
                                                   1, from_flt_fmt,
                                                   mach_info::native_float_format ());
 
-                    dst_elt_type tmp (data[i]);
-
-                    if (is_old_NA (tmp))
-                      tmp = replace_old_NA (tmp);
-
-                    conv_data[j] = tmp;
+                    // FIXME: Potentially add conversion code for MIPS NA here
+                    //        Bug #59830.
+                    // dst_elt_type tmp (data[i]);
+                    // if (is_MIPS_NA (tmp))
+                    //  tmp = replace_MIPS_NA (tmp);
+                    // conv_data[j] = tmp;
+
+                    conv_data[j] = data[i];
                   }
               }
             else
@@ -6436,12 +6406,8 @@
                 for (octave_idx_type i = 0; i < input_buf_elts && j < elts_read;
                      i++, j++)
                   {
-                    dst_elt_type tmp (data[i]);
-
-                    if (is_old_NA (tmp))
-                      tmp = replace_old_NA (tmp);
-
-                    conv_data[j] = tmp;
+                    // FIXME: Potentially add conversion code for MIPS NA here
+                    conv_data[j] = data[i];
                   }
               }
             else
@@ -7086,7 +7052,7 @@
 
 #define INSTANTIATE_WRITE(T)                                            \
   template                                                              \
-  octave_idx_type                                                       \
+  OCTINTERP_API octave_idx_type                                         \
   stream::write (const Array<T>& data, octave_idx_type block_size,      \
                  oct_data_conv::data_type output_type,                  \
                  octave_idx_type skip,                                  \
--- a/libinterp/corefcn/oct-stream.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/oct-stream.h	Sun May 16 09:44:35 2021 +0200
@@ -160,16 +160,16 @@
 
     // Set current error state and set fail to TRUE.
 
-    void error (const std::string& msg);
-    void error (const std::string& who, const std::string& msg);
+    OCTINTERP_API void error (const std::string& msg);
+    OCTINTERP_API void error (const std::string& who, const std::string& msg);
 
     // Clear any error message and set fail to FALSE.
 
-    void clear (void);
+    OCTINTERP_API void clear (void);
 
     // Clear stream state.
 
-    void clearerr (void);
+    OCTINTERP_API void clearerr (void);
 
   private:
 
@@ -195,57 +195,69 @@
     // Functions that are defined for all input streams (input streams
     // are those that define is).
 
-    std::string do_gets (octave_idx_type max_len, bool& err, bool strip_newline,
-                         const std::string& who /* = "gets" */);
+    OCTINTERP_API std::string
+    do_gets (octave_idx_type max_len, bool& err, bool strip_newline,
+             const std::string& who /* = "gets" */);
 
-    std::string getl (octave_idx_type max_len, bool& err,
-                      const std::string& who /* = "getl" */);
-    std::string gets (octave_idx_type max_len, bool& err,
-                      const std::string& who /* = "gets" */);
-    off_t skipl (off_t count, bool& err, const std::string& who /* = "skipl" */);
+    OCTINTERP_API std::string
+    getl (octave_idx_type max_len, bool& err,
+          const std::string& who /* = "getl" */);
+    OCTINTERP_API std::string
+    gets (octave_idx_type max_len, bool& err,
+          const std::string& who /* = "gets" */);
+    OCTINTERP_API off_t
+    skipl (off_t count, bool& err, const std::string& who /* = "skipl" */);
 
-    octave_value do_scanf (scanf_format_list& fmt_list, octave_idx_type nr,
-                           octave_idx_type nc,
-                           bool one_elt_size_spec, octave_idx_type& count,
-                           const std::string& who /* = "scanf" */);
+    OCTINTERP_API octave_value
+    do_scanf (scanf_format_list& fmt_list, octave_idx_type nr,
+              octave_idx_type nc, bool one_elt_size_spec,
+              octave_idx_type& count, const std::string& who /* = "scanf" */);
 
-    octave_value scanf (const std::string& fmt, const Array<double>& size,
-                        octave_idx_type& count, const std::string& who /* = "scanf" */);
+    OCTINTERP_API octave_value
+    scanf (const std::string& fmt, const Array<double>& size,
+           octave_idx_type& count, const std::string& who /* = "scanf" */);
 
-    bool do_oscanf (const scanf_format_elt *elt, octave_value&,
-                    const std::string& who /* = "scanf" */);
+    OCTINTERP_API bool
+    do_oscanf (const scanf_format_elt *elt, octave_value&,
+               const std::string& who /* = "scanf" */);
 
-    octave_value_list oscanf (const std::string& fmt,
-                              const std::string& who /* = "scanf" */);
+    OCTINTERP_API octave_value_list
+    oscanf (const std::string& fmt, const std::string& who /* = "scanf" */);
 
-    octave_value do_textscan (const std::string& fmt, octave_idx_type ntimes,
-                              const octave_value_list& options,
-                              const std::string& who, octave_idx_type& count);
+    OCTINTERP_API octave_value
+    do_textscan (const std::string& fmt, octave_idx_type ntimes,
+                 const octave_value_list& options,
+                 const std::string& who, octave_idx_type& count);
 
     // Functions that are defined for all output streams (output streams
     // are those that define os).
 
-    int flush (void);
+    OCTINTERP_API int flush (void);
 
-    int do_numeric_printf_conv (std::ostream& os, const printf_format_elt *elt,
-                                int nsa, int sa_1, int sa_2,
-                                const octave_value& val,
-                                const std::string& who);
+    OCTINTERP_API int
+    do_numeric_printf_conv (std::ostream& os, const printf_format_elt *elt,
+                            int nsa, int sa_1, int sa_2,
+                            const octave_value& val,
+                            const std::string& who);
+
+    OCTINTERP_API void field_width_error (const std::string& who) const;
 
-    void field_width_error (const std::string& who) const;
-
-    int do_printf (printf_format_list& fmt_list, const octave_value_list& args,
-                   const std::string& who /* = "printf" */);
+    OCTINTERP_API int
+    do_printf (printf_format_list& fmt_list, const octave_value_list& args,
+               const std::string& who /* = "printf" */);
 
-    int printf (const std::string& fmt, const octave_value_list& args,
-                const std::string& who /* = "printf" */);
+    OCTINTERP_API int
+    printf (const std::string& fmt, const octave_value_list& args,
+            const std::string& who /* = "printf" */);
 
-    int puts (const std::string& s, const std::string& who /* = "puts" */);
+    OCTINTERP_API int
+    puts (const std::string& s, const std::string& who /* = "puts" */);
 
     // We can always do this in terms of seek(), so the derived class
     // only has to provide that.
 
-    void invalid_operation (const std::string& who, const char *rw);
+    OCTINTERP_API void
+    invalid_operation (const std::string& who, const char *rw);
   };
 
   class
@@ -263,82 +275,101 @@
 
     ~stream (void) = default;
 
-    int flush (void);
+    OCTINTERP_API int flush (void);
 
-    std::string getl (octave_idx_type max_len, bool& err,
-                      const std::string& who /* = "getl" */);
-    std::string getl (const octave_value& max_len, bool& err,
-                      const std::string& who /* = "getl" */);
+    OCTINTERP_API std::string
+    getl (octave_idx_type max_len, bool& err,
+          const std::string& who /* = "getl" */);
+
+    OCTINTERP_API std::string
+    getl (const octave_value& max_len, bool& err,
+          const std::string& who /* = "getl" */);
 
-    std::string gets (octave_idx_type max_len, bool& err,
-                      const std::string& who /* = "gets" */);
-    std::string gets (const octave_value& max_len, bool& err,
-                      const std::string& who /* = "gets" */);
+    OCTINTERP_API std::string
+    gets (octave_idx_type max_len, bool& err,
+          const std::string& who /* = "gets" */);
+
+    OCTINTERP_API std::string
+    gets (const octave_value& max_len, bool& err,
+          const std::string& who /* = "gets" */);
 
-    off_t skipl (off_t count, bool& err, const std::string& who /* = "skipl" */);
-    off_t skipl (const octave_value& count, bool& err,
-                 const std::string& who /* = "skipl" */);
+    OCTINTERP_API off_t
+    skipl (off_t count, bool& err, const std::string& who /* = "skipl" */);
 
-    int seek (off_t offset, int origin);
-    int seek (const octave_value& offset, const octave_value& origin);
+    OCTINTERP_API off_t
+    skipl (const octave_value& count, bool& err,
+           const std::string& who /* = "skipl" */);
 
-    off_t tell (void);
+    OCTINTERP_API int seek (off_t offset, int origin);
 
-    int rewind (void);
+    OCTINTERP_API int
+    seek (const octave_value& offset, const octave_value& origin);
+
+    OCTINTERP_API off_t tell (void);
 
-    bool is_open (void) const;
+    OCTINTERP_API int rewind (void);
 
-    void close (void);
+    OCTINTERP_API bool is_open (void) const;
+
+    OCTINTERP_API void close (void);
 
-    octave_value read (const Array<double>& size, octave_idx_type block_size,
-                       oct_data_conv::data_type input_type,
-                       oct_data_conv::data_type output_type,
-                       octave_idx_type skip, mach_info::float_format flt_fmt,
-                       octave_idx_type& count);
+    OCTINTERP_API octave_value
+    read (const Array<double>& size, octave_idx_type block_size,
+          oct_data_conv::data_type input_type,
+          oct_data_conv::data_type output_type,
+          octave_idx_type skip, mach_info::float_format flt_fmt,
+          octave_idx_type& count);
 
-    octave_idx_type write (const octave_value& data, octave_idx_type block_size,
-                           oct_data_conv::data_type output_type,
-                           octave_idx_type skip,
-                           mach_info::float_format flt_fmt);
+    OCTINTERP_API octave_idx_type
+    write (const octave_value& data, octave_idx_type block_size,
+           oct_data_conv::data_type output_type,
+           octave_idx_type skip, mach_info::float_format flt_fmt);
 
-    bool write_bytes (const void *data, std::size_t n_elts);
+    OCTINTERP_API bool write_bytes (const void *data, std::size_t n_elts);
 
-    bool skip_bytes (std::size_t n_elts);
+    OCTINTERP_API bool skip_bytes (std::size_t n_elts);
 
     template <typename T>
-      octave_idx_type write (const Array<T>& data, octave_idx_type block_size,
-                             oct_data_conv::data_type output_type,
-                             octave_idx_type skip,
-                             mach_info::float_format flt_fmt);
+    OCTINTERP_API octave_idx_type
+    write (const Array<T>& data, octave_idx_type block_size,
+           oct_data_conv::data_type output_type,
+           octave_idx_type skip, mach_info::float_format flt_fmt);
 
-    octave_value scanf (const std::string& fmt, const Array<double>& size,
-                        octave_idx_type& count, const std::string& who /* = "scanf" */);
+    OCTINTERP_API octave_value
+    scanf (const std::string& fmt, const Array<double>& size,
+           octave_idx_type& count, const std::string& who /* = "scanf" */);
 
-    octave_value scanf (const octave_value& fmt, const Array<double>& size,
-                        octave_idx_type& count, const std::string& who /* = "scanf" */);
+    OCTINTERP_API octave_value
+    scanf (const octave_value& fmt, const Array<double>& size,
+           octave_idx_type& count, const std::string& who /* = "scanf" */);
 
-    octave_value_list oscanf (const std::string& fmt,
-                              const std::string& who /* = "scanf" */);
+    OCTINTERP_API octave_value_list
+    oscanf (const std::string& fmt, const std::string& who /* = "scanf" */);
 
-    octave_value_list oscanf (const octave_value& fmt,
-                              const std::string& who /* = "scanf" */);
+    OCTINTERP_API octave_value_list
+    oscanf (const octave_value& fmt, const std::string& who /* = "scanf" */);
 
-    octave_value textscan (const std::string& fmt, octave_idx_type ntimes,
-                           const octave_value_list& options,
-                           const std::string& who, octave_idx_type& count);
+    OCTINTERP_API octave_value
+    textscan (const std::string& fmt, octave_idx_type ntimes,
+              const octave_value_list& options,
+              const std::string& who, octave_idx_type& count);
 
-    int printf (const std::string& fmt, const octave_value_list& args,
-                const std::string& who /* = "printf" */);
+    OCTINTERP_API int
+    printf (const std::string& fmt, const octave_value_list& args,
+            const std::string& who /* = "printf" */);
 
-    int printf (const octave_value& fmt, const octave_value_list& args,
-                const std::string& who /* = "printf" */);
+    OCTINTERP_API int
+    printf (const octave_value& fmt, const octave_value_list& args,
+            const std::string& who /* = "printf" */);
 
-    int puts (const std::string& s, const std::string& who /* = "puts" */);
-    int puts (const octave_value& s, const std::string& who /* = "puts" */);
+    OCTINTERP_API int
+    puts (const std::string& s, const std::string& who /* = "puts" */);
+    OCTINTERP_API int
+    puts (const octave_value& s, const std::string& who /* = "puts" */);
 
-    bool eof (void) const;
+    OCTINTERP_API bool eof (void) const;
 
-    std::string error (bool clear, int& err_num);
+    OCTINTERP_API std::string error (bool clear, int& err_num);
 
     std::string error (bool clear = false)
     {
@@ -364,13 +395,13 @@
 
     operator bool () const { return ok (); }
 
-    std::string name (void) const;
+    OCTINTERP_API std::string name (void) const;
 
-    int mode (void) const;
+    OCTINTERP_API int mode (void) const;
 
-    mach_info::float_format float_format (void) const;
+    OCTINTERP_API mach_info::float_format float_format (void) const;
 
-    static std::string mode_as_string (int mode);
+    OCTINTERP_API static std::string mode_as_string (int mode);
 
     std::string encoding (void)
     {
@@ -415,7 +446,7 @@
         m_rep->invalid_operation (who, rw);
     }
 
-    octave_value
+    OCTINTERP_API octave_value
     finalize_read (std::list<void *>& input_buf_list,
                    octave_idx_type input_buf_elts,
                    octave_idx_type elts_read,
@@ -431,35 +462,36 @@
   {
   public:
 
-    stream_list (interpreter& interp);
+    OCTINTERP_API stream_list (interpreter& interp);
 
     stream_list (const stream_list&) = delete;
     stream_list& operator = (const stream_list&) = delete;
 
-    ~stream_list (void);
+    OCTINTERP_API ~stream_list (void);
 
-    int insert (stream& os);
+    OCTINTERP_API int insert (stream& os);
 
-    stream lookup (int fid, const std::string& who = "") const;
-    stream lookup (const octave_value& fid, const std::string& who = "") const;
+    OCTINTERP_API stream lookup (int fid, const std::string& who = "") const;
+    OCTINTERP_API stream
+    lookup (const octave_value& fid, const std::string& who = "") const;
 
-    int remove (int fid, const std::string& who = "");
-    int remove (const octave_value& fid, const std::string& who = "");
+    OCTINTERP_API int remove (int fid, const std::string& who = "");
+    OCTINTERP_API int remove (const octave_value& fid, const std::string& who = "");
 
-    void clear (bool flush = true);
+    OCTINTERP_API void clear (bool flush = true);
 
-    string_vector get_info (int fid) const;
-    string_vector get_info (const octave_value& fid) const;
+    OCTINTERP_API string_vector get_info (int fid) const;
+    OCTINTERP_API string_vector get_info (const octave_value& fid) const;
 
-    std::string list_open_files (void) const;
+    OCTINTERP_API std::string list_open_files (void) const;
 
-    octave_value open_file_numbers (void) const;
+    OCTINTERP_API octave_value open_file_numbers (void) const;
 
-    int get_file_number (const octave_value& fid) const;
+    OCTINTERP_API int get_file_number (const octave_value& fid) const;
 
-    octave_value stdin_file (void) const;
-    octave_value stdout_file (void) const;
-    octave_value stderr_file (void) const;
+    OCTINTERP_API octave_value stdin_file (void) const;
+    OCTINTERP_API octave_value stdout_file (void) const;
+    OCTINTERP_API octave_value stderr_file (void) const;
 
   private:
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/ordqz.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,678 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+// Generalized eigenvalue reordering via LAPACK
+
+// Originally written by M. Koehler <koehlerm(AT)mpi-magdeburg.mpg.de>
+
+#undef DEBUG
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <cctype>
+#include <cmath>
+
+#include "f77-fcn.h"
+#include "lo-lapack-proto.h"
+#include "qr.h"
+#include "quit.h"
+
+#include "defun.h"
+#include "error.h"
+#include "errwarn.h"
+#include "ovl.h"
+
+
+#if defined (DEBUG)
+#  include "pager.h"
+#  include "pr-output.h"
+#endif
+
+
+DEFUN (ordqz, args, nargout,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {[@var{AR}, @var{BR}, @var{QR}, @var{ZR}] =} ordqz (@var{AA}, @var{BB}, @var{Q}, @var{Z}, @var{keyword})
+@deftypefnx {} {[@var{AR}, @var{BR}, @var{QR}, @var{ZR}] =} ordqz (@var{AA}, @var{BB}, @var{Q}, @var{Z}, @var{select})
+Reorder the QZ@tie{}decomposition of a generalized eigenvalue problem.
+
+The generalized eigenvalue problem is defined as
+
+@tex
+$$A x = \lambda B x$$
+@end tex
+@ifnottex
+
+@math{A x = @var{lambda} B x}
+
+@end ifnottex
+
+Its generalized Schur decomposition is computed using the @code{qz} algorithm:
+
+@code{[@var{AA}, @var{BB}, @var{Q}, @var{Z}] = qz (@var{A}, @var{B})}
+
+where @var{AA}, @var{BB}, @var{Q}, and @var{Z} fulfill
+@tex
+$$ AA = Q \cdot A \cdot Z, BB = Q \cdot B \cdot Z $$
+@end tex
+@ifnottex
+
+@example
+@group
+
+@var{AA} = @var{Q} * @var{A} * @var{Z}, @var{BB} = @var{Q} * @var{B} * @var{Z}
+
+@end group
+@end example
+
+@end ifnottex
+
+The @code{ordqz} function computes a unitary transformation @var{QR} and
+@var{ZR} such that the order of the eigenvalue on the diagonal of @var{AA} and
+@var{BB} is changed.  The resulting reordered matrices @var{AR} and @var{BR}
+fulfill:
+
+@tex
+$$ A_R = Q_R \cdot A \cdot Z_R, B_R = Q_R \cdot B \cdot Z_R $$
+@end tex
+@ifnottex
+
+@example
+@group
+
+@var{AR} = @var{QR} * @var{A} * @var{ZR}, @var{BR} = @var{QR} * @var{B} * @var{ZR}
+
+@end group
+@end example
+
+@end ifnottex
+
+The function can either be called with the @var{keyword} argument which
+selects the eigenvalues in the top left block of @var{AR} and @var{BR} in the
+following way:
+
+@table @asis
+@item @qcode{"S"}, @qcode{"udi"}
+small: leading block has all
+@tex
+$|\lambda| < 1$
+@end tex
+@ifnottex
+|@var{lambda}| < 1
+@end ifnottex
+
+@item @qcode{"B"}, @qcode{"udo"}
+big: leading block has all
+@tex
+$|\lambda| \geq 1$
+@end tex
+@ifnottex
+|@var{lambda}| @geq{} 1
+@end ifnottex
+
+@item @qcode{"-"}, @qcode{"lhp"}
+negative real part: leading block has all eigenvalues in the open left
+half-plane
+
+@item @qcode{"+"}, @qcode{"rhp"}
+non-negative real part: leading block has all eigenvalues in the closed right
+half-plane
+@end table
+
+If a logical vector @var{select} is given instead of a keyword the @code{ordqz}
+function reorders all eigenvalues @code{k} to the left block for which
+@code{select(k)} is true.
+
+Note: The keywords are compatible with the ones from @code{qr}.
+
+@seealso{eig, ordeig, qz, schur, ordschur}
+@end deftypefn */)
+{
+  enum { LHP, RHP, UDI, UDO, VEC, NONE } select_mode = NONE;
+
+  if (args.length () != 5)
+    print_usage ();
+
+  // Check select argument
+  if (args(4).is_string())
+    {
+      std::string opts = args(4).string_value ();
+      std::for_each (opts.begin (), opts.end (),
+                     [] (char & c) { c = std::tolower (c); });
+      if (opts == "lhp" || opts == "-")
+        select_mode = LHP;
+      else if (opts == "rhp" || opts == "+")
+        select_mode = RHP;
+      else if (opts == "udi" || opts == "s")
+        select_mode = UDI;
+      else if (opts == "udo" || opts == "b")
+        select_mode = UDO;
+      else
+        error_with_id ("Octave:ordqz:unknown-keyword",
+                       "ordqz: unknown KEYWORD, possible values: "
+                       "lhp, rhp, udi, udo");
+    }
+  else if (args(4).isreal () || args(4).isinteger () || args(4).islogical ())
+    {
+      if (args(4).rows () > 1 && args(4).columns () > 1)
+        error_with_id ("Octave:ordqz:select-not-vector",
+                       "ordqz: SELECT argument must be a vector");
+      select_mode = VEC;
+    }
+  else
+    error_with_id ("Octave:ordqz:unknown-arg",
+                   "ordqz: OPT must be string or a logical vector");
+
+  if (nargout > 4)
+    error_with_id ("Octave:ordqz:nargout",
+                   "ordqz: at most four output arguments possible");
+
+  // Matrix A: check dimensions.
+  F77_INT nn = octave::to_f77_int (args(0).rows ());
+  F77_INT nc = octave::to_f77_int (args(0).columns ());
+
+  if (args(0).isempty ())
+    {
+      warn_empty_arg ("qz: A");
+      return octave_value_list (2, Matrix ());
+    }
+  else if (nc != nn)
+    err_square_matrix_required ("qz", "A");
+
+  // Matrix A: get value.
+  Matrix aa;
+  ComplexMatrix caa;
+
+  if (args(0).iscomplex ())
+    caa = args(0).complex_matrix_value ();
+  else
+    aa = args(0).matrix_value ();
+
+  // Extract argument 2 (bb, or cbb if complex).
+  F77_INT b_nr = octave::to_f77_int (args(1).rows ());
+  F77_INT b_nc = octave::to_f77_int (args(1).columns ());
+
+  if (nn != b_nc || nn != b_nr)
+    err_nonconformant ();
+
+  Matrix bb;
+  ComplexMatrix cbb;
+
+  if (args(1).iscomplex ())
+    cbb = args(1).complex_matrix_value ();
+  else
+    bb = args(1).matrix_value ();
+
+  // Extract argument 3 (qq, or cqq if complex).
+  F77_INT q_nr = octave::to_f77_int (args(2).rows ());
+  F77_INT q_nc = octave::to_f77_int (args(2).columns ());
+
+  if (nn != q_nc || nn != q_nr)
+    err_nonconformant ();
+
+  Matrix qq;
+  ComplexMatrix cqq;
+
+  if (args(2).iscomplex ())
+    cqq = args(2).complex_matrix_value ().hermitian ();
+  else
+    qq = args(2).matrix_value ().transpose ();
+
+  // Extract argument 4 (zz, or czz if complex).
+  F77_INT z_nr = octave::to_f77_int (args(3).rows ());
+  F77_INT z_nc = octave::to_f77_int (args(3).columns ());
+
+  if (nn != z_nc || nn != z_nr)
+    err_nonconformant ();
+
+  Matrix zz;
+  ComplexMatrix czz;
+
+  if (args(3).iscomplex ())
+    czz = args(3).complex_matrix_value ();
+  else
+    zz = args(3).matrix_value ();
+
+  bool complex_case = (args(0).iscomplex () || args(1).iscomplex ()
+                       || args(2).iscomplex () || args(3).iscomplex ());
+
+  if (select_mode == VEC && args(4).rows () != nn && args(4).columns () != nn)
+    error_with_id ("Octave:ordqz:numel_select",
+                   "ordqz: SELECT vector has the wrong number of elements");
+
+  Array<double> select_array (dim_vector (nn, 1));
+  if (select_mode == VEC)
+    select_array = args(4).vector_value ();
+
+  Array<F77_LOGICAL> select (dim_vector (nn, 1));
+
+  if (complex_case)
+    {
+      // Complex
+      if (args(0).isreal ())
+        caa = ComplexMatrix (aa);
+      if (args(1).isreal ())
+        cbb = ComplexMatrix (bb);
+      if (args(2).isreal ())
+        cqq = ComplexMatrix (qq);
+      if (args(3).isreal ())
+        czz = ComplexMatrix (zz);
+
+      ComplexRowVector alpha (dim_vector (nn, 1));
+      ComplexRowVector beta  (dim_vector (nn, 1));
+      octave_idx_type k;
+
+      for (k = 0; k < nn-1; k++)
+        {
+          if (caa(k+1,k) != 0.0)
+            error_with_id ("Octave:ordqz:unsupported_AA",
+                           "ordqz: quasi upper triangular matrices are not "
+                           "allowed with complex data");
+        }
+
+      for (k = 0; k < nn; k++)
+        {
+          alpha(k) = caa(k,k);
+          beta(k)  = cbb(k,k);
+        }
+
+      for (k = 0; k < nn; k++)
+        {
+          switch (select_mode)
+            {
+            case LHP:
+              select(k) = real (alpha(k) * beta(k)) < 0;
+              break;
+            case RHP:
+              select(k) = real (alpha(k) * beta(k)) > 0;
+              break;
+            case UDI:
+              if (beta(k) != 0.0)
+                select(k) = abs (alpha(k)/beta(k)) < 1.0;
+              else
+                select(k) = false;
+              break;
+            case UDO:
+              if (beta(k) != 0.0)
+                select(k) = abs (alpha(k)/beta(k)) > 1.0;
+              else
+                select(k) = true;
+              break;
+            case VEC:
+              if (select_array(k) != 0.0)
+                select(k) = true;
+              else
+                select(k) = false;
+              break;
+            default:
+              // default: case just here to suppress compiler warning.
+              panic_impossible ();
+            }
+        }
+
+      F77_LOGICAL wantq, wantz;
+      wantq = 1,  wantz = 1;
+      F77_INT ijob, mm, lrwork3, liwork, info;
+      ijob = 0,  lrwork3 = 1,  liwork = 1;
+      F77_DBLE pl, pr;
+      ComplexRowVector work3 (lrwork3);
+      Array<F77_INT> iwork (dim_vector (liwork, 1));
+
+      F77_XFCN (ztgsen, ZTGSEN,
+                (ijob, wantq, wantz,
+                 select.fortran_vec (), nn,
+                 F77_DBLE_CMPLX_ARG (caa.fortran_vec ()), nn,
+                 F77_DBLE_CMPLX_ARG (cbb.fortran_vec ()), nn,
+                 F77_DBLE_CMPLX_ARG (alpha.fortran_vec ()),
+                 F77_DBLE_CMPLX_ARG (beta.fortran_vec ()),
+                 F77_DBLE_CMPLX_ARG (cqq.fortran_vec ()), nn,
+                 F77_DBLE_CMPLX_ARG (czz.fortran_vec ()), nn,
+                 mm,
+                 pl, pr,
+                 nullptr,
+                 F77_DBLE_CMPLX_ARG (work3.fortran_vec ()), lrwork3,
+                 iwork.fortran_vec (), liwork,
+                 info));
+      if (info != 0)
+        error_with_id ("Octave:ordqz:ztgsen_failed",
+                       "ordqz: failed to reorder eigenvalues");
+    }
+  else
+    {
+      // Extract eigenvalues
+      RowVector alphar (dim_vector (nn, 1));
+      RowVector alphai (dim_vector (nn, 1));
+      RowVector beta (dim_vector (nn, 1));
+
+      octave_idx_type k;
+
+      k = 0;
+      while (k < nn)
+        {
+#ifdef DEBUG
+          octave_stdout << "ordqz: k = " << k  << " nn = " << nn << " \n";
+#endif
+          if ((k < nn-1 && aa(k+1,k) == 0.0) || k == nn-1)
+            {
+              alphar(k) = aa(k,k);
+              alphai(k) = 0.0;
+              beta(k)   = bb(k,k);
+              k++;
+            }
+          else
+            {
+              double ar[2], ai[2], b[2], work[4];
+              char qz_job = 'E';
+              char comp_q = 'N';
+              char comp_z = 'N';
+              F77_INT nl = 2;
+              F77_INT ilo = 1;
+              F77_INT ihi = 2;
+              F77_INT lwork = 4;
+              F77_INT info = 0;
+              double * aa_vec = aa.fortran_vec ();
+              double * bb_vec = bb.fortran_vec ();
+
+              F77_XFCN (dhgeqz, DHGEQZ,
+                        (F77_CONST_CHAR_ARG2 (&qz_job, 1),
+                         F77_CONST_CHAR_ARG2 (&comp_q, 1),
+                         F77_CONST_CHAR_ARG2 (&comp_z, 1),
+                         nl, ilo, ihi,
+                         &aa_vec[k+k*nn] , nn,
+                         &bb_vec[k+k*nn], nn,
+                         ar, ai, b,
+                         nullptr, nn,
+                         nullptr, nn, work, lwork, info
+                         F77_CHAR_ARG_LEN (1)
+                         F77_CHAR_ARG_LEN (1)
+                         F77_CHAR_ARG_LEN (1)));
+              if (info != 0)
+                error("ordqz: failed to extract eigenvalues");
+
+              alphar(k)   = ar[0];
+              alphar(k+1) = ar[1];
+              alphai(k)   = ai[0];
+              alphai(k+1) = ai[1];
+              beta(k)   = b[0];
+              beta(k+1) = b[1];
+
+              k += 2;
+            }
+
+        }
+
+      for (k = 0; k < nn; k++)
+        {
+          switch (select_mode)
+            {
+            case LHP:
+              select(k) = alphar(k) * beta(k) < 0;
+              break;
+            case RHP:
+              select(k) = alphar(k) * beta(k) > 0;
+              break;
+            case UDI:
+              select(k) = alphar(k)*alphar(k)
+                          + alphai(k)*alphai(k) < beta(k)*beta(k);
+              break;
+            case UDO:
+              select(k) = alphar(k)*alphar(k)
+                          + alphai(k)*alphai(k) > beta(k)*beta(k);
+              break;
+            case VEC:
+              if (select_array(k) != 0.0)
+                select(k) = true;
+              else
+                select(k) = false;
+              break;
+            default:
+              // default: case just here to suppress compiler warning.
+              panic_impossible();
+            }
+        }
+
+      F77_LOGICAL wantq, wantz;
+      wantq = 1,  wantz = 1;
+      F77_INT ijob, mm, lrwork3, liwork, info;
+      ijob = 0,  lrwork3 = 4*nn+16,  liwork = nn;
+      F77_DBLE pl, pr;
+      RowVector rwork3 (lrwork3);
+      Array<F77_INT> iwork (dim_vector (liwork, 1));
+
+      F77_XFCN (dtgsen, DTGSEN,
+                (ijob, wantq, wantz,
+                 select.fortran_vec (), nn,
+                 aa.fortran_vec (), nn,
+                 bb.fortran_vec (), nn,
+                 alphar.fortran_vec (),
+                 alphai.fortran_vec (),
+                 beta.fortran_vec (),
+                 qq.fortran_vec (), nn,
+                 zz.fortran_vec (), nn,
+                 mm,
+                 pl, pr,
+                 nullptr,
+                 rwork3.fortran_vec (), lrwork3,
+                 iwork.fortran_vec (), liwork,
+                 info));
+      if (info != 0)
+        error("ordqz: failed to reorder eigenvalues");
+    }
+
+  octave_value_list retval (nargout);
+  switch (nargout)
+    {
+    case 4:
+      if (complex_case)
+        retval(3) = czz;
+      else
+        retval(3) = zz;
+      OCTAVE_FALLTHROUGH;
+    case 3:
+      if (complex_case)
+        retval(2) = cqq.hermitian();
+      else
+        retval(2) = qq.transpose();
+      OCTAVE_FALLTHROUGH;
+    case 2:
+      if (complex_case)
+        retval(1) = cbb;
+      else
+        retval(1) = bb;
+      OCTAVE_FALLTHROUGH;
+    case 1:
+      if (complex_case)
+        retval(0) = caa;
+      else
+        retval(0) = aa;
+      break;
+    case 0:
+      if (complex_case)
+        retval(0) = caa;
+      else
+        retval(0) = aa;
+      break;
+    }
+
+  return retval;
+}
+
+
+/*
+%!shared A, B, AA, BB, QQ, ZZ, AC, BC, AAC, BBC, QQC, ZZC, select, selectc
+%! A = [ -1.03428  0.24929  0.43205 -0.12860;
+%!        1.16228  0.27870  2.12954  0.69250;
+%!       -0.51524 -0.34939 -0.77820  2.13721;
+%!       -1.32941  2.11870  0.72005  1.00835 ];
+%! B = [  1.407302 -0.632956 -0.360628  0.068534;
+%!        0.149898  0.298248  0.991777  0.023652;
+%!        0.169281 -0.405205 -1.775834  1.511730;
+%!        0.717770  1.291390 -1.766607 -0.531352 ];
+%! AC = [ 0.4577 + 0.7199i   0.1476 + 0.6946i   0.6202 + 0.2092i   0.7559 + 0.2759i;
+%!        0.5868 + 0.7275i   0.9174 + 0.8781i   0.6741 + 0.1985i   0.4320 + 0.7023i;
+%!        0.2408 + 0.6359i   0.2959 + 0.8501i   0.3904 + 0.5613i   0.5000 + 0.1428i;
+%!        0.8177 + 0.8581i   0.2583 + 0.8970i   0.7706 + 0.5451i   0.1068 + 0.1650i];
+%! BC = [ 0.089898 + 0.209257i   0.157769 + 0.311387i   0.018926 + 0.622517i   0.058825 + 0.374647i;
+%!        0.009367 + 0.098211i   0.736087 + 0.095797i   0.973192 + 0.583765i   0.434018 + 0.461909i;
+%!        0.880784 + 0.868215i   0.032839 + 0.569461i   0.873437 + 0.266081i   0.739426 + 0.362017i;
+%!        0.121649 + 0.115111i   0.426695 + 0.492222i   0.247670 + 0.034414i   0.771629 + 0.078153i];
+%! [AA, BB, QQ, ZZ] = qz (A, B);
+%! [AAC, BBC, QQC, ZZC] = qz (AC, BC);
+%! select = [0 0 1 1];
+%! selectc = [0 0 0 1];
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "rhp");
+%! assert (all (real (eig (AAX(1:3,1:3), BBX(1:3,1:3))) >= 0));
+%! assert (all (real (eig (AAX(4:4,4:4), BBX(4:4,4:4))) < 0));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "+");
+%! assert (all (real (eig (AAX(1:3,1:3), BBX(1:3,1:3))) >= 0));
+%! assert (all (real (eig (AAX(4:4,4:4), BBX(4:4,4:4))) < 0));
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "lhp");
+%! assert (all (real (eig (AAX(2:4,2:4), BBX(2:4,2:4))) >= 0));
+%! assert (all (real (eig (AAX(1:1,1:1), BBX(1:1,1:1))) < 0));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "-");
+%! assert (all (real (eig (AAX(2:4,2:4), BBX(2:4,2:4))) >= 0));
+%! assert (all (real (eig (AAX(1:1,1:1), BBX(1:1,1:1))) < 0));
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "udi");
+%! assert (all (abs (eig (AAX(1:1,1:1), BBX(1:1,1:1))) < 1));
+%! assert (all (abs (eig (AAX(2:4,2:4), BBX(2:4,2:4))) > 1));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "S");
+%! assert (all (abs (eig (AAX(1:1,1:1), BBX(1:1,1:1))) < 1));
+%! assert (all (abs (eig (AAX(2:4,2:4), BBX(2:4,2:4))) > 1));
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "udo");
+%! assert (all (abs (eig (AAX(1:3,1:3), BBX(1:3,1:3))) >= 1));
+%! assert (all (abs (eig (AAX(4:4,4:4), BBX(4:4,4:4))) < 1));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, "B");
+%! assert (all (abs (eig (AAX(1:3,1:3), BBX(1:3,1:3))) >= 1));
+%! assert (all (abs (eig (AAX(4:4,4:4), BBX(4:4,4:4))) < 1));
+
+%!test
+%! [AAX, BBX, QQX, ZZX] = ordqz (AA, BB, QQ, ZZ, select);
+%! assert (all (iscomplex (eig (AAX(1:2,1:2), BBX(1:2,1:2)))));
+%! assert (norm (QQX'*AAX*ZZX' - A, "fro"), 0, 1e-12);
+%! assert (norm (QQX'*BBX*ZZX' - B, "fro"), 0, 1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, "rhp");
+%! assert (all (real (eig (AACX(1:2,1:2), BBCX(1:2,1:2))) >= 0));
+%! assert (all (real (eig (AACX(3:4,3:4), BBCX(3:4,3:4))) < 0));
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0, 1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, "lhp");
+%! assert (all (real (eig (AACX(1:2,1:2), BBCX(1:2,1:2))) < 0));
+%! assert (all (real (eig (AACX(3:4,3:4), BBCX(3:4,3:4))) >= 0));
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0, 1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, "udi");
+%! assert (all (abs (eig (AACX(1:2,1:2), BBCX(1:2,1:2))) < 1));
+%! assert (all (abs (eig (AACX(3:4,3:4), BBCX(3:4,3:4))) >= 1));
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0, 1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, "udo");
+%! assert (all (abs (eig (AACX(1:2,1:2), BBCX(1:2,1:2))) >= 1));
+%! assert (all (abs (eig (AACX(3:4,3:4), BBCX(3:4,3:4))) < 1));
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0,  1e-12);
+
+%!test
+%! [AACX, BBCX, QQCX, ZZCX] = ordqz (AAC, BBC, QQC, ZZC, selectc);
+%! ev = abs (eig (AACX(1:1,1:1), BBCX(1:1,1:1)));
+%! assert(ev > 0.6 && ev < 0.7);
+%! assert (norm (QQCX'*AACX*ZZCX' - AC, "fro"), 0, 1e-12);
+%! assert (norm (QQCX'*BBCX*ZZCX' - BC, "fro"), 0, 1e-12);
+
+%!test
+%! A = toeplitz ([1,2,3,4]);
+%! [B, A] = qr (A);
+%! B = B';
+%! [AA, BB, Q, Z] = qz (A, B);
+%! [AAS, BBS, QS, ZS] = ordqz (AA, BB, Q, Z, "lhp");
+%! E2 = ordeig (AAS, BBS);
+%! ECOMP = [-3.414213562373092; -1.099019513592784;
+%!          -0.5857864376269046; 9.099019513592784];
+%! assert (norm (ECOMP - E2, "Inf"), 0, 1e-8);
+
+## Test input validation
+%!error <Invalid call> ordqz ()
+%!error <Invalid call> ordqz (eye (2))
+%!error <Invalid call> ordqz (eye (2), eye (2))
+%!error <Invalid call> ordqz (eye (2), eye (2), eye (2))
+%!error <Invalid call> ordqz (eye (2), eye (2), eye (2), eye (2))
+%!error id=Octave:ordqz:unknown-keyword
+%! ordqz (eye (2), eye (2), eye (2), eye (2), "foobar");
+%!error id=Octave:ordqz:select-not-vector
+%! ordqz (eye (2), eye (2), eye (2), eye (2), eye (2));
+%!error id=Octave:ordqz:unknown-arg
+%! ordqz (eye (2), eye (2), eye (2), eye (2), {"foobar"});
+%!error id=Octave:ordqz:nargout
+%! [a,b,c,d,e] = ordqz (eye (2), eye (2), eye (2), eye (2), "udi");
+%!warning <A: argument is empty matrix> ordqz ([], [], [], [], "udi");
+%!error <A must be a square matrix> ordqz (ones (1,2), [], [], [], "udi");
+%!error <nonconformant matrices>
+%! ordqz (eye (3), eye (2), eye (2), eye (2), "udi");
+%!error <nonconformant matrices>
+%! ordqz (eye (2), eye (3), eye (2), eye (2), "udi");
+%!error <nonconformant matrices>
+%! ordqz (eye (2), eye (2), eye (3), eye (2), "udi");
+%!error <nonconformant matrices>
+%! ordqz (eye (2), eye (2), eye (2), eye (3), "udi");
+%!error <SELECT vector .* wrong number of elements>
+%! ordqz (eye (2), eye (2), eye (2), eye (2), ones (1,5));
+%!error <quasi upper triangular matrices are not allowed with complex data>
+%! AA = zeros (2, 2);
+%! AA(2,1) = i;
+%! ordqz (AA, eye (2), eye (2), eye (2), "udi");
+
+*/
--- a/libinterp/corefcn/ordschur.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/ordschur.cc	Sun May 16 09:44:35 2021 +0200
@@ -74,7 +74,7 @@
 [@var{U}, @var{S}] = ordschur (@var{U}, @var{S}, [0,1])
 @end example
 
-@seealso{schur, ordeig}
+@seealso{schur, ordeig, ordqz}
 @end deftypefn */)
 {
   if (args.length () != 3)
--- a/libinterp/corefcn/pager.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/pager.cc	Sun May 16 09:44:35 2021 +0200
@@ -324,10 +324,8 @@
   {
     if (! m_flushing_output_to_pager)
       {
-        unwind_protect frame;
-
-        frame.protect_var (m_really_flush_to_pager);
-        frame.protect_var (m_flushing_output_to_pager);
+        unwind_protect_var<bool> restore_var1 (m_really_flush_to_pager);
+        unwind_protect_var<bool> restore_var2 (m_flushing_output_to_pager);
 
         m_really_flush_to_pager = true;
         m_flushing_output_to_pager = true;
@@ -379,13 +377,17 @@
 
   bool output_system::sync (const char *buf, int len)
   {
-    if (! m_interpreter.interactive ()
+    // FIXME: The following seems to be a bit of a mess.
+
+    if (m_interpreter.server_mode ()
+        || ! m_interpreter.interactive ()
         || application::forced_interactive ()
         || m_really_flush_to_pager
         || (m_page_screen_output && m_page_output_immediately)
         || ! m_page_screen_output)
       {
-        bool bypass_pager = (! m_interpreter.interactive ()
+        bool bypass_pager = (m_interpreter.server_mode ()
+                             || ! m_interpreter.interactive ()
                              || application::forced_interactive ()
                              || ! m_page_screen_output
                              || (m_really_flush_to_pager
@@ -441,8 +443,17 @@
       {
         if (bypass_pager)
           {
-            std::cout.write (msg, len);
-            std::cout.flush ();
+            if (m_interpreter.server_mode ())
+              {
+                event_manager& evmgr = m_interpreter.get_event_manager ();
+
+                evmgr.interpreter_output (std::string (msg, len));
+              }
+            else
+              {
+                std::cout.write (msg, len);
+                std::cout.flush ();
+              }
           }
         else
           {
--- a/libinterp/corefcn/pager.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/pager.h	Sun May 16 09:44:35 2021 +0200
@@ -129,7 +129,7 @@
     diary_buf *db;
   };
 
-  extern OCTAVE_API void flush_stdout (void);
+  extern OCTINTERP_API void flush_stdout (void);
 
   class output_system
   {
@@ -305,9 +305,9 @@
     void do_sync (const char *msg, int len, bool bypass_pager);
   };
 
-  extern std::ostream& __stdout__ (void);
+  extern OCTINTERP_API std::ostream& __stdout__ (void);
 
-  extern std::ostream& __diary__ (void);
+  extern OCTINTERP_API std::ostream& __diary__ (void);
 }
 
 #define octave_stdout (octave::__stdout__ ())
--- a/libinterp/corefcn/pr-flt-fmt.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/pr-flt-fmt.h	Sun May 16 09:44:35 2021 +0200
@@ -40,11 +40,12 @@
 template <typename T>
 class pr_rational_float;
 
-extern int output_precision (void);
+extern OCTINTERP_API int output_precision (void);
 
-extern void set_output_prec (int prec);
+extern OCTINTERP_API void set_output_prec (int prec);
 
 class
+OCTINTERP_API
 float_format
 {
 public:
@@ -205,6 +206,7 @@
 };
 
 class
+OCTINTERP_API
 float_display_format
 {
 public:
--- a/libinterp/corefcn/pr-output.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/pr-output.cc	Sun May 16 09:44:35 2021 +0200
@@ -1319,7 +1319,7 @@
 
 template <>
 float_display_format
-make_format (const Range& r)
+make_format (const octave::range<double>& r)
 {
   if (free_format)
     return float_display_format ();
@@ -2161,13 +2161,13 @@
               nm += buf.str ();
             }
 
-          Array<idx_vector> idx (dim_vector (ndims, 1));
-
-          idx(0) = idx_vector (':');
-          idx(1) = idx_vector (':');
+          Array<octave::idx_vector> idx (dim_vector (ndims, 1));
+
+          idx(0) = octave::idx_vector (':');
+          idx(1) = octave::idx_vector (':');
 
           for (int k = 2; k < ndims; k++)
-            idx(k) = idx_vector (ra_idx(k));
+            idx(k) = octave::idx_vector (ra_idx(k));
 
           octave_value page
             = MAT_T (Array<ELT_T> (nda.index (idx), dim_vector (nr, nc)));
@@ -2488,12 +2488,13 @@
 }
 
 void
-octave_print_internal (std::ostream& os, const Range& r,
+octave_print_internal (std::ostream& os, const octave::range<double>& r,
                        bool pr_as_read_syntax, int extra_indent)
 {
   double base = r.base ();
-  double increment = r.inc ();
+  double increment = r.increment ();
   double limit = r.limit ();
+  double final_value = r.final_value ();
   octave_idx_type num_elem = r.numel ();
 
   if (plus_format && ! pr_as_read_syntax)
@@ -2575,12 +2576,7 @@
                     val = base + i * increment;
 
                   if (i == num_elem - 1)
-                    {
-                      // See the comments in Range::matrix_value.
-                      if ((increment > 0 && val >= limit)
-                          || (increment < 0 && val <= limit))
-                        val = limit;
-                    }
+                    val = final_value;
 
                   os << "  ";
 
@@ -2750,13 +2746,13 @@
               nm += buf.str ();
             }
 
-          Array<idx_vector> idx (dim_vector (ndims, 1));
-
-          idx(0) = idx_vector (':');
-          idx(1) = idx_vector (':');
+          Array<octave::idx_vector> idx (dim_vector (ndims, 1));
+
+          idx(0) = octave::idx_vector (':');
+          idx(1) = octave::idx_vector (':');
 
           for (int k = 2; k < ndims; k++)
-            idx(k) = idx_vector (ra_idx(k));
+            idx(k) = octave::idx_vector (ra_idx(k));
 
           Array<std::string> page (nda.index (idx), dim_vector (nr, nc));
 
@@ -2992,13 +2988,13 @@
                 os << "\n";
             }
 
-          Array<idx_vector> idx (dim_vector (ndims, 1));
-
-          idx(0) = idx_vector (':');
-          idx(1) = idx_vector (':');
+          Array<octave::idx_vector> idx (dim_vector (ndims, 1));
+
+          idx(0) = octave::idx_vector (':');
+          idx(1) = octave::idx_vector (':');
 
           for (int k = 2; k < ndims; k++)
-            idx(k) = idx_vector (ra_idx(k));
+            idx(k) = octave::idx_vector (ra_idx(k));
 
           Array<T> page (nda.index (idx), dim_vector (nr, nc));
 
@@ -3100,13 +3096,13 @@
                 os << "\n";
             }
 
-          Array<idx_vector> idx (dim_vector (ndims, 1));
-
-          idx(0) = idx_vector (':');
-          idx(1) = idx_vector (':');
+          Array<octave::idx_vector> idx (dim_vector (ndims, 1));
+
+          idx(0) = octave::idx_vector (':');
+          idx(1) = octave::idx_vector (':');
 
           for (int k = 2; k < ndims; k++)
-            idx(k) = idx_vector (ra_idx(k));
+            idx(k) = octave::idx_vector (ra_idx(k));
 
           Array<T> page (nda.index (idx), dim_vector (nr, nc));
 
@@ -3309,7 +3305,7 @@
 
 %!assert <*57004> (rats ([]), '')
 
-%!xtest <57704>
+%!test <57704>
 %! [old_fmt, old_spacing] = format ();
 %! unwind_protect
 %!   format short;
@@ -3608,7 +3604,7 @@
   frame.protect_var (Vcompact_format);
   frame.protect_var (uppercase_format);
   int prec = output_precision ();
-  frame.add ([prec] (void) { set_output_prec (prec); });
+  frame.add ([=] (void) { set_output_prec (prec); });
 
   format = format_string;   // Initialize with existing value
   while (argc-- > 0)
--- a/libinterp/corefcn/pr-output.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/pr-output.h	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,6 @@
 class FloatDiagMatrix;
 class NDArray;
 class FloatNDArray;
-class Range;
 class boolMatrix;
 class boolNDArray;
 class charMatrix;
@@ -57,6 +56,11 @@
 class Cell;
 class octave_value;
 
+namespace octave
+{
+  template <typename T> class range;
+}
+
 template <typename T> class intNDArray;
 
 template <typename T>
@@ -91,7 +95,7 @@
 
 template <>
 float_display_format
-make_format (const Range& r);
+make_format (const octave::range<double>& r);
 
 template <>
 float_display_format
@@ -309,7 +313,7 @@
                        int extra_indent = 0);
 
 extern OCTINTERP_API void
-octave_print_internal (std::ostream& os, const Range& r,
+octave_print_internal (std::ostream& os, const octave::range<double>& r,
                        bool pr_as_read_syntax = false,
                        int extra_indent = 0);
 
--- a/libinterp/corefcn/psi.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/psi.cc	Sun May 16 09:44:35 2021 +0200
@@ -175,7 +175,7 @@
 ## "Introduction to the Gamma Function"
 
 ## Interesting identities of the digamma function, in section of 5.1.3
-%!assert (psi (1/3), - em - (3/2) * log(3) - ((sqrt (3) / 6) * pi), eps*10)
+%!assert (psi (1/3), - em - (3/2) * log (3) - ((sqrt (3) / 6) * pi), eps*10)
 %!assert (psi (1/4), - em -3 * log (2) - pi/2, eps*10)
 %!assert (psi (1/6), - em -2 * log (2) - (3/2) * log (3) - ((sqrt (3) / 2) * pi), eps*10)
 
--- a/libinterp/corefcn/qr.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/qr.cc	Sun May 16 09:44:35 2021 +0200
@@ -79,6 +79,8 @@
     return octave::math::qr<T>::std;
 }
 
+// dense X
+//
 // [Q, R] = qr (X):       form Q unitary and R upper triangular such
 //                        that Q * R = X
 //
@@ -95,13 +97,21 @@
 //
 // qr (X) alone returns the output of the LAPACK routine dgeqrf, such
 // that R = triu (qr (X))
-
+//
+// sparse X
+//
+// X = qr (A, B):         if M < N, X is the minimum 2-norm solution of
+//                        A\B. If M >= N, X is the least squares
+//                        approximation of A\B. X is calculated by
+//                        SPQR-function SuiteSparseQR_min2norm.
+//
 DEFUN (qr, args, nargout,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {[@var{Q}, @var{R}] =} qr (@var{A})
-@deftypefnx {} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A})  # non-sparse A
+@deftypefnx {} {[@var{Q}, @var{R}, @var{P}] =} qr (@var{A})
 @deftypefnx {} {@var{X} =} qr (@var{A})  # non-sparse A
 @deftypefnx {} {@var{R} =} qr (@var{A})  # sparse A
+@deftypefnx {} {@var{X} =} qr (@var{A}, @var{B}) # sparse A
 @deftypefnx {} {[@var{C}, @var{R}] =} qr (@var{A}, @var{B})
 @deftypefnx {} {[@dots{}] =} qr (@dots{}, 0)
 @deftypefnx {} {[@dots{}] =} qr (@dots{}, "vector")
@@ -164,8 +174,8 @@
 @var{A} is full.  (Note: unlike most commands, the single return value is not
 the first return value when multiple values are requested.)
 
-If the matrix @var{A} is full, and a third output @var{P} is requested, then
-@code{qr} calculates the permuted QR@tie{}factorization
+If a third output @var{P} is requested, then @code{qr} calculates the permuted
+QR@tie{}factorization
 @tex
 $QR = AP$ where $Q$ is an orthogonal matrix, $R$ is upper triangular, and $P$
 is a permutation matrix.
@@ -181,9 +191,14 @@
 @var{P} is a permutation matrix.
 @end ifnottex
 
-The permuted QR@tie{}factorization has the additional property that the
-diagonal entries of @var{R} are ordered by decreasing magnitude.  In other
-words, @code{abs (diag (@var{R}))} will be ordered from largest to smallest.
+If @var{A} is dense, the permuted QR@tie{}factorization has the additional
+property that the diagonal entries of @var{R} are ordered by decreasing
+magnitude.  In other words, @code{abs (diag (@var{R}))} will be ordered
+from largest to smallest.
+
+If @var{A} is sparse, @var{P} is a fill-reducing ordering of the columns
+of @var{A}.  In that case, the diagonal entries of @var{R} are not ordered by
+decreasing magnitude.
 
 For example, given the matrix @code{@var{A} = [1, 2; 3, 4]},
 
@@ -213,27 +228,38 @@
 @end group
 @end example
 
-If the input matrix @var{A} is sparse then the sparse QR@tie{}factorization
-is computed using @sc{CSparse}.  Because the matrix @var{Q} is, in general, a
-full matrix, it is recommended to request only one return value @var{R}.  In
-that case, the computation avoids the construction of @var{Q} and returns
-@var{R} such that @code{@var{R} = chol (@var{A}' * @var{A})}.
+If the input matrix @var{A} is sparse, the sparse QR@tie{}factorization
+is computed by using @sc{SPQR} or @sc{CXSparse} (e.g., if @sc{SPQR} is not
+available).  Because the matrix @var{Q} is, in general, a full matrix, it is
+recommended to request only one return value @var{R}.  In that case, the
+computation avoids the construction of @var{Q} and returns a sparse @var{R} such
+that @code{@var{R} = chol (@var{A}' * @var{A})}.
 
-If an additional matrix @var{B} is supplied and two return values are
-requested, then @code{qr} returns @var{C}, where
+If @var{A} is dense, an additional matrix @var{B} is supplied and two
+return values are requested, then @code{qr} returns @var{C}, where
 @code{@var{C} = @var{Q}' * @var{B}}.  This allows the least squares
 approximation of @code{@var{A} \ @var{B}} to be calculated as
 
 @example
 @group
 [@var{C}, @var{R}] = qr (@var{A}, @var{B})
-@var{x} = @var{R} \ @var{C}
+@var{X} = @var{R} \ @var{C}
 @end group
 @end example
 
+If @var{A} is a sparse MxN matrix and an additional matrix @var{B} is
+supplied, one or two return values are possible.  If one return value @var{X}
+is requested and M < N, then @var{X} is the minimum 2-norm solution of
+@w{@code{@var{A} \ @var{B}}}.  If M >= N, @var{X} is the least squares
+approximation @w{of @code{@var{A} \ @var{B}}}.  If two return values are
+requested, @var{C} and @var{R} have the same meaning as in the dense case
+(@var{C} is dense and @var{R} is sparse).
+The version with one return parameter should be preferred because
+it uses less memory and can handle rank-deficient matrices better.
+
 If the final argument is the string @qcode{"vector"} then @var{P} is a
-permutation vector (of the columns of @var{A}) instead of a permutation matrix.
-In this case, the defining relationship is
+permutation vector (of the columns of @var{A}) instead of a permutation
+matrix. In this case, the defining relationship is:
 
 @example
 @var{Q} * @var{R} = @var{A}(:, @var{P})
@@ -243,12 +269,13 @@
 explicitly specified by using a final argument of @qcode{"matrix"}.
 
 If the final argument is the scalar 0 an @qcode{"economy"} factorization is
-returned.  When the original matrix @var{A} has size MxN and M > N then the
+returned.  If the original matrix @var{A} has size MxN and M > N, then the
 @qcode{"economy"} factorization will calculate just N rows in @var{R} and N
-columns in @var{Q} and omit the zeros in @var{R}.  If M @leq{} N there is no
+columns in @var{Q} and omit the zeros in @var{R}.  If M @leq{} N, there is no
 difference between the economy and standard factorizations.  When calculating
-an @qcode{"economy"} factorization the output @var{P} is always a vector
-rather than a matrix.
+an @qcode{"economy"} factorization and @var{A} is dense, the output @var{P} is
+always a vector rather than a matrix. If @var{A} is sparse, output
+@var{P} is a sparse permutation matrix.
 
 Background: The QR factorization has applications in the solution of least
 squares problems
@@ -331,45 +358,159 @@
 
   if (arg.issparse ())
     {
-      if (nargout > 2)
-        error ("qr: Permutation output is not supported for sparse input");
+      if (nargout > 3)
+        error ("qr: too many output arguments");
 
       if (is_cmplx)
         {
-          octave::math::sparse_qr<SparseComplexMatrix> q (arg.sparse_complex_matrix_value ());
+          if (have_b && nargout == 1)
+            {
+              octave_idx_type info;
 
-          if (have_b)
+              if (! args(1).issparse () && args(1).iscomplex ())
+                retval = ovl
+                  (octave::math::sparse_qr<SparseComplexMatrix>::solve
+                     <MArray<Complex>, ComplexMatrix>
+                     (arg.sparse_complex_matrix_value (),
+                      args(1).complex_matrix_value (), info));
+              else if (args(1).issparse () && args(1).iscomplex ())
+                retval = ovl
+                  (octave::math::sparse_qr<SparseComplexMatrix>::solve
+                     <SparseComplexMatrix, SparseComplexMatrix>
+                     (arg.sparse_complex_matrix_value (),
+                      args(1).sparse_complex_matrix_value (), info));
+              else if (! args(1).issparse () && ! args(1).iscomplex ())
+                retval = ovl
+                  (octave::math::sparse_qr<SparseComplexMatrix>::solve
+                     <MArray<double>, ComplexMatrix>
+                     (arg.sparse_complex_matrix_value (),
+                      args(1).matrix_value (), info));
+              else if (args(1).issparse () && ! args(1).iscomplex ())
+                retval = ovl
+                  (octave::math::sparse_qr<SparseComplexMatrix>::solve
+                     <SparseMatrix, SparseComplexMatrix>
+                     (arg.sparse_complex_matrix_value (),
+                      args(1).sparse_matrix_value (), info));
+              else
+                error ("qr: b is not valid");
+            }
+          else if (have_b && nargout == 2)
             {
-              retval = ovl (q.C (args(1).complex_matrix_value ()),
+              octave::math::sparse_qr<SparseComplexMatrix>
+              q (arg.sparse_complex_matrix_value (), 0);
+              retval = ovl (q.C (args(1).complex_matrix_value (), economy),
                             q.R (economy));
-              if (arg.rows () < arg.columns ())
-                warning ("qr: non minimum norm solution for under-determined "
-                         "problem %" OCTAVE_IDX_TYPE_FORMAT
-                         "x%" OCTAVE_IDX_TYPE_FORMAT,
-                         arg.rows (), arg.columns ());
+            }
+          else if (have_b && nargout == 3)
+            {
+              octave::math::sparse_qr<SparseComplexMatrix>
+              q (arg.sparse_complex_matrix_value ());
+              if (vector_p)
+                retval = ovl (q.C (args(1).complex_matrix_value (), economy),
+                              q.R (economy), q.E ());
+              else
+                retval = ovl (q.C (args(1).complex_matrix_value (), economy),
+                              q.R (economy), q.E_MAT ());
             }
-          else if (nargout > 1)
-            retval = ovl (q.Q (), q.R (economy));
           else
-            retval = ovl (q.R (economy));
+            {
+              if (nargout > 2)
+                {
+                  octave::math::sparse_qr<SparseComplexMatrix>
+                  q (arg.sparse_complex_matrix_value ());
+                  if (vector_p)
+                    retval = ovl (q.Q (economy), q.R (economy), q.E ());
+                  else
+                    retval = ovl (q.Q (economy), q.R (economy),
+                                  q.E_MAT ());
+                }
+              else if (nargout > 1)
+                {
+                  octave::math::sparse_qr<SparseComplexMatrix>
+                  q (arg.sparse_complex_matrix_value (), 0);
+                  retval = ovl (q.Q (economy), q.R (economy));
+                }
+              else
+                {
+                  octave::math::sparse_qr<SparseComplexMatrix>
+                  q (arg.sparse_complex_matrix_value (), 0);
+                  retval = ovl (q.R (economy));
+                }
+            }
         }
       else
         {
-          octave::math::sparse_qr<SparseMatrix> q (arg.sparse_matrix_value ());
-
-          if (have_b)
+          if (have_b && nargout == 1)
+            {
+              octave_idx_type info;
+              if (args(1).issparse () && ! args(1).iscomplex ())
+                retval = ovl (octave::math::sparse_qr<SparseMatrix>::solve
+                                <SparseMatrix, SparseMatrix>
+                                (arg.sparse_matrix_value (),
+                                 args (1).sparse_matrix_value (), info));
+              else if (! args(1).issparse () && args(1).iscomplex ())
+                retval = ovl (octave::math::sparse_qr<SparseMatrix>::solve
+                                <MArray<Complex>, ComplexMatrix>
+                                (arg.sparse_matrix_value (),
+                                 args (1).complex_matrix_value (), info));
+              else if (! args(1).issparse () && ! args(1).iscomplex ())
+                retval = ovl (octave::math::sparse_qr<SparseMatrix>::solve
+                                <MArray<double>, Matrix>
+                                (arg.sparse_matrix_value (),
+                                 args (1).matrix_value (), info));
+              else if (args(1).issparse () &&  args(1).iscomplex ())
+                retval = ovl (octave::math::sparse_qr<SparseMatrix>::solve
+                                <SparseComplexMatrix, SparseComplexMatrix>
+                                (arg.sparse_matrix_value (),
+                                 args(1).sparse_complex_matrix_value (),
+                                 info));
+              else
+                error ("qr: b is not valid");
+            }
+          else if (have_b && nargout == 2)
+            {
+              octave::math::sparse_qr<SparseMatrix>
+              q (arg.sparse_matrix_value (), 0);
+              retval = ovl (q.C (args(1).matrix_value (), economy),
+                            q.R (economy));
+            }
+          else if (have_b && nargout == 3)
             {
-              retval = ovl (q.C (args(1).matrix_value ()), q.R (economy));
-              if (arg.rows () < arg.columns ())
-                warning ("qr: non minimum norm solution for under-determined "
-                         "problem %" OCTAVE_IDX_TYPE_FORMAT
-                         "x%" OCTAVE_IDX_TYPE_FORMAT,
-                         arg.rows (), arg.columns ());
+              octave::math::sparse_qr<SparseMatrix>
+              q (arg.sparse_matrix_value ());
+              if (vector_p)
+                retval = ovl (q.C (args(1).matrix_value (), economy),
+                              q.R (economy), q.E ());
+              else
+                retval = ovl (q.C (args(1).matrix_value (), economy),
+                              q.R (economy), q.E_MAT ());
             }
-          else if (nargout > 1)
-            retval = ovl (q.Q (), q.R (economy));
+
           else
-            retval = ovl (q.R (economy));
+            {
+              if (nargout > 2)
+                {
+                  octave::math::sparse_qr<SparseMatrix>
+                  q (arg.sparse_matrix_value ());
+                  if (vector_p)
+                    retval = ovl (q.Q (economy), q.R (economy), q.E ());
+                  else
+                    retval = ovl (q.Q (economy), q.R (economy),
+                                  q.E_MAT ());
+                }
+              else if (nargout > 1)
+                {
+                  octave::math::sparse_qr<SparseMatrix>
+                  q (arg.sparse_matrix_value (), 0);
+                  retval = ovl (q.Q (economy), q.R (economy));
+                }
+              else
+                {
+                  octave::math::sparse_qr<SparseMatrix>
+                  q (arg.sparse_matrix_value (), 0);
+                  retval = ovl (q.R (economy));
+                }
+            }
         }
     }
   else
@@ -446,8 +587,8 @@
                     octave::math::qr<FloatComplexMatrix> fact (m, type);
                     retval = ovl (fact.Q (), get_qr_r (fact));
                     if (have_b)
-                      retval (0) = conj (fact.Q ().transpose ())
-                                   * args(1).float_complex_matrix_value ();
+                      retval(0) = conj (fact.Q ().transpose ())
+                                  * args(1).float_complex_matrix_value ();
                   }
                   break;
 
@@ -531,8 +672,8 @@
                     octave::math::qr<ComplexMatrix> fact (m, type);
                     retval = ovl (fact.Q (), get_qr_r (fact));
                     if (have_b)
-                      retval (0) = conj (fact.Q ().transpose ())
-                                   * args(1).complex_matrix_value ();
+                      retval(0) = conj (fact.Q ().transpose ())
+                                  * args(1).complex_matrix_value ();
                   }
                   break;
 
@@ -860,7 +1001,7 @@
 ## The deactivated tests below can't be tested till rectangular back-subs is
 ## implemented for sparse matrices.
 
-%!testif HAVE_CXSPARSE
+%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -869,7 +1010,7 @@
 %! r = qr (a);
 %! assert (r'*r, a'*a, 1e-10);
 
-%!testif HAVE_COLAMD, HAVE_CXSPARSE
+%!testif HAVE_COLAMD; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -880,7 +1021,7 @@
 %! r = qr (a);
 %! assert (r'*r, a'*a, 1e-10);
 
-%!testif HAVE_CXSPARSE
+%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -889,7 +1030,7 @@
 %! [c,r] = qr (a, ones (n,1));
 %! assert (r\c, full (a)\ones (n,1), 10e-10);
 
-%!testif HAVE_CXSPARSE
+%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -900,7 +1041,7 @@
 %! assert (r\c, full (a)\b, 10e-10);
 
 ## Test under-determined systems!!
-%!#testif HAVE_CXSPARSE
+%!#testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -910,7 +1051,7 @@
 %! [c,r] = qr (a, b);
 %! assert (r\c, full (a)\b, 10e-10);
 
-%!testif HAVE_CXSPARSE
+%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -919,7 +1060,7 @@
 %! r = qr (a);
 %! assert (r'*r,a'*a,1e-10);
 
-%!testif HAVE_COLAMD, HAVE_CXSPARSE
+%!testif HAVE_COLAMD; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -930,7 +1071,7 @@
 %! r = qr (a);
 %! assert (r'*r, a'*a, 1e-10);
 
-%!testif HAVE_CXSPARSE
+%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -939,7 +1080,7 @@
 %! [c,r] = qr (a, ones (n,1));
 %! assert (r\c, full (a)\ones (n,1), 10e-10);
 
-%!testif HAVE_CXSPARSE
+%!testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
@@ -950,16 +1091,156 @@
 %! assert (r\c, full (a)\b, 10e-10);
 
 ## Test under-determined systems!!
-%!#testif HAVE_CXSPARSE
+%!#testif ; (__have_feature__ ("SPQR") && __have_feature__ ("CHOLMOD")) || __have_feature__ ("CXSPARSE")
 %! n = 20;  d = 0.2;
 %! ## initialize generators to make behavior reproducible
 %! rand ("state", 42);
 %! randn ("state", 42);
 %! a = 1i*sprandn (n,n+1,d) + speye (n,n+1);
-%! b = randn (n,2);
-%! [c,r] = qr (a, b);
+%! b = randn (n, 2);
+%! [c, r] = qr (a, b);
+%! assert (r\c, full (a)\b, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = sprandn (m, n, d);
+%! b = randn (m, 2);
+%! [c, r] = qr (a, b);
 %! assert (r\c, full (a)\b, 10e-10);
 
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = sprandn (m, n, d);
+%! b = sprandn (m, 2, d);
+%! [c, r] = qr (a, b, 0);
+%! [c2, r2] = qr (full (a), full (b), 0);
+%! assert (r\c, r2\c2, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = sprandn (m, n, d);
+%! b = randn (m, 2);
+%! [c, r, p] = qr (a, b, "matrix");
+%! x = p * (r\c);
+%! [c2, r2] = qr (full (a), b);
+%! x2 = r2 \ c2;
+%! assert (x, x2, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = sprandn (m, n, d);
+%! [q, r, p] = qr (a, "matrix");
+%! assert (q * r, a * p, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = sprandn (m, n, d);
+%! b = randn (m, 2);
+%! x = qr (a, b);
+%! [c2, r2] = qr (full (a), b);
+%! assert (x, r2\c2, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = sprandn (m, n, d);
+%! b = i * randn (m, 2);
+%! x = qr (a, b);
+%! [c2, r2] = qr (full (a), b);
+%! assert (x, r2\c2, 10e-10);
+
+%!#testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = sprandn (m, n, d);
+%! b = i * randn (m, 2);
+%! [c, r] = qr (a, b);
+%! [c2, r2] = qr (full (a), b);
+%! assert (r\c, r2\c2, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = sprandn (m, n, d);
+%! b = i * randn (m, 2);
+%! [c, r, p] = qr (a, b, "matrix");
+%! x = p * (r\c);
+%! [c2, r2] = qr (full (a), b);
+%! x2 = r2 \ c2;
+%! assert (x, x2, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = i * sprandn (m, n, d);
+%! b = sprandn (m, 2, d);
+%! [c, r] = qr (a, b, 0);
+%! [c2, r2] = qr (full (a), full (b), 0);
+%! assert (r\c, r2\c2, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = i * sprandn (m, n, d);
+%! b = randn (m, 2);
+%! [c, r, p] = qr (a, b, "matrix");
+%! x = p * (r\c);
+%! [c2, r2] = qr (full (a), b);
+%! x2 = r2 \ c2;
+%! assert(x, x2, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = i * sprandn (m, n, d);
+%! [q, r, p] = qr (a, "matrix");
+%! assert(q * r, a * p, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! n = 12; m = 20; d = 0.2;
+%! ## initialize generators to make behavior reproducible
+%! rand ("state", 42);
+%! randn ("state", 42);
+%! a = i * sprandn (m, n, d);
+%! b = randn (m, 2);
+%! x = qr (a, b);
+%! [c2, r2] = qr (full (a), b);
+%! assert (x, r2\c2, 10e-10);
+
+%!testif HAVE_SPQR, HAVE_CHOLMOD
+%! a = sparse (5, 6);
+%! a(3,1) = 0.8;
+%! a(2,2) = 1.4;
+%! a(1,6) = -0.5;
+%! r = qr (a);
+%! assert (r'*r, a'*a, 10e-10);
 */
 
 static
--- a/libinterp/corefcn/quad.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/quad.cc	Sun May 16 09:44:35 2021 +0200
@@ -71,9 +71,9 @@
         {
           tmp = octave::feval (quad_fcn, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "quad");
+          err_user_supplied_eval (ee, "quad");
         }
 
       if (! tmp.length () || ! tmp(0).is_defined ())
@@ -107,9 +107,9 @@
         {
           tmp = octave::feval (quad_fcn, args, 1);
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          err_user_supplied_eval (e, "quad");
+          err_user_supplied_eval (ee, "quad");
         }
 
       if (! tmp.length () || ! tmp(0).is_defined ())
@@ -180,9 +180,7 @@
 
   warned_imaginary = false;
 
-  octave::unwind_protect frame;
-
-  frame.protect_var (call_depth);
+  octave::unwind_protect_var<int> restore_var (call_depth);
   call_depth++;
 
   if (call_depth > 1)
--- a/libinterp/corefcn/quadcc.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/quadcc.cc	Sun May 16 09:44:35 2021 +0200
@@ -2242,9 +2242,9 @@
 %! assert (class (quadcc (@sin, single (0), single (1))), "single");
 
 ## Test input validation
-%!error (quadcc ())
-%!error (quadcc (@sin))
-%!error (quadcc (@sin, 0))
+%!error quadcc ()
+%!error quadcc (@sin)
+%!error quadcc (@sin, 0)
 %!error <lower limit .* must be a .* scalar> (quadcc (@sin, ones (2), pi))
 %!error <lower limit .* must be a real scalar> (quadcc (@sin, -i, pi))
 %!error <upper limit .* must be a .* scalar> (quadcc (@sin, 0, ones (2)))
--- a/libinterp/corefcn/qz.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/qz.cc	Sun May 16 09:44:35 2021 +0200
@@ -162,9 +162,9 @@
 @end enumerate
 
 Note: @code{qz} performs permutation balancing, but not scaling
-(@pxref{XREFbalance,,balance}), which may be lead to less accurate results than
-@code{eig}.  The order of output arguments was selected for compatibility with
-@sc{matlab}.
+(@pxref{XREFbalance,,@code{balance}}), which may be lead to less accurate
+results than @code{eig}.  The order of output arguments was selected for
+compatibility with @sc{matlab}.
 @seealso{eig, gsvd, balance, chol, hess, lu, qr, qzhess, schur}
 @end deftypefn */)
 {
--- a/libinterp/corefcn/rand.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/rand.cc	Sun May 16 09:44:35 2021 +0200
@@ -117,10 +117,12 @@
   octave_value retval;
   dim_vector dims;
 
-  octave::unwind_protect frame;
   // Restore current distribution on any exit.
-  frame.add_fcn (octave::rand::distribution,
-                 octave::rand::distribution ());
+  octave::unwind_action restore_distribution
+    ([] (const std::string& old_distribution)
+     {
+       octave::rand::distribution (old_distribution);
+     }, octave::rand::distribution ());
 
   octave::rand::distribution (distribution);
 
@@ -181,7 +183,7 @@
           }
         else if (tmp.is_range ())
           {
-            Range r = tmp.range_value ();
+            octave::range<double> r = tmp.range_value ();
 
             if (! r.all_elements_are_ints ())
               error ("%s: all elements of range must be integers", fcn);
@@ -191,7 +193,7 @@
             dims.resize (n);
 
             octave_idx_type base = octave::math::nint_big (r.base ());
-            octave_idx_type incr = octave::math::nint_big (r.inc ());
+            octave_idx_type incr = octave::math::nint_big (r.increment ());
 
             for (octave_idx_type i = 0; i < n; i++)
               {
@@ -210,9 +212,9 @@
               {
                 iv = tmp.octave_idx_type_vector_value (true);
               }
-            catch (octave::execution_exception& e)
+            catch (octave::execution_exception& ee)
               {
-                error (e, "%s: dimensions must be a scalar or array of integers", fcn);
+                error (ee, "%s: dimensions must be a scalar or array of integers", fcn);
               }
 
             octave_idx_type len = iv.numel ();
@@ -388,12 +390,14 @@
 @leq{} 625 for @var{v}.  This new state will be a hash based on the value of
 @var{v}, not @var{v} itself.
 
-By default, the generator is initialized from @code{/dev/urandom} if it is
-available, otherwise from CPU time, wall clock time, and the current
-fraction of a second.  Note that this differs from @sc{matlab}, which
-always initializes the state to the same state at startup.  To obtain
-behavior comparable to @sc{matlab}, initialize with a deterministic state
-vector in Octave's startup files (@pxref{Startup Files}).
+By default, the generator is initialized by contributing entropy from the
+wall clock time, the CPU time, the current fraction of a second, the process
+ID and---if available---up to 1024 bits from the C++ random numbers source
+@code{random_device}, which might be non-deterministic (implementation
+specific).  Note that this differs from @sc{matlab}, which always initializes
+the state to the same state at startup.  To obtain behavior comparable to
+@sc{matlab}, initialize with a deterministic state vector in Octave's startup
+files (@pxref{Startup Files}).
 
 To compute the pseudo-random sequence, @code{rand} uses the Mersenne
 Twister with a period of @math{2^{19937}-1}
@@ -1198,8 +1202,8 @@
   if (m < n)
     idx.resize (dim_vector (1, m));
 
-  // Now create an array object with a cached idx_vector.
-  return ovl (new octave_matrix (r, idx_vector (idx)));
+  // Now create an array object with a cached octave::idx_vector.
+  return ovl (new octave_matrix (r, octave::idx_vector (idx)));
 }
 
 /*
--- a/libinterp/corefcn/regexp.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/regexp.cc	Sun May 16 09:44:35 2021 +0200
@@ -60,7 +60,7 @@
   std::size_t j = 0;
   std::size_t len = s.length ();
 
-  retval.resize (len+i);
+  retval.resize (len);
 
   while (j < len)
     {
@@ -79,11 +79,15 @@
                 }
               break;
 
-            // Translate \< and \> to PCRE word boundary
+            // Translate \< and \> to PCRE patterns for pseudo-word boundary
             case '<': // begin word boundary
+              retval.insert (i, "(?<=\\W|^)");
+              i += 8;
+              break;
+
             case '>': // end word boundary
-              retval[i] = '\\';
-              retval[++i] = 'b';
+              retval.insert (i, "(?=\\W|$)");
+              i += 7;
               break;
 
             case 'o': // octal input
@@ -752,10 +756,10 @@
 @end table
 
 Implementation Note: For compatibility with @sc{matlab}, escape sequences
-in @var{pat} (e.g., @qcode{"@xbackslashchar{}n"} => newline) are expanded
+in @var{pat} (e.g., @qcode{"@backslashchar{}n"} => newline) are expanded
 even when @var{pat} has been defined with single quotes.  To disable
 expansion use a second backslash before the escape sequence (e.g.,
-"@xbackslashchar{}@xbackslashchar{}n") or use the @code{regexptranslate}
+"@backslashchar{}@backslashchar{}n") or use the @code{regexptranslate}
 function.
 
 The outputs of @code{regexp} default to the order given below
@@ -1178,12 +1182,19 @@
 %!assert (regexp ("\n", '\n'), 1)
 %!assert (regexp ("\n", "\n"), 1)
 
-# Test escape sequences are silently converted
+## Test escape sequences are silently converted
 %!test <*45407>
 %! assert (regexprep ('s', 's', 'x\.y'), 'x.y');
 %! assert (regexprep ('s', '(s)', 'x\$1y'), 'x$1y');
 %! assert (regexprep ('s', '(s)', 'x\\$1y'), 'x\sy');
 
+## Test start-of-word / end-of-word patterns for Matlab compatibility
+%!test <*59992>
+%! assert (regexp ('foo!+bar', '\<\w'), [1, 6]);
+%! assert (regexp ('foo!+bar', '.\>'), [3, 4, 8]);
+%! assert (regexp ('foo!+bar\nbar!+foo', '.\>'), [3, 4, 8, 13, 14, 18]);
+%! assert (regexp ('foo!+bar\nbar!+foo', '\<\w'), [1, 6, 10, 16]);
+
 ## Test input validation
 %!error regexp ('string', 'tri', 'BadArg')
 %!error regexp ('string')
@@ -1199,7 +1210,8 @@
 
 Search for @var{pat} in UTF-8 encoded @var{str} and return the positions and
 substrings of any matches, or empty values if there are none.
-@xref{XREFregexp,,regexp}, for details on the syntax of the search pattern.
+@xref{XREFregexp,,@code{regexp}}, for details on the syntax of the search
+pattern.
 @seealso{regexp}
 @end deftypefn */)
 {
@@ -1396,7 +1408,7 @@
 Replace occurrences of pattern @var{pat} in @var{string} with @var{repstr}.
 
 The pattern is a regular expression as documented for @code{regexp}.
-@xref{XREFregexp,,regexp}.
+@xref{XREFregexp,,@code{regexp}}.
 
 All strings must be UTF-8 encoded.
 
@@ -1423,10 +1435,10 @@
 @end table
 
 Implementation Note: For compatibility with @sc{matlab}, escape sequences
-in @var{pat} (e.g., @qcode{"@xbackslashchar{}n"} => newline) are expanded
+in @var{pat} (e.g., @qcode{"@backslashchar{}n"} => newline) are expanded
 even when @var{pat} has been defined with single quotes.  To disable
 expansion use a second backslash before the escape sequence (e.g.,
-"@xbackslashchar{}@xbackslashchar{}n") or use the @code{regexptranslate}
+"@backslashchar{}@backslashchar{}n") or use the @code{regexptranslate}
 function.
 @seealso{regexp, regexpi, strrep}
 @end deftypefn */)
--- a/libinterp/corefcn/sighandlers.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/sighandlers.cc	Sun May 16 09:44:35 2021 +0200
@@ -540,7 +540,7 @@
 %! debug_on_interrupt (orig_val);
 %! assert (debug_on_interrupt (), orig_val);
 
-%!error (debug_on_interrupt (1, 2))
+%!error debug_on_interrupt (1, 2)
 */
 
 DEFUN (sighup_dumps_octave_core, args, nargout,
@@ -571,7 +571,7 @@
 %! sighup_dumps_octave_core (orig_val);
 %! assert (sighup_dumps_octave_core (), orig_val);
 
-%!error (sighup_dumps_octave_core (1, 2))
+%!error sighup_dumps_octave_core (1, 2)
 */
 
 DEFUN (sigquit_dumps_octave_core, args, nargout,
@@ -602,7 +602,7 @@
 %! sigquit_dumps_octave_core (orig_val);
 %! assert (sigquit_dumps_octave_core (), orig_val);
 
-%!error (sigquit_dumps_octave_core (1, 2))
+%!error sigquit_dumps_octave_core (1, 2)
 */
 
 DEFUN (sigterm_dumps_octave_core, args, nargout,
@@ -633,5 +633,5 @@
 %! sigterm_dumps_octave_core (orig_val);
 %! assert (sigterm_dumps_octave_core (), orig_val);
 
-%!error (sigterm_dumps_octave_core (1, 2))
+%!error sigterm_dumps_octave_core (1, 2)
 */
--- a/libinterp/corefcn/sparse.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/sparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -101,8 +101,9 @@
 
 @strong{Note}: if multiple values are specified with the same @var{i},
 @var{j} indices, the corresponding value in @var{s} will be the sum of the
-values at the repeated location.  See @code{accumarray} for an example of
-how to produce different behavior, such as taking the minimum instead.
+values at the repeated location.  @xref{XREFaccumarray,,@code{accumarray}}, for
+an example of how to produce different behavior such as taking the minimum
+instead.
 
 If the option @qcode{"unique"} is given, and more than one value is
 specified at the same @var{i}, @var{j} indices, then the last specified
@@ -152,9 +153,7 @@
   octave_value retval;
 
   // Temporarily disable sparse_auto_mutate if set (it's obsolete anyway).
-  octave::unwind_protect frame;
-  frame.protect_var (Vsparse_auto_mutate);
-  Vsparse_auto_mutate = false;
+  octave::unwind_protect_var<bool> restore_var (Vsparse_auto_mutate, false);
 
   if (nargin == 1)
     {
@@ -215,9 +214,9 @@
       int k = 0;    // index we're checking when index_vector throws
       try
         {
-          idx_vector i = args(0).index_vector ();
+          octave::idx_vector i = args(0).index_vector ();
           k = 1;
-          idx_vector j = args(1).index_vector ();
+          octave::idx_vector j = args(1).index_vector ();
 
           if (args(2).islogical ())
             retval = SparseBoolMatrix (args(2).bool_array_value (), i,j,
@@ -231,10 +230,10 @@
           else
             err_wrong_type_arg ("sparse", args(2));
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
           // Rethrow to allow more info to be reported later.
-          e.set_pos_if_unset (2, k+1);
+          ie.set_pos_if_unset (2, k+1);
           throw;
         }
     }
@@ -244,7 +243,7 @@
 
 /*
 ## Tests for sparse constructor are in test/sparse.tst
-%!assert (1);
+%!assert (1)
 */
 
 DEFUN (spalloc, args, ,
--- a/libinterp/corefcn/stack-frame.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/stack-frame.cc	Sun May 16 09:44:35 2021 +0200
@@ -1169,7 +1169,7 @@
 
     while (frame)
       {
-        octave::symbol_info_list symbols = frame->all_variables ();
+        symbol_info_list symbols = frame->all_variables ();
 
         octave_scalar_map ws;
 
--- a/libinterp/corefcn/stack-frame.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/stack-frame.h	Sun May 16 09:44:35 2021 +0200
@@ -476,15 +476,15 @@
         varref (sym).assign (op, type, idx, rhs);
     }
 
-    void do_non_const_unary_op (octave_value::unary_op op,
+    void non_const_unary_op (octave_value::unary_op op,
                                 const symbol_record& sym,
                                 const std::string& type,
                                 const std::list<octave_value_list>& idx)
     {
       if (idx.empty ())
-        varref (sym).do_non_const_unary_op (op);
+        varref (sym).non_const_unary_op (op);
       else
-        varref (sym).do_non_const_unary_op (op, type, idx);
+        varref (sym).non_const_unary_op (op, type, idx);
     }
 
     octave_value value (const symbol_record& sym, const std::string& type,
--- a/libinterp/corefcn/strfind.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/strfind.cc	Sun May 16 09:44:35 2021 +0200
@@ -418,17 +418,18 @@
   if (nargin == 5)
     {
       if (! args(3).is_string () || ! args(4).is_scalar_type ())
-        error ("strrep: invalid optional arguments");
+        error ("strrep: invalid optional argument");
 
       std::string opt = args(3).string_value ();
-      if (opt == "overlaps")
-        overlaps = args(4).bool_value ();
-      else
+      if (opt != "overlaps")
         error ("strrep: unknown option: %s", opt.c_str ());
+
+      overlaps = args(4).bool_value ();
     }
 
   octave_value retval;
 
+  // Aliasing for better code readability
   octave_value argstr = args(0);
   octave_value argpat = args(1);
   octave_value argrep = args(2);
@@ -442,25 +443,42 @@
       qs_preprocess (pat, table);
 
       if (argstr.is_string ())
-        retval = qs_replace (argstr.char_array_value (), pat, rep,
-                             table, overlaps);
+        if (argstr.rows () == 1)  // most common case of a single string
+          retval = qs_replace (argstr.char_array_value (), pat, rep,
+                               table, overlaps);
+        else
+          {
+            const charMatrix argchm = argstr.char_matrix_value ();
+            octave_idx_type nel = argchm.rows ();
+            octave_idx_type nc = argchm.columns ();
+            charMatrix retchm (nel, 0);
+
+            for (octave_idx_type i = 0; i < nel; i++)
+              {
+                charMatrix rowchm;
+                rowchm = qs_replace (argchm.extract (i, 0, i, nc-1),
+                                     pat, rep, table, overlaps);
+                retchm.insert (rowchm, i, 0);
+              }
+
+            retval = retchm;
+          }
       else if (argstr.iscell ())
         {
-          const Cell argsc = argstr.cell_value ();
-          Cell retc (argsc.dims ());
-          octave_idx_type ns = argsc.numel ();
+          const Cell argcell = argstr.cell_value ();
+          if (! argcell.iscellstr ())
+            error ("strrep: each element of S must be a string");
 
-          for (octave_idx_type i = 0; i < ns; i++)
+          Cell retcell (argcell.dims ());
+          octave_idx_type nel = argcell.numel ();
+
+          for (octave_idx_type i = 0; i < nel; i++)
             {
-              octave_value argse = argsc(i);
-              if (argse.is_string ())
-                retc(i) = qs_replace (argse.char_array_value (), pat, rep,
-                                      table, overlaps);
-              else
-                error ("strrep: each element of S must be a string");
+              retcell(i) = qs_replace (argcell(i).char_array_value (),
+                                       pat, rep, table, overlaps);
             }
 
-          retval = retc;
+          retval = retcell;
         }
       else
         error ("strrep: S must be a string or cell array of strings");
@@ -478,9 +496,23 @@
 %!                "Th&%$ &%$ a test string")
 %!assert (strrep ("abababc", "abab", "xyz"), "xyzxyzc")
 %!assert (strrep ("abababc", "abab", "xyz", "overlaps", false), "xyzabc")
+%!assert (strrep ({"Hello World"; "Goodbye World"}, "World", "Jane"),
+%!                {"Hello Jane"; "Goodbye Jane"})
+%!assert (strrep (char ("Hello World", "Goodbye World"), "World", "Jane"),
+%!                char ("Hello Jane", "Goodbye Jane"))
 
 %!assert (size (strrep ("a", "a", "")), [0 0])
 
 %!error strrep ()
-%!error strrep ("foo", "bar", 3, 4)
+%!error strrep ("A")
+%!error strrep ("A", "B")
+%!error strrep ("A", "B", "C", "D")
+%!error strrep ("A", "B", "C", "D", "E", "F")
+%!error <invalid optional argument> strrep ("A", "B", "C", 3, true)
+%!error <invalid optional argument> strrep ("A", "B", "C", "str", ones (2,2))
+%!error <unknown option: foobar> strrep ("A", "B", "C", "foobar", true)
+%!error <each element of S must be a string> strrep ({"A", 1.0}, "B", "C")
+%!error <S must be a string or cell array of strings> strrep (1.0, "B", "C")
+%!error <PTN and REP arguments must be strings> strrep ("A", 1.0, "C")
+%!error <PTN and REP arguments must be strings> strrep ("A", "B", 1.0)
 */
--- a/libinterp/corefcn/strfns.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/strfns.cc	Sun May 16 09:44:35 2021 +0200
@@ -831,7 +831,7 @@
 %!assert (str2double ("-.1e-5"), -1e-6)
 %!testif ; ! ismac ()
 %! assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]);
-%!xtest <47413>
+%!test <47413>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! if (! ismac ()), return; endif
 %! assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]);
@@ -859,18 +859,18 @@
 %!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN))
 %!testif ; ! ismac ()
 %! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
-%!xtest <47413>
+%!test <47413>
 %! if (! ismac ()), return; endif
 %! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
 %!testif ; ! ismac ()
 %! assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
-%!xtest <47413>
+%!test <47413>
 %! if (! ismac ()), return; endif
 %! assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
 %!assert (str2double (zeros (3,1,2)), NaN)
 %!assert (str2double (''), NaN)
 %!assert (str2double ([]), NaN)
-%!assert (str2double (char(zeros(3,0))), NaN)
+%!assert (str2double (char (zeros (3,0))), NaN)
 */
 
 DEFUN (__native2unicode__, args, ,
@@ -881,11 +881,6 @@
 @seealso{native2unicode, __unicode2native__}
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 2)
-    print_usage ();
-
   if (args(0).is_string ())
     return ovl (args(0));
 
@@ -901,28 +896,26 @@
   std::size_t length;
   uint8_t *utf8_str = nullptr;
 
-  octave::unwind_protect frame;
-
   utf8_str = octave_u8_conv_from_encoding (codepage, src, srclen, &length);
 
   if (! utf8_str)
     {
       if (errno == ENOSYS)
-        error ("native2unicode: iconv() is not supported. Installing GNU "
+        error ("native2unicode: iconv() is not supported.  Installing GNU "
                "libiconv and then re-compiling Octave could fix this.");
       else
         error ("native2unicode: converting from codepage '%s' to UTF-8: %s",
                codepage, std::strerror (errno));
     }
 
-  frame.add_fcn (::free, static_cast<void *> (utf8_str));
+  octave::unwind_action free_utf8_str ([=] () { ::free (utf8_str); });
 
   octave_idx_type len = length;
 
   charNDArray retval (dim_vector (1, len));
 
   for (octave_idx_type i = 0; i < len; i++)
-    retval.xelem(i) = utf8_str[i];
+    retval.xelem (i) = utf8_str[i];
 
   return ovl (retval);
 }
@@ -936,11 +929,6 @@
 @seealso{unicode2native, __native2unicode__}
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 2)
-    print_usage ();
-
   std::string tmp = args(1).string_value ();
   const char *codepage
     = (tmp.empty () ? octave_locale_charset_wrapper () : tmp.c_str ());
@@ -953,28 +941,26 @@
   std::size_t length;
   char *native_bytes = nullptr;
 
-  octave::unwind_protect frame;
-
   native_bytes = octave_u8_conv_to_encoding (codepage, src, srclen, &length);
 
   if (! native_bytes)
     {
       if (errno == ENOSYS)
-        error ("unicode2native: iconv() is not supported. Installing GNU "
+        error ("unicode2native: iconv() is not supported.  Installing GNU "
                "libiconv and then re-compiling Octave could fix this.");
       else
         error ("unicode2native: converting from UTF-8 to codepage '%s': %s",
                codepage, std::strerror (errno));
     }
 
-  frame.add_fcn (::free, static_cast<void *> (native_bytes));
+  octave::unwind_action free_native_bytes ([=] () { ::free (native_bytes); });
 
   octave_idx_type len = length;
 
   uint8NDArray retval (dim_vector (1, len));
 
   for (octave_idx_type i = 0; i < len; i++)
-    retval.xelem(i) = native_bytes[i];
+    retval.xelem (i) = native_bytes[i];
 
   return ovl (retval);
 }
@@ -1005,9 +991,7 @@
 
 @end deftypefn */)
 {
-  int nargin = args.length ();
-
-  if (nargin != 1)
+  if (args.length () != 1)
     print_usage ();
 
   charNDArray str = args(0).xchar_array_value ("STR must be a string");
@@ -1042,7 +1026,7 @@
 }
 
 /*
-%!assert (unicode_idx (["aäou"; "Ä∞"]), [1 2 2 3 4; 5 5 6 6 6]);
+%!assert (unicode_idx (["aäou"; "Ä∞"]), [1 2 2 3 4; 5 5 6 6 6])
 */
 
 DEFUN (__u8_validate__, args, ,
@@ -1051,23 +1035,24 @@
 Return string with valid UTF-8.
 
 On encountering invalid UTF-8 in @var{in_str}, the bytes are either replaced by
-the replacement character "�" (if @var{mode} is omitted or the string
-"replace") or interpreted as the Unicode code points U+0080–U+00FF with the
-same value as the byte (if @var{mode} is the string "unicode"), thus
-interpreting the bytes according to ISO-8859-1.
-
+the replacement character @qcode{"�"} (if @var{mode} is omitted or is the
+string @qcode{"replace"}) or interpreted as the Unicode code points
+U+0080–U+00FF with the same value as the byte (if @var{mode} is the string
+@qcode{"unicode"}), thus interpreting the bytes according to ISO-8859-1.
 @end deftypefn */)
 {
-  if (args.length () < 1 || args.length () > 2)
+  int nargin = args.length ();
+
+  if (nargin < 1 || nargin > 2)
     print_usage ();
 
   // Input check
   std::string in_str =
-      args(0).xstring_value ("__u8_validate__: IN_STR must be a string.");
+    args(0).xstring_value ("__u8_validate__: IN_STR must be a string");
 
   std::string mode = "replace";
-  if (args.length () > 1)
-    mode = args(1).xstring_value ("__u8_validate__: MODE must be a string.");
+  if (nargin == 2)
+    mode = args(1).xstring_value ("__u8_validate__: MODE must be a string");
 
   octave::string::u8_fallback_type fb_type;
   if (mode == "replace")
@@ -1075,7 +1060,7 @@
   else if (mode == "unicode")
     fb_type = octave::string::U8_ISO_8859_1;
   else
-    error ("__u8_validate__: MODE must either be \"replace\" or \"unicode\".");
+    error (R"(__u8_validate__: MODE must be either "replace" or "unicode")");
 
   octave::string::u8_validate ("__u8_validate__", in_str, fb_type);
 
@@ -1087,7 +1072,7 @@
 @deftypefn {} {} newline
 Return the character corresponding to a newline.
 
-This is equivalent to @qcode{"@xbackslashchar{}n"}.
+This is equivalent to @qcode{"@backslashchar{}n"}.
 
 Example Code
 
@@ -1115,6 +1100,8 @@
 %!assert (newline (), "\n")
 
 %!error newline (1)
+## FIXME: The next error() test requires a semicolon at EOL until
+##        bug #59265 is resolved.
 %!error [a, b] = newline ();
 */
 
--- a/libinterp/corefcn/sub2ind.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/sub2ind.cc	Sun May 16 09:44:35 2021 +0200
@@ -68,8 +68,8 @@
 Convert subscripts to linear indices.
 
 The input @var{dims} is a dimension vector where each element is the size of
-the array in the respective dimension (@pxref{XREFsize,,size}).  The remaining
-inputs are scalars or vectors of subscripts to be converted.
+the array in the respective dimension (@pxref{XREFsize,,@code{size}}).  The
+remaining inputs are scalars or vectors of subscripts to be converted.
 
 The output vector @var{ind} contains the converted linear indices.
 
@@ -116,7 +116,7 @@
 
   dim_vector dv = get_dim_vector (args(0), "sub2ind");
 
-  Array<idx_vector> idxa (dim_vector (nargin-1, 1));
+  Array<octave::idx_vector> idxa (dim_vector (nargin-1, 1));
 
   for (int j = 0; j < nargin - 1; j++)
     {
@@ -130,12 +130,12 @@
           if (j > 0 && args(j+1).dims () != args(1).dims ())
             error ("sub2ind: all subscripts must be of the same size");
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
-          e.set_pos_if_unset (nargin-1, j+1);
-          e.set_var ();
-          std::string msg = e.message ();
-          error_with_id (e.err_id (), "%s", msg.c_str ());
+          ie.set_pos_if_unset (nargin-1, j+1);
+          ie.set_var ();
+          std::string msg = ie.message ();
+          error_with_id (ie.err_id (), "%s", msg.c_str ());
         }
     }
 
@@ -193,8 +193,8 @@
 Convert linear indices to subscripts.
 
 The input @var{dims} is a dimension vector where each element is the size of
-the array in the respective dimension (@pxref{XREFsize,,size}).  The second
-input @var{ind} contains linear indies to be converted.
+the array in the respective dimension (@pxref{XREFsize,,@code{size}}).  The
+second input @var{ind} contains linear indies to be converted.
 
 The outputs @var{s1}, @dots{}, @var{sN} contain the converted subscripts.
 
@@ -270,9 +270,9 @@
     {
       retval = Array<octave_value> (ind2sub (dv, args(1).index_vector ()));
     }
-  catch (const octave::index_exception& e)
+  catch (const octave::index_exception& ie)
     {
-      error ("ind2sub: invalid index %s", e.what ());
+      error ("ind2sub: invalid index %s", ie.what ());
     }
 
   return retval;
@@ -313,7 +313,7 @@
 %! r = ind2sub ([2, 2, 2], 1:8);
 %! assert (r, 1:8);
 
-%!error <DIMS must contain integers> ind2sub ([2, -2], 3);
-%!error <index out of range> ind2sub ([2, 2, 2], 1:9);
-%!error <invalid index> ind2sub ([2, 2, 2], -1:8);
+%!error <DIMS must contain integers> ind2sub ([2, -2], 3)
+%!error <index out of range> ind2sub ([2, 2, 2], 1:9)
+%!error <invalid index> ind2sub ([2, 2, 2], -1:8)
 */
--- a/libinterp/corefcn/svd.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/svd.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,9 +62,12 @@
 static typename octave::math::svd<T>::Driver
 svd_driver (void)
 {
-  return (Vsvd_driver == "gesvd"
-          ? octave::math::svd<T>::Driver::GESVD
-          : octave::math::svd<T>::Driver::GESDD);
+  if (Vsvd_driver == "gejsv")
+      return octave::math::svd<T>::Driver::GEJSV;
+  else if (Vsvd_driver == "gesdd")
+      return octave::math::svd<T>::Driver::GESDD;
+  else
+      return octave::math::svd<T>::Driver::GESVD;  // default
 }
 
 DEFUN (svd, args, nargout,
@@ -164,8 +167,9 @@
 singular matrices in addition to singular values) there is a choice of two
 routines in @sc{lapack}.  The default routine used by Octave is @code{gesvd}.
 The alternative is @code{gesdd} which is 5X faster, but may use more memory
-and may be inaccurate for some input matrices.  See the documentation for
-@code{svd_driver} for more information on choosing a driver.
+and may be inaccurate for some input matrices.  There is a third routine
+@code{gejsv}, suitable for better accuracy at extreme scale.  See the
+documentation for @code{svd_driver} for more information on choosing a driver.
 @seealso{svd_driver, svds, eig, lu, chol, hess, qr, qz}
 @end deftypefn */)
 {
@@ -377,6 +381,15 @@
 
 %!assert <*55710> (1 / svd (-0), Inf)
 
+%!test
+%! old_driver = svd_driver ("gejsv");
+%! s0 = [1e-20; 1e-10; 1];  # only gejsv can pass
+%! q = sqrt (0.5);
+%! a = s0 .* [q, 0, -q; -0.5, q, -0.5; 0.5, q, 0.5];
+%! s1 = svd (a);
+%! svd_driver (old_driver);
+%! assert (sort (s1), s0, -10 * eps);
+
 %!error svd ()
 %!error svd ([1, 2; 4, 5], 2, 3)
 */
@@ -388,17 +401,17 @@
 @deftypefnx {} {} svd_driver (@var{new_val}, "local")
 Query or set the underlying @sc{lapack} driver used by @code{svd}.
 
-Currently recognized values are @qcode{"gesdd"} and @qcode{"gesvd"}.
-The default is @qcode{"gesvd"}.
+Currently recognized values are @qcode{"gesdd"}, @qcode{"gesvd"}, and
+@qcode{"gejsv"}.  The default is @qcode{"gesvd"}.
 
 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.
 
-Algorithm Notes: The @sc{lapack} library provides two routines for calculating
-the full singular value decomposition (left and right singular matrices as
-well as singular values).  When calculating just the singular values the
-following discussion is not relevant.
+Algorithm Notes: The @sc{lapack} library routines @code{gesvd} and @code{gesdd}
+are different only when calculating the full singular value decomposition (left
+and right singular matrices as well as singular values).  When calculating just
+the singular values the following discussion is not relevant.
 
 The newer @code{gesdd} routine is based on a Divide-and-Conquer algorithm that
 is 5X faster than the alternative @code{gesvd}, which is based on QR
@@ -406,6 +419,12 @@
 For an @nospell{MxN} input matrix the memory usage is of order O(min(M,N) ^ 2),
 whereas the alternative is of order O(max(M,N)).
 
+The routine @code{gejsv} uses a preconditioned Jacobi SVD algorithm.  Unlike
+@code{gesvd} and @code{gesdd}, in @code{gejsv}, there is no bidiagonalization
+step that could contaminate accuracy in some extreme cases.  Also, @code{gejsv}
+is known to be optimally accurate in some sense.  However, the speed is slower
+(single threaded at its core) and uses more memory (O(min(M,N) ^ 2 + M + N)).
+
 Beyond speed and memory issues, there have been instances where some input
 matrices were not accurately decomposed by @code{gesdd}.  See currently active
 bug @url{https://savannah.gnu.org/bugs/?55564}.  Until these accuracy issues
@@ -415,7 +434,7 @@
 @seealso{svd}
 @end deftypefn */)
 {
-  static const char *driver_names[] = { "gesvd", "gesdd", nullptr };
+  static const char *driver_names[] = { "gesvd", "gesdd", "gejsv", nullptr };
 
   return SET_INTERNAL_VARIABLE_CHOICES (svd_driver, driver_names);
 }
@@ -427,8 +446,15 @@
 %! [U1, S1, V1] = svd (A);
 %! svd_driver ("gesdd");
 %! [U2, S2, V2] = svd (A);
+%! svd_driver ("gejsv");
+%! [U3, S3, V3] = svd (A);
+%! assert (svd_driver (), "gejsv");
 %! svd_driver (old_driver);
-%! assert (U1, U2, 5*eps);
-%! assert (S1, S2, 5*eps);
-%! assert (V1, V2, 5*eps);
+%! assert (U1, U2, 6*eps);
+%! assert (S1, S2, 6*eps);
+%! assert (V1, V2, 6*eps);
+%! z = U1(1,:) ./ U3(1,:);
+%! assert (U1, U3 .* z, 100*eps);
+%! assert (S1, S3, 6*eps);
+%! assert (V1, V3 .* z, 100*eps);
 */
--- a/libinterp/corefcn/syminfo.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/syminfo.h	Sun May 16 09:44:35 2021 +0200
@@ -50,7 +50,9 @@
     std::string line;
   };
 
-  class symbol_info
+  class
+  OCTINTERP_API
+  symbol_info
   {
   public:
 
@@ -85,7 +87,9 @@
     bool m_is_persistent;
   };
 
-  class symbol_info_list : public base_list<symbol_info>
+  class
+  OCTINTERP_API
+  symbol_info_list : public base_list<symbol_info>
   {
   public:
 
--- a/libinterp/corefcn/symscope.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/symscope.cc	Sun May 16 09:44:35 2021 +0200
@@ -116,7 +116,7 @@
             if (! fcn)
               continue;
 
-            octave::symbol_scope scope = fcn->scope ();
+            symbol_scope scope = fcn->scope ();
 
             std::list<std::string> plst = scope.parent_fcn_names ();
 
@@ -211,7 +211,7 @@
   void
   symbol_scope_rep::cache_dir_name (const std::string& name)
   {
-    m_dir_name = octave::sys::canonicalize_file_name (name);
+    m_dir_name = sys::canonicalize_file_name (name);
   }
 
   bool
--- a/libinterp/corefcn/syscalls.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/syscalls.cc	Sun May 16 09:44:35 2021 +0200
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/sysdep.cc	Sun May 16 09:44:35 2021 +0200
@@ -97,7 +97,9 @@
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <tlhelp32.h>
+#include <psapi.h>
 #include <shellapi.h>
+#include <shobjidl.h>
 
 #endif
 
@@ -178,29 +180,11 @@
 
 #endif
 
-  // Set app id if we have the SetCurrentProcessExplicitAppUserModelID
-  // available (>= Win7).  FIXME: Could we check for existence of this
-  // function in the configure script instead of dynamically loading
-  // shell32.dll?
-
   void set_application_id (void)
   {
 #if defined (__MINGW32__) || defined (_MSC_VER)
 
-    typedef HRESULT (WINAPI *SETCURRENTAPPID)(PCWSTR AppID);
-
-    HMODULE hShell = LoadLibrary ("shell32.dll");
-
-    if (hShell)
-      {
-        SETCURRENTAPPID pfnSetCurrentProcessExplicitAppUserModelID
-          = reinterpret_cast<SETCURRENTAPPID> (GetProcAddress (hShell, "SetCurrentProcessExplicitAppUserModelID"));
-
-        if (pfnSetCurrentProcessExplicitAppUserModelID)
-          pfnSetCurrentProcessExplicitAppUserModelID (L"gnu.octave." VERSION);
-
-        FreeLibrary (hShell);
-      }
+    SetCurrentProcessExplicitAppUserModelID (L"gnu.octave." VERSION);
 
 #endif
   }
@@ -225,7 +209,7 @@
   return octave_value (reinterpret_cast<std::ptrdiff_t> (status) > 32);
 #else
   // Quote file path
-  file = "\"" + file + "\"";
+  file = '"' + file + '"';
 
 #  if defined (__APPLE__)
 #    define FSYSTEM_OPEN_STR "open "
@@ -246,10 +230,10 @@
 
 DEFUN (__is_elevated_process__, args, ,
        doc: /* -*- texinfo -*-
-@deftypefn  {} {@var{retval} =} __is_elevated_process__ ()
+@deftypefn {} {@var{retval} =} __is_elevated_process__ ()
 Check if current process has elevated rights.
 
-On Windows, return true if the current process has elevated right. Otherwise,
+On Windows, return true if the current process has elevated right.  Otherwise,
 return false.
 On non-Windows platforms, this function fails with an error.
 @end deftypefn */)
@@ -282,6 +266,101 @@
 #endif
 }
 
+DEFUN (__wmemory__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {[@var{proc}, @var{sys}] =} __wmemory__ ()
+Return memory information on Windows.
+
+On non-Windows platforms, this function fails with an error.
+@end deftypefn */)
+{
+#if defined (OCTAVE_USE_WINDOWS_API)
+  if (args.length () != 0)
+    print_usage ();
+
+  // Get memory usage of the current process
+  octave_scalar_map proc_struct;
+
+  HANDLE h_proc = GetCurrentProcess ();
+  if (h_proc == nullptr)
+    error ("__wmemory__: Couldn't open handle to own process");
+
+  PROCESS_MEMORY_COUNTERS proc_mem_count;
+  if (GetProcessMemoryInfo (h_proc, &proc_mem_count, sizeof (proc_mem_count)))
+    {
+      proc_struct.setfield ("PageFaultCount",
+                            proc_mem_count.PageFaultCount);
+      proc_struct.setfield ("PeakWorkingSetSize",
+                            proc_mem_count.PeakWorkingSetSize);
+      proc_struct.setfield ("WorkingSetSize",
+                            proc_mem_count.WorkingSetSize);
+      proc_struct.setfield ("QuotaPeakPagedPoolUsage",
+                            proc_mem_count.QuotaPeakPagedPoolUsage);
+      proc_struct.setfield ("QuotaPagedPoolUsage",
+                            proc_mem_count.QuotaPagedPoolUsage);
+      proc_struct.setfield ("QuotaPeakNonPagedPoolUsage",
+                            proc_mem_count.QuotaPeakNonPagedPoolUsage);
+      proc_struct.setfield ("QuotaNonPagedPoolUsage",
+                            proc_mem_count.QuotaNonPagedPoolUsage);
+      proc_struct.setfield ("PagefileUsage",
+                            proc_mem_count.PagefileUsage);
+      proc_struct.setfield ("PeakPagefileUsage",
+                            proc_mem_count.PeakPagefileUsage);
+    }
+  else
+    {
+      proc_struct.setfield ("PageFaultCount", 0);
+      proc_struct.setfield ("PeakWorkingSetSize", 0);
+      proc_struct.setfield ("WorkingSetSize", 0);
+      proc_struct.setfield ("QuotaPeakPagedPoolUsage", 0);
+      proc_struct.setfield ("QuotaPagedPoolUsage", 0);
+      proc_struct.setfield ("QuotaPeakNonPagedPoolUsage", 0);
+      proc_struct.setfield ("QuotaNonPagedPoolUsage", 0);
+      proc_struct.setfield ("PagefileUsage", 0);
+      proc_struct.setfield ("PeakPagefileUsage", 0);
+    }
+
+  CloseHandle (h_proc);
+
+  // Get system memory usage
+  octave_scalar_map sys_struct;
+
+  MEMORYSTATUSEX mem_stat;
+
+  mem_stat.dwLength = sizeof (mem_stat);
+
+  if (GlobalMemoryStatusEx (&mem_stat))
+    {
+      sys_struct.setfield ("MemoryLoad", mem_stat.dwMemoryLoad);
+      sys_struct.setfield ("TotalPhys", mem_stat.ullTotalPhys);
+      sys_struct.setfield ("AvailPhys", mem_stat.ullAvailPhys);
+      sys_struct.setfield ("TotalPageFile", mem_stat.ullTotalPageFile);
+      sys_struct.setfield ("AvailPageFile", mem_stat.ullAvailPageFile);
+      sys_struct.setfield ("TotalVirtual", mem_stat.ullTotalVirtual);
+      sys_struct.setfield ("AvailVirtual", mem_stat.ullAvailVirtual);
+      sys_struct.setfield ("AvailExtendedVirtual",
+                           mem_stat.ullAvailExtendedVirtual);
+    }
+  else
+    {
+      sys_struct.setfield ("MemoryLoad", 0);
+      sys_struct.setfield ("TotalPhys", 0);
+      sys_struct.setfield ("AvailPhys", 0);
+      sys_struct.setfield ("TotalPageFile", 0);
+      sys_struct.setfield ("AvailPageFile", 0);
+      sys_struct.setfield ("TotalVirtual", 0);
+      sys_struct.setfield ("AvailVirtual", 0);
+      sys_struct.setfield ("AvailExtendedVirtual", 0);
+    }
+
+  return ovl (proc_struct, sys_struct);
+
+#else
+  octave_unused_parameter (args);
+  error ("__wmemory__: Function is only supported on Windows platforms");
+#endif
+}
+
 namespace octave
 {
 #if defined (__MINGW32__)
@@ -392,11 +471,11 @@
     if (len > 4 && name[0] == '\\' && name[1] == '\\')
       {
         // It starts with two slashes.  Find the next slash.
-        std::size_t next_slash = name.find ("\\", 3);
+        std::size_t next_slash = name.find ('\\', 3);
         if (next_slash != std::string::npos && len > next_slash+1)
           {
             // Check if it ends with the share
-            std::size_t last_slash = name.find ("\\", next_slash+1);
+            std::size_t last_slash = name.find ('\\', next_slash+1);
             if (last_slash == std::string::npos
                 || (len > next_slash+2 && last_slash == len-1))
               candidate = true;
@@ -619,22 +698,14 @@
   FILE * popen (const char *command, const char *mode)
   {
 #if defined (__MINGW32__) || defined (_MSC_VER)
-    wchar_t *wcommand = u8_to_wchar (command);
-    wchar_t *wmode = u8_to_wchar (mode);
-
-    unwind_protect frame;
-    frame.add_fcn (::free, static_cast<void *> (wcommand));
-    frame.add_fcn (::free, static_cast<void *> (wmode));
+    std::wstring wcommand = octave::sys::u8_to_wstring (command);
+    std::wstring wmode = octave::sys::u8_to_wstring (mode);
 
-    if (wmode && wmode[0] && ! wmode[1])
-      {
-        // Use binary mode on Windows if unspecified
-        wchar_t tmode[3] = {wmode[0], L'b', L'\0'};
+    // Use binary mode on Windows if unspecified
+    if (wmode.length () < 2)
+      wmode += L'b';
 
-        return _wpopen (wcommand, tmode);
-      }
-    else
-      return _wpopen (wcommand, wmode);
+    return _wpopen (wcommand.c_str (), wmode.c_str ());
 #else
     return ::popen (command, mode);
 #endif
@@ -865,9 +936,7 @@
     if (result != ERROR_SUCCESS)
       return result;
 
-    unwind_protect frame;
-
-    frame.add_fcn (reg_close_key_wrapper, h_subkey);
+    unwind_action restore_keys ([=] () { reg_close_key_wrapper (h_subkey); });
 
     std::wstring wname = sys::u8_to_wstring (name);
     DWORD length = 0;
@@ -978,7 +1047,8 @@
 
 Examples:
 
-Get a list of value names at the key @nospell{@qcode{'HKCU\Environment'}}:
+Get a list of value names at the key
+@nospell{@qcode{'HKCU@backslashchar{}Environment'}}:
 
 @example
 @group
@@ -1074,7 +1144,7 @@
       LONG retval = octave::get_regkey_value (h_rootkey, subkey_name,
                                               value_name, key_val);
       if (retval == ERROR_FILE_NOT_FOUND)
-        error ("winqueryreg: no value found for '%s' at %s\\%s.",
+        error ("winqueryreg: no value found for '%s' at %s\\%s",
                value_name.c_str (), rootkey_name.c_str (),
                subkey_name.c_str ());
       if (retval != ERROR_SUCCESS)
@@ -1253,7 +1323,7 @@
       else if (state == "query")
         ;// Do nothing
       else
-        error ("pause: first argument must be \"on\", \"off\" or \"query\"");
+        error (R"(pause: first argument must be "on", "off", or "query")");
 
       if (nargout > 0 || state == "query")
         retval.append (saved_state ? "on" : "off");
@@ -1284,7 +1354,7 @@
 %!test
 %! pause (1);
 
-%!error (pause (1, 2))
+%!error pause (1, 2)
 */
 
 // FIXME: maybe this should only return 1 if IEEE floating
--- a/libinterp/corefcn/sysdep.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/sysdep.h	Sun May 16 09:44:35 2021 +0200
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/text-engine.h	Sun May 16 09:44:35 2021 +0200
@@ -322,7 +322,7 @@
   text_processor
   {
   public:
-    virtual void visit (text_element_string& e) = 0;
+    virtual void visit (text_element_string&) { }
 
     virtual void visit (text_element_symbol&) { }
 
@@ -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/text-renderer.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/text-renderer.cc	Sun May 16 09:44:35 2021 +0200
@@ -28,28 +28,22 @@
 #endif
 
 #include "base-text-renderer.h"
+#include "error.h"
 #include "errwarn.h"
 #include "ft-text-renderer.h"
+#include "latex-text-renderer.h"
 #include "text-renderer.h"
 
 namespace octave
 {
-  static base_text_renderer *
-  make_text_renderer (void)
-  {
-    // Allow the possibility of choosing different text rendering
-    // implementations.
-
-    return make_ft_text_renderer ();
-  }
-
   text_renderer::text_renderer (void)
-    : rep (make_text_renderer ())
+    : rep (make_ft_text_renderer ()), latex_rep (make_latex_text_renderer ())
   { }
 
   text_renderer::~text_renderer (void)
   {
     delete rep;
+    delete latex_rep;
   }
 
   bool
@@ -83,9 +77,14 @@
   text_renderer::get_extent (const std::string& txt, double rotation,
                              const caseless_str& interpreter)
   {
-    static Matrix empty_extent (1, 4, 0.0);
+    static Matrix retval (1, 4, 0.0);
 
-    return ok () ? rep->get_extent (txt, rotation, interpreter) : empty_extent;
+    if (interpreter == "latex" && latex_rep->ok ())
+      retval = latex_rep->get_extent (txt, rotation, interpreter);
+    else if (ok ())
+      retval = rep->get_extent (txt, rotation, interpreter);
+
+    return retval;
   }
 
   void
@@ -111,14 +110,20 @@
                            const std::string& angle, double size)
   {
     if (ok ())
-      rep->set_font (name, weight, angle, size);
+      {
+        rep->set_font (name, weight, angle, size);
+        latex_rep->set_font (name, weight, angle, size);
+      }
   }
 
   void
   text_renderer::set_color (const Matrix& c)
   {
     if (ok ())
-      rep->set_color (c);
+      {
+        rep->set_color (c);
+        latex_rep->set_color (c);
+      }
   }
 
   void
@@ -131,7 +136,10 @@
     static Matrix empty_bbox (1, 4, 0.0);
     static uint8NDArray empty_pxls;
 
-    if (ok ())
+    if (interpreter == "latex" && latex_rep->ok ())
+      latex_rep->text_to_pixels (txt, pxls, bbox, halign, valign, rotation,
+                                 interpreter, handle_rotation);
+    else if (ok ())
       rep->text_to_pixels (txt, pxls, bbox, halign, valign, rotation,
                            interpreter, handle_rotation);
     else
@@ -151,7 +159,10 @@
     static Matrix empty_bbox (1, 4, 0.0);
     static std::list<text_renderer::string> empty_lst;
 
-    if (ok ())
+    if (interpreter == "latex" && latex_rep->ok ())
+      latex_rep->text_to_strlist (txt, lst, bbox, halign, valign, rotation,
+                                  interpreter);
+    else if (ok ())
       rep->text_to_strlist (txt, lst, bbox, halign, valign, rotation,
                             interpreter);
     else
--- a/libinterp/corefcn/text-renderer.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/text-renderer.h	Sun May 16 09:44:35 2021 +0200
@@ -136,12 +136,13 @@
 
       string (const std::string& s, font& f, const double x0, const double y0)
         : str (s), family (f.get_name ()), fnt (f), x (x0), y (y0), z (0.0),
-          xdata (), code (0), color (Matrix (1,3,0.0))
+          xdata (), code (0), color (Matrix (1,3,0.0)), svg_element ()
       { }
 
       string (const string& s)
         : str (s.str), family (s.family), fnt (s.fnt), x (s.x), y (s.y),
-          z (s.z), xdata (s.xdata), code (s.code), color (s.color)
+          z (s.z), xdata (s.xdata), code (s.code), color (s.color),
+          svg_element (s.svg_element)
       { }
 
       ~string (void) = default;
@@ -200,6 +201,10 @@
 
       uint32_t get_code (void) const { return code; }
 
+      void set_svg_element (const std::string& svg) { svg_element = svg; }
+
+      std::string get_svg_element (void) const { return svg_element; }
+
       void set_color (const uint8NDArray& c)
       {
         color(0) = static_cast<double> (c(0)) / 255;
@@ -218,6 +223,7 @@
       std::vector<double> xdata;
       uint32_t code;
       Matrix color;
+      std::string svg_element;
     };
 
     void text_to_strlist (const std::string& txt,
@@ -228,6 +234,7 @@
   private:
 
     base_text_renderer *rep;
+    base_text_renderer *latex_rep;
   };
 }
 
--- a/libinterp/corefcn/toplev.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/toplev.cc	Sun May 16 09:44:35 2021 +0200
@@ -72,6 +72,9 @@
 #  define SHELL_PATH "/bin/sh"
 #endif
 
+#define STRINGIFY(s) STRINGIFY1(s)
+#define STRINGIFY1(s) #s
+
 DEFUN (warranty, , ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} warranty ()
@@ -111,7 +114,7 @@
 
   octave::child_list& kids
     = octave::__get_child_list__ ("run_command_and_return_output");
-  frame.add_method (kids, &octave::child_list::remove, cmd->pid ());
+  frame.add (&octave::child_list::remove, kids, cmd->pid ());
 
   if (! *cmd)
     error ("system: unable to start subprocess for '%s'", cmd_str.c_str ());
@@ -264,9 +267,9 @@
         {
           return_output = args(1).is_true ();
         }
-      catch (octave::execution_exception& e)
+      catch (octave::execution_exception& ee)
         {
-          error (e, "system: RETURN_OUTPUT must be boolean value true or false");
+          error (ee, "system: RETURN_OUTPUT must be boolean value true or false");
         }
     }
 
@@ -281,9 +284,8 @@
     cmd_str = '"' + cmd_str + '"';
 #endif
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (restore_signal_mask, get_signal_mask ());
+  octave::unwind_action restore_mask
+    ([] (void *mask) { restore_signal_mask (mask); }, get_signal_mask ());
 
   octave_unblock_async_signals ();
   octave_unblock_signal_by_name ("SIGTSTP");
@@ -294,7 +296,7 @@
     retval = run_command_and_return_output (cmd_str);
   else
     {
-      int status = system (cmd_str.c_str ());
+      int status = octave::sys::system (cmd_str);
 
       // The value in status is as returned by waitpid.  If
       // the process exited normally, extract the actual exit
@@ -424,9 +426,11 @@
            { "localverarchlibdir", octave::config::local_ver_arch_lib_dir () },
            { "localverfcnfiledir", octave::config::local_ver_fcn_file_dir () },
            { "localveroctfiledir", octave::config::local_ver_oct_file_dir () },
+           { "major_version", STRINGIFY (OCTAVE_MAJOR_VERSION) },
            { "man1dir", octave::config::man1_dir () },
            { "man1ext", octave::config::man1_ext () },
            { "mandir", octave::config::man_dir () },
+           { "minor_version", STRINGIFY (OCTAVE_MINOR_VERSION) },
            { "octdatadir", octave::config::oct_data_dir () },
            { "octdocdir", octave::config::oct_doc_dir () },
            { "octetcdir", octave::config::oct_etc_dir () },
@@ -435,6 +439,7 @@
            { "octincludedir", octave::config::oct_include_dir () },
            { "octlibdir", octave::config::oct_lib_dir () },
            { "octtestsdir", octave::config::oct_tests_dir () },
+           { "patch_version", STRINGIFY (OCTAVE_PATCH_VERSION) },
            { "release_date", OCTAVE_RELEASE_DATE },
            { "startupfiledir", octave::config::startupfile_dir () },
            { "version", OCTAVE_VERSION }};
--- a/libinterp/corefcn/tril.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/tril.cc	Sun May 16 09:44:35 2021 +0200
@@ -209,8 +209,10 @@
   dim_vector dims = arg.dims ();
   if (dims.ndims () != 2)
     error ("%s: need a 2-D matrix", name.c_str ());
-  else if (k < -dims(0) || k > dims(1))
-    error ("%s: requested diagonal out of range", name.c_str ());
+  else if (k < -dims(0))
+    k = -dims(0);
+  else if (k > dims(1))
+    k = dims(1);
 
   octave_value retval;
 
@@ -284,41 +286,43 @@
         octave_value_list ov_idx;
         std::list<octave_value_list> idx_tmp;
         ov_idx(1) = static_cast<double> (nc+1);
-        ov_idx(0) = Range (1, nr);
+        ov_idx(0) = octave::range<double> (1, nr);
         idx_tmp.push_back (ov_idx);
         ov_idx(1) = static_cast<double> (nc);
         tmp = tmp.resize (dim_vector (0,0));
-        tmp = tmp.subsasgn ("(", idx_tmp, arg.do_index_op (ov_idx));
+        tmp = tmp.subsasgn ("(", idx_tmp, arg.index_op (ov_idx));
         tmp = tmp.resize (dims);
 
+        octave_idx_type one = 1;
+
         if (lower)
           {
-            octave_idx_type st = (nc < nr + k ? nc : nr + k);
+            octave_idx_type st = std::min (nc, nr + k);
 
             for (octave_idx_type j = 1; j <= st; j++)
               {
-                octave_idx_type nr_limit = (1 > j - k ? 1 : j - k);
+                octave_idx_type nr_limit = std::max (one, j - k);
                 ov_idx(1) = static_cast<double> (j);
-                ov_idx(0) = Range (nr_limit, nr);
+                ov_idx(0) = octave::range<double> (nr_limit, nr);
                 std::list<octave_value_list> idx;
                 idx.push_back (ov_idx);
 
-                tmp = tmp.subsasgn ("(", idx, arg.do_index_op (ov_idx));
+                tmp = tmp.subsasgn ("(", idx, arg.index_op (ov_idx));
               }
           }
         else
           {
-            octave_idx_type st = (k + 1 > 1 ? k + 1 : 1);
+            octave_idx_type st = std::max (k + 1, one);
 
             for (octave_idx_type j = st; j <= nc; j++)
               {
-                octave_idx_type nr_limit = (nr < j - k ? nr : j - k);
+                octave_idx_type nr_limit = std::min (nr, j - k);
                 ov_idx(1) = static_cast<double> (j);
-                ov_idx(0) = Range (1, nr_limit);
+                ov_idx(0) = octave::range<double> (1, nr_limit);
                 std::list<octave_value_list> idx;
                 idx.push_back (ov_idx);
 
-                tmp = tmp.subsasgn ("(", idx, arg.do_index_op (ov_idx));
+                tmp = tmp.subsasgn ("(", idx, arg.index_op (ov_idx));
               }
           }
 
@@ -428,24 +432,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	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2018-2021 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/urlwrite.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/urlwrite.cc	Sun May 16 09:44:35 2021 +0200
@@ -52,12 +52,6 @@
 #include "unwind-prot.h"
 #include "url-handle-manager.h"
 
-static void
-delete_file (const std::string& file)
-{
-  octave::sys::unlink (file);
-}
-
 DEFUN (urlwrite, args, nargout,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} urlwrite (@var{url}, @var{localfile})
@@ -148,9 +142,8 @@
   if (! ofile.is_open ())
     error ("urlwrite: unable to open file");
 
-  octave::unwind_protect_safe frame;
-
-  frame.add_fcn (delete_file, filename);
+  int(*unlink_fptr)(const std::string&) = octave::sys::unlink;
+  octave::unwind_action_safe unlink_action (unlink_fptr, filename);
 
   octave::url_transfer url_xfer (url, ofile);
 
@@ -164,7 +157,7 @@
   ofile.close ();
 
   if (url_xfer.good ())
-    frame.discard ();
+    unlink_action.discard ();
 
   if (nargout > 0)
     {
--- a/libinterp/corefcn/utils.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/utils.cc	Sun May 16 09:44:35 2021 +0200
@@ -133,6 +133,167 @@
 
 namespace octave
 {
+  bool
+  make_valid_name (std::string& str, const make_valid_name_options& options)
+  {
+    // If `isvarname (str)`, no modifications necessary.
+    if (valid_identifier (str) && ! iskeyword (str))
+      return false;
+
+    // Change whitespace followed by lowercase letter to uppercase, except
+    // for the first
+    bool previous = false;
+    bool any_non_space = false;
+    for (char& c : str)
+      {
+        c = ((any_non_space && previous && std::isalpha (c)) ? std::toupper (c)
+                                                             : c);
+        previous = std::isspace (c);
+        any_non_space |= (! previous);  // once true, always true
+      }
+
+    // Remove any whitespace.
+    str.erase (std::remove_if (str.begin(), str.end(),
+                               [] (unsigned char x)
+                                  { return std::isspace(x); }),
+               str.end());
+    if (str.empty ())
+      str = options.get_prefix ();
+
+    // Add prefix and capitalize first character, if `str` is a reserved
+    // keyword.
+    if (iskeyword (str))
+      {
+        str[0] = std::toupper (str[0]);
+        str = options.get_prefix () + str;
+      }
+
+    // Add prefix if first character is not a letter or underscore.
+    if (! std::isalpha (str[0]) && str[0] != '_')
+      str = options.get_prefix () + str;
+
+    // Replace non alphanumerics or underscores
+    if (options.get_replacement_style () == "underscore")
+      for (char& c : str)
+        c = (std::isalnum (c) ? c : '_');
+    else if (options.get_replacement_style () == "delete")
+      str.erase (std::remove_if (str.begin(), str.end(),
+                                 [] (unsigned char x)
+                                    { return ! std::isalnum (x) && x != '_'; }),
+                 str.end());
+    else if (options.get_replacement_style () == "hex")
+      {
+        const std::string permitted_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                            "abcdefghijklmnopqrstuvwxyz"
+                                            "_0123456789";
+        // Get the first non-permitted char.
+        std::size_t pos = str.find_first_not_of (permitted_chars);
+        // Buffer for hex string "0xFF" (+1 for null terminator).
+        char hex_str[5];
+        // Repeat until end of string.
+        while (pos != std::string::npos)
+          {
+            // Replace non-permitted char by it's hex value.
+            std::snprintf (hex_str, sizeof (hex_str), "0x%02X", str[pos]);
+            str.replace (pos, 1, hex_str);
+            // Get the next occurrence from the last position.
+            // (-1 for null terminator)
+            pos = str.find_first_not_of (permitted_chars,
+                                         pos + sizeof (hex_str) - 1);
+          }
+      }
+
+    return true;
+  }
+
+  make_valid_name_options::make_valid_name_options
+    (const octave_value_list& args)
+  {
+    auto nargs = args.length ();
+    if (nargs == 0)
+      return;
+
+    // nargs = 2, 4, 6, ... permitted
+    if (nargs % 2)
+      error ("makeValidName: property/value options must occur in pairs");
+
+    auto str_to_lower = [] (std::string& s)
+                           {
+                             std::transform (s.begin(), s.end(), s.begin(),
+                                             [] (unsigned char c)
+                                                { return std::tolower(c); });
+                           };
+
+    for (auto i = 0; i < nargs; i = i + 2)
+      {
+        std::string parameter = args(i).xstring_value ("makeValidName: "
+          "option argument must be a string");
+        str_to_lower (parameter);
+        if (parameter == "replacementstyle")
+          {
+            m_replacement_style = args(i + 1).xstring_value ("makeValidName: "
+              "'ReplacementStyle' value must be a string");
+            str_to_lower (m_replacement_style);
+            if ((m_replacement_style != "underscore")
+                && (m_replacement_style != "delete")
+                && (m_replacement_style != "hex"))
+              error ("makeValidName: invalid 'ReplacementStyle' value '%s'",
+                     m_replacement_style.c_str ());
+          }
+        else if (parameter == "prefix")
+          {
+            m_prefix = args(i + 1).xstring_value ("makeValidName: "
+              "'Prefix' value must be a string");
+            if (! octave::valid_identifier (m_prefix)
+                || octave::iskeyword (m_prefix))
+              error ("makeValidName: invalid 'Prefix' value '%s'",
+                     m_prefix.c_str ());
+          }
+        else
+          error ("makeValidName: unknown property '%s'", parameter.c_str ());
+      }
+  }
+}
+
+DEFUN (__make_valid_name__, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn  {} {@var{varname} =} __make_valid_name__ (@var{str})
+@deftypefnx {} {@var{varname} =} __make_valid_name__ (@var{str}, @qcode{"ReplacementStyle"})
+@deftypefnx {} {@var{varname} =} __make_valid_name__ (@var{str}, @qcode{"ReplacementStyle"}, @qcode{"Prefix"})
+@deftypefnx {} {[@var{varname}, @var{ismodified}] =} __make_valid_name__ (@dots{})
+Return a valid variable name @var{varname} from input @var{str}.
+
+For more documentation, see @code{matlab.lang.makeValidName}.
+
+@seealso{isvarname, matlab.lang.makeValidName}
+@end deftypefn */)
+{
+  auto nargin = args.length ();
+  if (nargin < 1)
+    print_usage ();
+
+  octave::make_valid_name_options options (args.slice (1, nargin - 1));
+
+  if (args(0).is_string ())
+    {
+      std::string varname = args(0).string_value ();
+      bool is_modified = octave::make_valid_name (varname, options);
+      return ovl (varname, is_modified);
+    }
+  else if (args(0).iscellstr ())
+    {
+      Array<std::string> varnames = args(0).cellstr_value ();
+      Array<bool> is_modified (varnames.dims ());
+      for (auto i = 0; i < varnames.numel (); i++)
+        is_modified(i) = octave::make_valid_name (varnames(i), options);
+      return ovl (varnames, is_modified);
+    }
+  else
+    error ("makeValidName: STR must be a string or cellstr");
+}
+
+namespace octave
+{
   // Return TRUE if F and G are both names for the same file.
 
   bool same_file (const std::string& f, const std::string& g)
@@ -635,7 +796,7 @@
 
     if (! dir.empty ())
       {
-        load_path& lp = __get_load_path__ ("contents_in_file_path");
+        load_path& lp = __get_load_path__ ("contents_file_in_path");
 
         std::string tcontents
           = sys::file_ops::concat (lp.find_dir (dir), "Contents.m");
@@ -783,8 +944,8 @@
 Convert escape sequences in @var{string} to the characters they represent.
 
 Escape sequences begin with a leading backslash
-(@qcode{'@xbackslashchar{}'}) followed by 1--3 characters
-(.e.g., @qcode{"@xbackslashchar{}n"} => newline).
+(@qcode{'@backslashchar{}'}) followed by 1--3 characters
+(.e.g., @qcode{"@backslashchar{}n"} => newline).
 @seealso{undo_string_escapes}
 @end deftypefn */)
 {
@@ -1285,9 +1446,9 @@
 
                     retval *= jdx.length (dv(i));
                   }
-                catch (const index_exception& e)
+                catch (const index_exception& ie)
                   {
-                    error ("dims_to_numel: invalid index %s", e.what ());
+                    error ("dims_to_numel: invalid index %s", ie.what ());
                   }
               }
           }
@@ -1500,7 +1661,7 @@
 
 Implementation Note: Strings are first converted to double values before the
 checks for valid indices are made.  Unless a string contains the NULL
-character @nospell{"@xbackslashchar{}0"}, it will always be a valid index.
+character @nospell{"@backslashchar{}0"}, it will always be a valid index.
 @end deftypefn */)
 {
   int nargin = args.length ();
@@ -1516,7 +1677,7 @@
 
   try
     {
-      idx_vector idx = args(0).index_vector (true);
+      octave::idx_vector idx = args(0).index_vector (true);
 
       if (nargin == 2)
         retval = idx.extent (n) <= n;
@@ -1648,183 +1809,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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/utils.h	Sun May 16 09:44:35 2021 +0200
@@ -46,6 +46,63 @@
   extern OCTINTERP_API bool valid_identifier (const char *s);
   extern OCTINTERP_API bool valid_identifier (const std::string& s);
 
+  //! Helper class for `make_valid_name` function calls.
+  //!
+  //! Extracting options separately for multiple (e.g. 1000+) function calls
+  //! avoids expensive repetitive parsing of the very same options.
+
+  class
+  OCTINTERP_API
+  make_valid_name_options
+  {
+  public:
+
+    //! Default options for `make_valid_name` function calls.
+    //!
+    //! Calling the constructor without arguments is equivalent to:
+    //!
+    //! @code{.cc}
+    //! make_valid_name_options (ovl ("ReplacementStyle", "underscore",
+    //!                               "Prefix", "x"));
+    //! @endcode
+
+    make_valid_name_options () = default;
+
+    //! Extract attribute-value-pairs from an octave_value_list of strings.
+    //!
+    //! If attributes occur multiple times, the rightmost pair is chosen.
+    //!
+    //! @code{.cc}
+    //! make_valid_name_options (ovl ("ReplacementStyle", "hex", ...));
+    //! @endcode
+
+    make_valid_name_options (const octave_value_list& args);
+
+    //! @return ReplacementStyle, see `help matlab.lang.makeValidName`.
+
+    const std::string&
+    get_replacement_style () const { return m_replacement_style; }
+
+    //! @return Prefix, see `help matlab.lang.makeValidName`.
+
+    const std::string& get_prefix () const { return m_prefix; }
+
+  private:
+
+    std::string m_replacement_style{"underscore"};
+    std::string m_prefix{"x"};
+  };
+
+  //! Modify @p str to be a valid variable name.
+  //!
+  //! @param str input string
+  //! @param options see also `help matlab.lang.makeValidName`.
+  //!
+  //! @return true, if @p str was modified.
+
+  extern OCTINTERP_API bool
+  make_valid_name (std::string& str, const make_valid_name_options& options);
+
   extern OCTINTERP_API bool
   same_file (const std::string& f, const std::string& g);
 
@@ -141,139 +198,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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/variables.cc	Sun May 16 09:44:35 2021 +0200
@@ -469,11 +469,25 @@
   if (nargin < 1 || nargin > 2)
     print_usage ();
 
+  // For compatibility with undocumented Matlab behavior, return 0 if
+  // there is an empty built-in object as the only argument.
+
+  if (args(0).builtin_type () != btyp_unknown && args(0).isempty ())
+    return ovl (0);
+
+  // Also for compatibility, return 0 if the second argument is an empty
+  // built-in object.
+
+  if (nargin == 2 && args(1).builtin_type () != btyp_unknown
+      && args(1).isempty ())
+    return ovl (0);
+
   std::string name = args(0).xstring_value ("exist: NAME must be a string");
 
   if (nargin == 2)
     {
-      std::string type = args(1).xstring_value ("exist: TYPE must be a string");
+      std::string type
+        = args(1).xstring_value ("exist: TYPE must be a string");
 
       if (type == "class")
         warning (R"(exist: "class" type argument is not implemented)");
@@ -531,10 +545,10 @@
 %! end_unwind_protect
 %! assert (exist (fullfile (pwd (), "%nonexistentfile%"), "file"), 0);
 
-%!assert (exist ("fftw"), 3);
-%!assert (exist ("fftw.oct"), 3);
-%!assert (exist ("fftw", "file"), 3);
-%!assert (exist ("fftw", "builtin"), 0);
+%!assert (exist ("fftw"), 3)
+%!assert (exist ("fftw.oct"), 3)
+%!assert (exist ("fftw", "file"), 3)
+%!assert (exist ("fftw", "builtin"), 0)
 
 %!assert (exist ("ftp"), 2);
 %!assert (exist ("ftp.m"), 2);
@@ -1446,8 +1460,8 @@
   if (val.is_defined ())
     {
       // Ensure auto-restoration.
-      octave::unwind_protect frame;
-      frame.protect_var (Vmissing_function_hook);
+      octave::unwind_protect_var<std::string>
+        restore_var (Vmissing_function_hook);
 
       // Clear the variable prior to calling the function.
       const std::string func_name = Vmissing_function_hook;
@@ -1465,27 +1479,49 @@
 
 DEFMETHOD (__varval__, interp, args, ,
            doc: /* -*- texinfo -*-
-@deftypefn {} {} __varval__ (@var{name})
+@deftypefn {} {@var{value} =} __varval__ (@var{name})
 Return the value of the variable @var{name} directly from the symbol table.
+
+If @var{name} does not exist then nothing is returned, not even an empty matrix
+(@code{[]}), since there would be no way to distinguish between a variable
+not found in the symbol table and a variable who's value was @code{[]}.
+
+A standard usage pattern is to code a @code{try}/@code{catch} block around a
+call to @code{__varval__}.
+
+Example Code
+
+@example
+@group
+try
+  @var{val} = __varval__ (@var{name});
+catch
+  ## No variable @var{name} found in symbol table
+  @var{val} = NA;                  # Substitute Not Available (NA)
+  error ("@var{name} not found");  # or, throw an error.
+end_try_catch
+@end group
+@end example
+
+Programming Note: The magic @var{name} @qcode{".argn."} will retrieve the text
+of input arguments to a function and is used by @code{inputname} internally.
+@seealso{inputname}
 @end deftypefn */)
 {
   if (args.length () != 1)
     print_usage ();
 
-  std::string name = args(0).xstring_value ("__varval__: first argument must be a variable name");
-
-  std::string nm = args(0).string_value ();
+  std::string name = args(0).xstring_value ("__varval__: NAME must be a string");
 
-  // FIXME: we need this kluge to implement inputname in a .m file.
-
-  if (nm == ".argn.")
+  // We need this kluge to implement inputname in a .m file.
+  if (name == ".argn.")
     {
       octave::tree_evaluator& tw = interp.get_evaluator ();
 
       return tw.get_auto_fcn_var (octave::stack_frame::ARG_NAMES);
     }
 
-  return interp.varval (nm);
+  return interp.varval (name);
 }
 
 static std::string Vmissing_component_hook;
@@ -1520,42 +1556,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;
-
-  std::size_t pos = 0;
-
-  std::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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/variables.h	Sun May 16 09:44:35 2021 +0200
@@ -116,8 +116,4 @@
 extern OCTINTERP_API std::string
 maybe_missing_function_hook (const std::string& name);
 
-OCTAVE_DEPRECATED (5, "this function will be removed in a future version of Octave")
-extern OCTINTERP_API string_vector
-get_struct_elts (const std::string& text);
-
 #endif
--- a/libinterp/corefcn/xpow.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/xpow.cc	Sun May 16 09:44:35 2021 +0200
@@ -119,7 +119,10 @@
   octave_idx_type nr = b.rows ();
   octave_idx_type nc = b.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   try
@@ -170,7 +173,10 @@
   octave_idx_type nr = b.rows ();
   octave_idx_type nc = b.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   EIG b_eig (b);
@@ -209,7 +215,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   if (xisint (b))
@@ -295,7 +304,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   if (xisint (b))
@@ -335,7 +347,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   EIG a_eig (a);
@@ -383,7 +398,10 @@
   octave_idx_type nr = b.rows ();
   octave_idx_type nc = b.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   EIG b_eig (b);
@@ -431,7 +449,10 @@
   octave_idx_type nr = b.rows ();
   octave_idx_type nc = b.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   EIG b_eig (b);
@@ -470,7 +491,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   if (xisint (b))
@@ -556,7 +580,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   EIG a_eig (a);
@@ -590,7 +617,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return Matrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   ComplexDiagMatrix r (nr, nc);
@@ -711,7 +741,7 @@
 }
 
 octave_value
-elem_xpow (double a, const Range& r)
+elem_xpow (double a, const octave::range<double>& r)
 {
   octave_value retval;
 
@@ -722,19 +752,18 @@
     {
       octave_idx_type n = r.numel ();
       Matrix result (1, n);
-      if (same_sign (r.base (), r.inc ()))
+      if (same_sign (r.base (), r.increment ()))
         {
           double base = std::pow (a, r.base ());
-          double inc = std::pow (a, r.inc ());
+          double inc = std::pow (a, r.increment ());
           result(0) = base;
           for (octave_idx_type i = 1; i < n; i++)
             result(i) = (base *= inc);
         }
       else
         {
-          // Don't use Range::limit () here.
-          double limit = std::pow (a, r.base () + (n-1) * r.inc ());
-          double inc = std::pow (a, -r.inc ());
+          double limit = std::pow (a, r.final_value ());
+          double inc = std::pow (a, -r.increment ());
           result(n-1) = limit;
           for (octave_idx_type i = n-2; i >= 0; i--)
             result(i) = (limit *= inc);
@@ -743,7 +772,10 @@
       retval = result;
     }
   else
-    retval = elem_xpow (a, r.matrix_value ());
+    {
+      Matrix tmp = r.array_value ();
+      retval = elem_xpow (a, tmp);
+    }
 
   return retval;
 }
@@ -940,7 +972,7 @@
 }
 
 octave_value
-elem_xpow (const Complex& a, const Range& r)
+elem_xpow (const Complex& a, const octave::range<double>& r)
 {
   octave_value retval;
 
@@ -952,19 +984,18 @@
       octave_idx_type n = r.numel ();
       ComplexMatrix result (1, n);
 
-      if (same_sign (r.base (), r.inc ()))
+      if (same_sign (r.base (), r.increment ()))
         {
           Complex base = std::pow (a, r.base ());
-          Complex inc = std::pow (a, r.inc ());
+          Complex inc = std::pow (a, r.increment ());
           result(0) = base;
           for (octave_idx_type i = 1; i < n; i++)
             result(i) = (base *= inc);
         }
       else
         {
-          // Don't use Range::limit () here.
-          Complex limit = std::pow (a, r.base () + (n-1) * r.inc ());
-          Complex inc = std::pow (a, -r.inc ());
+          Complex limit = std::pow (a, r.final_value ());
+          Complex inc = std::pow (a, -r.increment ());
           result(n-1) = limit;
           for (octave_idx_type i = n-2; i >= 0; i--)
             result(i) = (limit *= inc);
@@ -973,7 +1004,10 @@
       retval = result;
     }
   else
-    retval = elem_xpow (a, r.matrix_value ());
+    {
+      Matrix tmp = r.array_value ();
+      retval = elem_xpow (a, tmp);
+    }
 
   return retval;
 }
@@ -1518,7 +1552,10 @@
   octave_idx_type nr = b.rows ();
   octave_idx_type nc = b.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   FloatEIG b_eig (b);
@@ -1570,7 +1607,10 @@
   octave_idx_type nr = b.rows ();
   octave_idx_type nc = b.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   FloatEIG b_eig (b);
@@ -1609,7 +1649,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   if (xisint (b))
@@ -1695,7 +1738,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   if (xisint (b))
@@ -1725,7 +1771,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   FloatEIG a_eig (a);
@@ -1773,7 +1822,10 @@
   octave_idx_type nr = b.rows ();
   octave_idx_type nc = b.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   FloatEIG b_eig (b);
@@ -1821,7 +1873,10 @@
   octave_idx_type nr = b.rows ();
   octave_idx_type nc = b.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   FloatEIG b_eig (b);
@@ -1860,7 +1915,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   if (xisint (b))
@@ -1946,7 +2004,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   FloatEIG a_eig (a);
@@ -1980,7 +2041,10 @@
   octave_idx_type nr = a.rows ();
   octave_idx_type nc = a.cols ();
 
-  if (nr == 0 || nc == 0 || nr != nc)
+  if (nr == 0 || nc == 0)
+    return FloatMatrix ();
+
+  if (nr != nc)
     err_nonsquare_matrix ();
 
   FloatComplexDiagMatrix r (nr, nc);
--- a/libinterp/corefcn/xpow.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/corefcn/xpow.h	Sun May 16 09:44:35 2021 +0200
@@ -75,7 +75,7 @@
 
 extern OCTINTERP_API octave_value elem_xpow (double a, const Matrix& b);
 extern OCTINTERP_API octave_value elem_xpow (double a, const ComplexMatrix& b);
-extern OCTINTERP_API octave_value elem_xpow (double a, const Range& r);
+extern OCTINTERP_API octave_value elem_xpow (double a, const octave::range<double>& r);
 
 extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, double b);
 extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, const Matrix& b);
@@ -86,7 +86,7 @@
 extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const Matrix& b);
 extern OCTINTERP_API octave_value elem_xpow (const Complex& a,
                                              const ComplexMatrix& b);
-extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const Range& r);
+extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const octave::range<double>& r);
 
 extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, double b);
 extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a,
--- a/libinterp/dldfcn/__delaunayn__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/__delaunayn__.cc	Sun May 16 09:44:35 2021 +0200
@@ -65,23 +65,17 @@
 
 #  include "oct-qhull.h"
 
-#  if defined (NEED_QHULL_VERSION)
+#  if defined (NEED_QHULL_R_VERSION)
 char qh_version[] = "__delaunayn__.oct 2007-08-21";
 #  endif
 
 static void
-close_fcn (FILE *f)
+free_qhull_memory (qhT *qh)
 {
-  std::fclose (f);
-}
-
-static void
-free_qhull_memory ()
-{
-  qh_freeqhull (! qh_ALL);
+  qh_freeqhull (qh, ! qh_ALL);
 
   int curlong, totlong;
-  qh_memfreeshort (&curlong, &totlong);
+  qh_memfreeshort (qh, &curlong, &totlong);
 
   if (curlong || totlong)
     warning ("__delaunayn__: did not free %d bytes of long memory (%d pieces)",
@@ -161,36 +155,37 @@
       double *pt_array = p.fortran_vec ();
       boolT ismalloc = false;
 
-      // Qhull flags argument is not const char*
-      OCTAVE_LOCAL_BUFFER (char, flags, 9 + options.length ());
+      std::string cmd = "qhull d " + options;
 
-      sprintf (flags, "qhull d %s", options.c_str ());
+      // Set the outfile pointer to stdout for status information.
+      FILE *outfile = nullptr;
 
-      octave::unwind_protect frame;
-
-      // Replace the outfile pointer with stdout for debugging information.
+      // Set the errfile pointer to stderr for errors and summary information.
+      // Note: pointer cannot be NULL to disable reporting, unlike outfile.
 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)
-      FILE *outfile = std::fopen ("NUL", "w");
+      FILE *errfile = std::fopen ("NUL", "w");
 #else
-      FILE *outfile = std::fopen ("/dev/null", "w");
+      FILE *errfile = std::fopen ("/dev/null", "w");
 #endif
-      FILE *errfile = stderr;
 
-      if (! outfile)
-        error ("__delaunayn__: unable to create temporary file for output");
+      if (! errfile)
+        error ("__delaunayn__: unable to redirect Qhull errors to /dev/null");
+
+      octave::unwind_action close_errfile ([=] () { std::fclose (errfile); });
 
-      frame.add_fcn (close_fcn, outfile);
+      qhT context = { };
+      qhT *qh = &context;
 
-      int exitcode = qh_new_qhull (dim, n, pt_array,
-                                   ismalloc, flags, outfile, errfile);
+      int exitcode = qh_new_qhull (qh, dim, n, pt_array, ismalloc, &cmd[0],
+                                   outfile, errfile);
 
-      frame.add_fcn (free_qhull_memory);
+      octave::unwind_action free_memory ([qh] () { free_qhull_memory (qh); });
 
       if (exitcode)
         error ("__delaunayn__: qhull failed");
 
       // triangulate non-simplicial facets
-      qh_triangulate ();
+      qh_triangulate (qh);
 
       facetT *facet;
       vertexT *vertex, **vertexp;
@@ -217,7 +212,7 @@
 
               FOREACHvertex_ (facet->vertices)
                 {
-                  simpl(i, j++) = 1 + qh_pointid(vertex->point);
+                  simpl(i, j++) = 1 + qh_pointid(qh, vertex->point);
                 }
               i++;
             }
--- a/libinterp/dldfcn/__init_fltk__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/__init_fltk__.cc	Sun May 16 09:44:35 2021 +0200
@@ -2490,22 +2490,21 @@
 // autoloaded functions in the PKG_ADD file and will not be visible to
 // the interpreter.
 
+#if defined (HAVE_FLTK)
 static octave_value_list
 F__fltk_check__ (octave::interpreter& interp, const octave_value_list&, int)
 {
-#if defined (HAVE_FLTK)
   Fl::check ();
 
   if (Vdrawnow_requested)
     Fdrawnow (interp);
 
   return octave_value_list ();
-#else
   octave_unused_parameter (interp);
 
   err_disabled_feature ("__fltk_check__", "OpenGL and FLTK");
+}
 #endif
-}
 
 // Initialize the fltk graphics toolkit.
 
--- a/libinterp/dldfcn/__init_gnuplot__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/__init_gnuplot__.cc	Sun May 16 09:44:35 2021 +0200
@@ -134,10 +134,8 @@
     // Prevent recursion
     if (! drawnow_executing)
       {
-        octave::unwind_protect frame;
-        frame.protect_var (drawnow_executing);
+        octave::unwind_protect_var<bool> restore_var (drawnow_executing, true);
 
-        drawnow_executing = true;
         octave_value_list args;
         args(0) = go.get_handle ().as_octave_value ();
         octave::feval ("__gnuplot_drawnow__", args);
@@ -235,7 +233,7 @@
           retval = fs.exists ();
         }
     }
-  catch (octave::execution_exception&)
+  catch (const octave::execution_exception&)
     {
       octave::interpreter& interp
         = octave::__get_interpreter__ ("have_gnuplot_binary");
--- a/libinterp/dldfcn/__ode15__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/__ode15__.cc	Sun May 16 09:44:35 2021 +0200
@@ -30,6 +30,8 @@
 #include "dColVector.h"
 #include "dMatrix.h"
 #include "dSparse.h"
+#include "f77-fcn.h"
+#include "lo-utils.h"
 
 #include "Cell.h"
 #include "defun-dld.h"
@@ -117,20 +119,20 @@
   static inline realtype *
   nv_data_s (N_Vector& v)
   {
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+#  if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
     // Disable warning from GCC about old-style casts in Sundials
     // macro expansions.  Do this in a function so that this
     // diagnostic may still be enabled for the rest of the file.
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wold-style-cast"
-#endif
+#   pragma GCC diagnostic push
+#   pragma GCC diagnostic ignored "-Wold-style-cast"
+#  endif
 
     return NV_DATA_S (v);
 
-#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+#  if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
     // Restore prevailing warning state for remainder of the file.
-#  pragma GCC diagnostic pop
-#endif
+#   pragma GCC diagnostic pop
+#  endif
   }
 
   class IDA
@@ -166,8 +168,8 @@
       : m_t0 (0.0), m_y0 (), m_yp0 (), m_havejac (false), m_havejacfun (false),
         m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fun (),
         m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr),
-        m_spdfdyp (nullptr), m_fun (nullptr), m_jacfun (nullptr), m_jacspfun (nullptr),
-        m_jacdcell (nullptr), m_jacspcell (nullptr),
+        m_spdfdyp (nullptr), m_fun (nullptr), m_jacfun (nullptr),
+        m_jacspfun (nullptr), m_jacdcell (nullptr), m_jacspcell (nullptr),
         m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr)
     { }
 
@@ -177,8 +179,8 @@
       : m_t0 (t), m_y0 (y), m_yp0 (yp), m_havejac (false), m_havejacfun (false),
         m_havejacsparse (false), m_mem (nullptr), m_num (), m_ida_fun (ida_fcn),
         m_ida_jac (), m_dfdy (nullptr), m_dfdyp (nullptr), m_spdfdy (nullptr),
-        m_spdfdyp (nullptr), m_fun (daefun), m_jacfun (nullptr), m_jacspfun (nullptr),
-        m_jacdcell (nullptr), m_jacspcell (nullptr),
+        m_spdfdyp (nullptr), m_fun (daefun), m_jacfun (nullptr),
+        m_jacspfun (nullptr), m_jacdcell (nullptr), m_jacspcell (nullptr),
         m_sunJacMatrix (nullptr), m_sunLinearSolver (nullptr)
     { }
 
@@ -245,9 +247,9 @@
 
     void initialize (void);
 
-    static ColumnVector NVecToCol (N_Vector& v, long int n);
+    static ColumnVector NVecToCol (N_Vector& v, octave_f77_int_type n);
 
-    static N_Vector ColToNVec (const ColumnVector& data, long int n);
+    static N_Vector ColToNVec (const ColumnVector& data, octave_f77_int_type n);
 
     void
     set_up (const ColumnVector& y);
@@ -266,9 +268,9 @@
     resfun_impl (realtype t, N_Vector& yy,
                  N_Vector& yyp, N_Vector& rr);
     static int
-    jacdense (realtype t, realtype cj, N_Vector yy,
-              N_Vector yyp, N_Vector, SUNMatrix JJ, void *user_data,
-              N_Vector, N_Vector, N_Vector)
+    jacdense (realtype t, realtype cj, N_Vector yy, N_Vector yyp,
+              N_Vector, SUNMatrix JJ, void *user_data, N_Vector,
+              N_Vector, N_Vector)
     {
       IDA *self = static_cast <IDA *> (user_data);
       self->jacdense_impl (t, cj, yy, yyp, JJ);
@@ -291,8 +293,8 @@
     }
 
     void
-    jacsparse_impl (realtype t, realtype cj, N_Vector& yy,
-                    N_Vector& yyp, SUNMatrix& Jac);
+    jacsparse_impl (realtype t, realtype cj,
+                    N_Vector& yy, N_Vector& yyp, SUNMatrix& Jac);
 #  endif
 
     void set_maxstep (realtype maxstep);
@@ -300,14 +302,15 @@
     void set_initialstep (realtype initialstep);
 
     bool
-    interpolate (int& cont, Matrix& output, ColumnVector& tout,
+    interpolate (octave_idx_type& cont, Matrix& output, ColumnVector& tout,
                  int refine, realtype tend, bool haveoutputfcn,
                  bool haveoutputsel, const octave_value& output_fcn,
                  ColumnVector& outputsel, bool haveeventfunction,
                  const octave_value& event_fcn, ColumnVector& te,
                  Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
                  ColumnVector& oldisterminal, ColumnVector& olddir,
-                 int& temp, ColumnVector& yold);
+                 octave_idx_type& temp, ColumnVector& yold,
+                 const octave_idx_type num_event_args);
 
     bool
     outputfun (const octave_value& output_fcn, bool haveoutputsel,
@@ -321,17 +324,20 @@
            realtype tsol, const ColumnVector& y, const std::string& flag,
            const ColumnVector& yp, ColumnVector& oldval,
            ColumnVector& oldisterminal, ColumnVector& olddir,
-           int cont, int& temp, realtype told, ColumnVector& yold);
+           octave_idx_type cont, octave_idx_type& temp, realtype told,
+           ColumnVector& yold,
+           const octave_idx_type num_event_args);
 
     void set_maxorder (int maxorder);
 
     octave_value_list
-    integrate (const int numt, const ColumnVector& tt,
+    integrate (const octave_idx_type numt, const ColumnVector& tt,
                const ColumnVector& y0, const ColumnVector& yp0,
                const int refine, bool haverefine, bool haveoutputfcn,
                const octave_value& output_fcn, bool haveoutputsel,
                ColumnVector& outputsel, bool haveeventfunction,
-               const octave_value& event_fcn);
+               const octave_value& event_fcn,
+               const octave_idx_type num_event_args);
 
     void print_stat (void);
 
@@ -344,7 +350,7 @@
     bool m_havejacfun;
     bool m_havejacsparse;
     void *m_mem;
-    int m_num;
+    octave_f77_int_type m_num;
     octave_value m_ida_fun;
     octave_value m_ida_jac;
     Matrix *m_dfdy;
@@ -388,15 +394,23 @@
   void
   IDA::set_up (const ColumnVector& y)
   {
-    N_Vector yy = ColToNVec(y, m_num);
+    N_Vector yy = ColToNVec (y, m_num);
 
     if (m_havejacsparse)
       {
 #  if defined (HAVE_SUNDIALS_SUNLINSOL_KLU)
-        // FIXME : one should not allocate space for a full Jacobian
-        // when using a sparse format.  Consider allocating less space
-        // then possibly using SUNSparseMatrixReallocate to increase it.
-        m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, m_num*m_num, CSC_MAT);
+#    if defined (HAVE_SUNSPARSEMATRIX_REALLOCATE)
+        // Initially allocate memory for 0 entries. We will reallocate when we
+        // get the Jacobian matrix from the user and know the actual number of
+        // entries.
+        m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, 0, CSC_MAT);
+#    else
+        octave_f77_int_type max_elems;
+        if (math::int_multiply_overflow (m_num, m_num, &max_elems))
+          error ("Unable to allocate memory for sparse Jacobian");
+
+        m_sunJacMatrix = SUNSparseMatrix (m_num, m_num, max_elems, CSC_MAT);
+#    endif
         if (! m_sunJacMatrix)
           error ("Unable to create sparse Jacobian for Sundials");
 
@@ -410,7 +424,9 @@
         IDASetJacFn (m_mem, IDA::jacsparse);
 
 #  else
-        error ("SUNDIALS SUNLINSOL KLU is not available in this version of Octave");
+        error ("SUNDIALS SUNLINSOL KLU was unavailable or disabled when "
+               "Octave was built");
+
 #  endif
 
       }
@@ -439,7 +455,7 @@
                       N_Vector& yy, N_Vector& yyp, SUNMatrix& JJ)
 
   {
-    long int Neq = NV_LENGTH_S(yy);
+    octave_f77_int_type Neq = NV_LENGTH_S (yy);
 
     ColumnVector y = NVecToCol (yy, Neq);
 
@@ -452,8 +468,9 @@
     else
       jac = (*m_jacdcell) (m_dfdy, m_dfdyp, cj);
 
+    octave_f77_int_type num_jac = to_f77_int (jac.numel ());
     std::copy (jac.fortran_vec (),
-               jac.fortran_vec () + jac.numel (),
+               jac.fortran_vec () + num_jac,
                SUNDenseMatrix_Data (JJ));
   }
 
@@ -474,42 +491,56 @@
     else
       jac = (*m_jacspcell) (m_spdfdy, m_spdfdyp, cj);
 
+#     if defined (HAVE_SUNSPARSEMATRIX_REALLOCATE)
+    octave_f77_int_type nnz = to_f77_int (jac.nnz ());
+    if (nnz > SUNSparseMatrix_NNZ (Jac))
+      {
+        // Allocate memory for sparse Jacobian defined in user function.
+        // This will always be required at least once since we set the number
+        // of non-zero elements to zero initially.
+        if (SUNSparseMatrix_Reallocate (Jac, nnz))
+          error ("Unable to allocate sufficient memory for IDA sparse matrix");
+      }
+#     endif
+
     SUNMatZero_Sparse (Jac);
+    // We have to use "sunindextype *" here but still need to check that
+    // conversion of each element to "octave_f77_int_type" is save.
     sunindextype *colptrs = SUNSparseMatrix_IndexPointers (Jac);
     sunindextype *rowvals = SUNSparseMatrix_IndexValues (Jac);
 
-    for (int i = 0; i < m_num + 1; i++)
-      colptrs[i] = jac.cidx(i);
+    for (octave_f77_int_type i = 0; i < m_num + 1; i++)
+      colptrs[i] = to_f77_int (jac.cidx (i));
 
     double *d = SUNSparseMatrix_Data (Jac);
-    for (int i = 0; i < jac.nnz (); i++)
+    for (octave_f77_int_type i = 0; i < to_f77_int (jac.nnz ()); i++)
       {
-        rowvals[i] = jac.ridx(i);
-        d[i] = jac.data(i);
+        rowvals[i] = to_f77_int (jac.ridx (i));
+        d[i] = jac.data (i);
       }
   }
 #  endif
 
   ColumnVector
-  IDA::NVecToCol (N_Vector& v, long int n)
+  IDA::NVecToCol (N_Vector& v, octave_f77_int_type n)
   {
     ColumnVector data (n);
     realtype *punt = nv_data_s (v);
 
-    for (octave_idx_type i = 0; i < n; i++)
+    for (octave_f77_int_type i = 0; i < n; i++)
       data(i) = punt[i];
 
     return data;
   }
 
   N_Vector
-  IDA::ColToNVec (const ColumnVector& data, long int n)
+  IDA::ColToNVec (const ColumnVector& data, octave_f77_int_type n)
   {
     N_Vector v = N_VNew_Serial (n);
 
     realtype *punt = nv_data_s (v);
 
-    for (octave_idx_type i = 0; i < n; i++)
+    for (octave_f77_int_type i = 0; i < n; i++)
       punt[i] = data(i);
 
     return v;
@@ -527,7 +558,7 @@
   void
   IDA::initialize (void)
   {
-    m_num = m_y0.numel ();
+    m_num = to_f77_int (m_y0.numel ());
     m_mem = IDACreate ();
 
     N_Vector yy = ColToNVec (m_y0, m_num);
@@ -559,18 +590,19 @@
   }
 
   octave_value_list
-  IDA::integrate (const int numt, const ColumnVector& tspan,
+  IDA::integrate (const octave_idx_type numt, const ColumnVector& tspan,
                   const ColumnVector& y, const ColumnVector& yp,
                   const int refine, bool haverefine, bool haveoutputfcn,
                   const octave_value& output_fcn, bool haveoutputsel,
                   ColumnVector& outputsel, bool haveeventfunction,
-                  const octave_value& event_fcn)
+                  const octave_value& event_fcn,
+                  const octave_idx_type num_event_args)
   {
     // Set up output
     ColumnVector tout, yout (m_num), ypout (m_num), ysel (outputsel.numel ());
     ColumnVector ie, te, oldval, oldisterminal, olddir;
     Matrix output, ye;
-    int cont = 0, temp = 0;
+    octave_idx_type cont = 0, temp = 0;
     bool status = 0;
     std::string string = "";
     ColumnVector yold = y;
@@ -591,7 +623,7 @@
     if (haveeventfunction)
       status = IDA::event (event_fcn, te, ye, ie, tsol, y,
                            "init", yp, oldval, oldisterminal,
-                           olddir, cont, temp, tsol, yold);
+                           olddir, cont, temp, tsol, yold, num_event_args);
 
     if (numt > 2)
       {
@@ -625,7 +657,8 @@
             if (haveeventfunction)
               status = IDA::event (event_fcn, te, ye, ie, tout(j), yout,
                                    string, ypout, oldval, oldisterminal,
-                                   olddir, j, temp, tout(j-1), yold);
+                                   olddir, j, temp, tout(j-1), yold,
+                                   num_event_args);
 
             // If integration is stopped, return only the reached steps
             if (status == 1)
@@ -662,7 +695,8 @@
                                          output_fcn, outputsel,
                                          haveeventfunction, event_fcn, te,
                                          ye, ie, oldval, oldisterminal,
-                                         olddir, temp, yold);
+                                         olddir, temp, yold,
+                                         num_event_args);
 
             ypout = NVecToCol (yyp, m_num);
             cont += 1;
@@ -681,7 +715,8 @@
             if (haveeventfunction && ! haverefine && tout(cont) < tend)
               status = IDA::event (event_fcn, te, ye, ie, tout(cont), yout,
                                    string, ypout, oldval, oldisterminal,
-                                   olddir, cont, temp, tout(cont-1), yold);
+                                   olddir, cont, temp, tout(cont-1), yold,
+                                   num_event_args);
           }
 
         if (status == 0)
@@ -709,7 +744,7 @@
                   status = IDA::event (event_fcn, te, ye, ie, tend, yout,
                                        string, ypout, oldval, oldisterminal,
                                        olddir, cont, temp, tout(cont-1),
-                                       yold);
+                                       yold, num_event_args);
               }
 
             N_VDestroy_Serial (dky);
@@ -721,20 +756,27 @@
 
       }
 
-    return ovl (tout, output, te, ye, ie);
+    // Index of Events (ie) variable must use 1-based indexing
+    return ovl (tout, output, te, ye, ie + 1.0);
   }
 
   bool
   IDA::event (const octave_value& event_fcn,
-              ColumnVector& te, Matrix& ye, ColumnVector& ie,
-              realtype tsol, const ColumnVector& y, const std::string& flag,
+              ColumnVector& te, Matrix& ye, ColumnVector& ie, realtype tsol,
+              const ColumnVector& y, const std::string& flag,
               const ColumnVector& yp, ColumnVector& oldval,
-              ColumnVector& oldisterminal, ColumnVector& olddir, int cont,
-              int& temp, realtype told, ColumnVector& yold)
+              ColumnVector& oldisterminal, ColumnVector& olddir,
+              octave_idx_type cont, octave_idx_type& temp, realtype told,
+              ColumnVector& yold,
+              const octave_idx_type num_event_args)
   {
     bool status = 0;
 
-    octave_value_list args = ovl (tsol, y, yp);
+    octave_value_list args;
+    if (num_event_args == 2)
+      args = ovl (tsol, y);
+    else
+      args = ovl (tsol, y, yp);
 
     // cont is the number of steps reached by the solver
     // temp is the number of events registered
@@ -757,8 +799,14 @@
         // Get the index of the changed values
         for (octave_idx_type i = 0; i < val.numel (); i++)
           {
-            if ((val(i) > 0 && oldval(i) < 0 && dir(i) != -1) // increasing
-                || (val(i) < 0 && oldval(i) > 0 && dir(i) != 1)) // decreasing
+            // Check for sign change and whether a rising / falling edge
+            // either passes through zero or detaches from zero (bug #59063)
+            if ((dir(i) != -1
+                 && ((val(i) >= 0 && oldval(i) < 0)
+                     || (val(i) > 0 && oldval(i) <= 0))) // increasing
+                || (dir(i) != 1
+                    && ((val(i) <= 0 && oldval(i) > 0)
+                        || (val(i) < 0 && oldval(i) >= 0)))) // decreasing
               {
                 index.resize (index.numel () + 1);
                 index (index.numel () - 1) = i;
@@ -825,14 +873,15 @@
   }
 
   bool
-  IDA::interpolate (int& cont, Matrix& output, ColumnVector& tout,
+  IDA::interpolate (octave_idx_type& cont, Matrix& output, ColumnVector& tout,
                     int refine, realtype tend, bool haveoutputfcn,
                     bool haveoutputsel, const octave_value& output_fcn,
                     ColumnVector& outputsel, bool haveeventfunction,
                     const octave_value& event_fcn, ColumnVector& te,
                     Matrix& ye, ColumnVector& ie, ColumnVector& oldval,
                     ColumnVector& oldisterminal, ColumnVector& olddir,
-                    int& temp, ColumnVector& yold)
+                    octave_idx_type& temp, ColumnVector& yold,
+                    const octave_idx_type num_event_args)
   {
     realtype h = 0, tcur = 0;
     bool status = 0;
@@ -884,7 +933,7 @@
           status = IDA::event (event_fcn, te, ye, ie, tout(cont),
                                yout, string, ypout, oldval,
                                oldisterminal, olddir, cont, temp,
-                               tout(cont-1), yold);
+                               tout(cont-1), yold, num_event_args);
       }
 
     N_VDestroy_Serial (dky);
@@ -916,7 +965,7 @@
 
     if (flag == "init")
       {
-        ColumnVector toutput(2);
+        ColumnVector toutput (2);
         toutput(0) = tsol;
         toutput(1) = tend;
         output(0) = toutput;
@@ -992,9 +1041,9 @@
       {
         tmp = feval (ida_fc, ovl (t, x, xdot), 1);
       }
-    catch (execution_exception& e)
+    catch (execution_exception& ee)
       {
-        err_user_supplied_eval (e, "__ode15__");
+        err_user_supplied_eval (ee, "__ode15__");
       }
 
     return tmp(0).vector_value ();
@@ -1010,9 +1059,9 @@
       {
         tmp = feval (ida_jc, ovl (t, x, xdot), 2);
       }
-    catch (execution_exception& e)
+    catch (execution_exception& ee)
       {
-        err_user_supplied_eval (e, "__ode15__");
+        err_user_supplied_eval (ee, "__ode15__");
       }
 
     return tmp(0).matrix_value () + cj * tmp(1).matrix_value ();
@@ -1028,9 +1077,9 @@
       {
         tmp = feval (ida_jc, ovl (t, x, xdot), 2);
       }
-    catch (execution_exception& e)
+    catch (execution_exception& ee)
       {
-        err_user_supplied_eval (e, "__ode15__");
+        err_user_supplied_eval (ee, "__ode15__");
       }
 
     return tmp(0).sparse_matrix_value () + cj * tmp(1).sparse_matrix_value ();
@@ -1052,11 +1101,12 @@
   octave_value_list
   do_ode15 (const octave_value& ida_fcn,
             const ColumnVector& tspan,
-            const int numt,
+            const octave_idx_type numt,
             const realtype t0,
             const ColumnVector& y0,
             const ColumnVector& yp0,
-            const octave_scalar_map& options)
+            const octave_scalar_map& options,
+            const octave_idx_type num_event_args)
   {
     octave_value_list retval;
 
@@ -1110,43 +1160,43 @@
     dae.initialize ();
 
     // Set tolerances
-    realtype rel_tol = options.getfield("RelTol").double_value ();
+    realtype rel_tol = options.getfield ("RelTol").double_value ();
 
     bool haveabstolvec = options.getfield ("haveabstolvec").bool_value ();
 
     if (haveabstolvec)
       {
-        ColumnVector abs_tol = options.getfield("AbsTol").vector_value ();
+        ColumnVector abs_tol = options.getfield ("AbsTol").vector_value ();
 
         dae.set_tolerance (abs_tol, rel_tol);
       }
     else
       {
-        realtype abs_tol = options.getfield("AbsTol").double_value ();
+        realtype abs_tol = options.getfield ("AbsTol").double_value ();
 
         dae.set_tolerance (abs_tol, rel_tol);
       }
 
     //Set max step
-    realtype maxstep = options.getfield("MaxStep").double_value ();
+    realtype maxstep = options.getfield ("MaxStep").double_value ();
 
     dae.set_maxstep (maxstep);
 
     //Set initial step
-    if (! options.getfield("InitialStep").isempty ())
+    if (! options.getfield ("InitialStep").isempty ())
       {
-        realtype initialstep = options.getfield("InitialStep").double_value ();
+        realtype initialstep = options.getfield ("InitialStep").double_value ();
 
         dae.set_initialstep (initialstep);
       }
 
     //Set max order FIXME: it doesn't work
-    int maxorder = options.getfield("MaxOrder").int_value ();
+    int maxorder = options.getfield ("MaxOrder").int_value ();
 
     dae.set_maxorder (maxorder);
 
     //Set Refine
-    const int refine = options.getfield("Refine").int_value ();
+    const int refine = options.getfield ("Refine").int_value ();
 
     bool haverefine = (refine > 1);
 
@@ -1155,25 +1205,25 @@
 
     // OutputFcn
     bool haveoutputfunction
-      = options.getfield("haveoutputfunction").bool_value ();
+      = options.getfield ("haveoutputfunction").bool_value ();
 
     if (haveoutputfunction)
-      output_fcn = options.getfield("OutputFcn");
+      output_fcn = options.getfield ("OutputFcn");
 
     // OutputSel
-    bool haveoutputsel = options.getfield("haveoutputselection").bool_value ();
+    bool haveoutputsel = options.getfield ("haveoutputselection").bool_value ();
 
     if (haveoutputsel)
-      outputsel = options.getfield("OutputSel").vector_value ();
+      outputsel = options.getfield ("OutputSel").vector_value ();
 
     octave_value event_fcn;
 
     // Events
     bool haveeventfunction
-      = options.getfield("haveeventfunction").bool_value ();
+      = options.getfield ("haveeventfunction").bool_value ();
 
     if (haveeventfunction)
-      event_fcn = options.getfield("Events");
+      event_fcn = options.getfield ("Events");
 
     // Set up linear solver
     dae.set_up (y0);
@@ -1182,10 +1232,10 @@
     retval = dae.integrate (numt, tspan, y0, yp0, refine,
                             haverefine, haveoutputfunction,
                             output_fcn, haveoutputsel, outputsel,
-                            haveeventfunction, event_fcn);
+                            haveeventfunction, event_fcn, num_event_args);
 
     // Statistics
-    bool havestats = options.getfield("havestats").bool_value ();
+    bool havestats = options.getfield ("havestats").bool_value ();
 
     if (havestats)
       dae.print_stat ();
@@ -1198,7 +1248,7 @@
 
 DEFUN_DLD (__ode15__, args, ,
            doc: /* -*- texinfo -*-
-@deftypefn {} {@var{t}, @var{y} =} __ode15__ (@var{fun}, @var{tspan}, @var{y0}, @var{yp0}, @var{options})
+@deftypefn {} {@var{t}, @var{y} =} __ode15__ (@var{fun}, @var{tspan}, @var{y0}, @var{yp0}, @var{options}, @var{num_event_args})
 Undocumented internal function.
 @end deftypefn */)
 {
@@ -1206,9 +1256,7 @@
 #if defined (HAVE_SUNDIALS)
 
   // Check number of parameters
-  int nargin = args.length ();
-
-  if (nargin != 5)
+  if (args.length () != 6)
     print_usage ();
 
   // Check odefun
@@ -1221,7 +1269,7 @@
   ColumnVector tspan
     = args(1).xvector_value ("__ode15__: TRANGE must be a vector of numbers");
 
-  int numt = tspan.numel ();
+  octave_idx_type numt = tspan.numel ();
 
   realtype t0 = tspan (0);
 
@@ -1250,9 +1298,15 @@
   octave_scalar_map options
     = args(4).xscalar_map_value ("__ode15__: OPTS argument must be a scalar structure");
 
+  // Provided number of arguments in the ode callback function
+  octave_idx_type num_event_args
+    = args(5).xidx_type_value ("__ode15__: NUM_EVENT_ARGS must be an integer");
 
-  return octave::do_ode15 (ida_fcn, tspan, numt, t0, y0, yp0, options);
+  if (num_event_args != 2 && num_event_args != 3)
+    error ("__ode15__: number of input arguments in event callback must be 2 or 3");
 
+  return octave::do_ode15 (ida_fcn, tspan, numt, t0, y0, yp0, options,
+                           num_event_args);
 
 #else
 
--- a/libinterp/dldfcn/__voronoi__.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/__voronoi__.cc	Sun May 16 09:44:35 2021 +0200
@@ -60,23 +60,17 @@
 
 #  include "oct-qhull.h"
 
-#  if defined (NEED_QHULL_VERSION)
+#  if defined (NEED_QHULL_R_VERSION)
 char qh_version[] = "__voronoi__.oct 2007-07-24";
 #  endif
 
 static void
-close_fcn (FILE *f)
+free_qhull_memory (qhT *qh)
 {
-  std::fclose (f);
-}
-
-static void
-free_qhull_memory ()
-{
-  qh_freeqhull (! qh_ALL);
+  qh_freeqhull (qh, ! qh_ALL);
 
   int curlong, totlong;
-  qh_memfreeshort (&curlong, &totlong);
+  qh_memfreeshort (qh, &curlong, &totlong);
 
   if (curlong || totlong)
     warning ("__voronoi__: did not free %d bytes of long memory (%d pieces)",
@@ -158,50 +152,36 @@
 
   boolT ismalloc = false;
 
-  octave::unwind_protect frame;
-
-  // Replace the outfile pointer with stdout for debugging information.
-#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)
-  FILE *outfile = std::fopen ("NUL", "w");
-#else
-  FILE *outfile = std::fopen ("/dev/null", "w");
-#endif
+  // Set the outfile pointer to stdout for status information.
+  FILE *outfile = nullptr;
   FILE *errfile = stderr;
 
-  if (! outfile)
-    error ("__voronoi__: unable to create temporary file for output");
-
-  frame.add_fcn (close_fcn, outfile);
-
-  // qh_new_qhull command and points arguments are not const...
+  qhT context = { };
+  qhT *qh = &context;
 
   std::string cmd = "qhull v" + options;
 
-  OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1);
-
-  strcpy (cmd_str, cmd.c_str ());
+  int exitcode = qh_new_qhull (qh, dim, num_points, points.fortran_vec (),
+                               ismalloc, &cmd[0], outfile, errfile);
 
-  int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (),
-                               ismalloc, cmd_str, outfile, errfile);
-
-  frame.add_fcn (free_qhull_memory);
+  octave::unwind_action free_memory ([qh] () { free_qhull_memory (qh); });
 
   if (exitcode)
     error ("%s: qhull failed", caller.c_str ());
 
   // Calling findgood_all provides the number of Voronoi vertices
-  // (sets qh num_good).
+  // (sets qh->num_good).
 
-  qh_findgood_all (qh facet_list);
+  qh_findgood_all (qh, qh->facet_list);
 
   octave_idx_type num_voronoi_regions
-    = qh num_vertices - qh_setsize (qh del_vertices);
+    = qh->num_vertices - qh_setsize (qh, qh->del_vertices);
 
-  octave_idx_type num_voronoi_vertices = qh num_good;
+  octave_idx_type num_voronoi_vertices = qh->num_good;
 
   // Find the voronoi centers for all facets.
 
-  qh_setvoronoi_all ();
+  qh_setvoronoi_all (qh);
 
   facetT *facet;
   vertexT *vertex;
@@ -224,8 +204,8 @@
 
   FORALLvertices
     {
-      if (qh hull_dim == 3)
-        qh_order_vertexneighbors (vertex);
+      if (qh->hull_dim == 3)
+        qh_order_vertexneighbors (qh, vertex);
 
       bool infinity_seen = false;
 
@@ -289,12 +269,12 @@
 
   FORALLvertices
     {
-      if (qh hull_dim == 3)
-        qh_order_vertexneighbors (vertex);
+      if (qh->hull_dim == 3)
+        qh_order_vertexneighbors (qh, vertex);
 
       bool infinity_seen = false;
 
-      octave_idx_type idx = qh_pointid (vertex->point);
+      octave_idx_type idx = qh_pointid (qh, vertex->point);
 
       octave_idx_type num_vertices = ni[k++];
 
--- a/libinterp/dldfcn/audiodevinfo.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/audiodevinfo.cc	Sun May 16 09:44:35 2021 +0200
@@ -304,7 +304,7 @@
       std::string arg3 = args(2).string_value ();
       std::transform (arg3.begin (), arg3.end (), arg3.begin (), tolower);
       if (arg3 != "driverversion")
-        error ("audiodevinfo: third argument must be \"DriverVersion\"");
+        error (R"(audiodevinfo: third argument must be "DriverVersion")");
 
       if (outin == 0)
         {
@@ -489,7 +489,7 @@
 %!   assert (devinfo.output(i).Name, audiodevinfo (0, devinfo.output(i).ID));
 %! endfor
 %! for i=1:nin
-%!   assert (devinfo.input(i).Name, audiodevinfo (1, devinfo.input(i).ID));
+%!   assert (devinfo.input (i).Name, audiodevinfo (1, devinfo.input (i).ID));
 %! endfor
 
 %!testif HAVE_PORTAUDIO
@@ -500,7 +500,7 @@
 %!   assert (devinfo.output(i).ID, audiodevinfo (0, devinfo.output(i).Name));
 %! endfor
 %! for i = 1:nin
-%!   assert (devinfo.input(i).ID, audiodevinfo (1, devinfo.input(i).Name));
+%!   assert (devinfo.input (i).ID, audiodevinfo (1, devinfo.input (i).Name));
 %! endfor
 */
 
@@ -592,21 +592,21 @@
   audioplayer *player = static_cast<audioplayer *> (data);
 
   if (! player)
-    error ("audio player callback function called without player");
+    error ("audioplayer callback function called without player");
 
   octave_value_list retval
     = octave::feval (player->octave_callback_function,
                      ovl (static_cast<double> (frames)), 1);
 
   if (retval.length () < 2)
-    error ("audio player callback function failed");
+    error ("audioplayer callback function failed");
 
   const Matrix sound = retval(0).matrix_value ();
   int return_status = retval(1).int_value ();
 
   if (frames - sound.rows () != 0 || sound.columns () < 1
       || sound.columns () > 2)
-    error ("audio player callback function failed");
+    error ("audioplayer callback function failed");
 
   // Don't multiply the audio data by scale_factor here.  Although it
   // does move the operation outside of the loops below, it also causes
@@ -682,7 +682,7 @@
       break;
 
     default:
-      error ("invalid player bit depth in callback function");
+      error ("invalid bit depth in audioplayer callback function");
     }
 
   return return_status;
@@ -696,7 +696,7 @@
   audioplayer *player = static_cast<audioplayer *> (data);
 
   if (! player)
-    error ("audio player callback function called without player");
+    error ("audioplayer callback function called without player");
 
   // Don't multiply the audio data by scale_factor here.  Although it would
   // move the operation outside of the loops below, it also causes a second
@@ -799,7 +799,7 @@
           break;
 
         default:
-          error ("invalid player bit depth in callback function");
+          error ("invalid bit depth in audioplayer callback function");
         }
     }
   else if (player->get_type () == TYPE_INT8)
@@ -863,12 +863,6 @@
   return paContinue;
 }
 
-static void
-safe_audioplayer_stop (audioplayer *player)
-{
-  player->stop ();
-}
-
 audioplayer::audioplayer (void)
   : octave_callback_function (nullptr),
     id (-1), fs (0), nbits (16), channels (0), sample_number (0),
@@ -1156,9 +1150,7 @@
   start = get_sample_number ();
   end = get_end_sample ();
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_audioplayer_stop, this);
+  octave::unwind_action stop_audioplayer ([=] () { stop (); });
 
   for (unsigned int i = start; i < end; i += buffer_size)
     {
@@ -1349,7 +1341,7 @@
   audiorecorder *recorder = static_cast<audiorecorder *> (data);
 
   if (! recorder)
-    error ("audio recorder callback function called without recorder");
+    error ("audiorecorder callback function called without recorder");
 
   int channels = recorder->get_channels ();
 
@@ -1453,7 +1445,7 @@
   audiorecorder *recorder = static_cast<audiorecorder *> (data);
 
   if (! recorder)
-    error ("audio recorder callback function called without recorder");
+    error ("audiorecorder callback function called without recorder");
 
   int channels = recorder->get_channels ();
 
@@ -1543,12 +1535,6 @@
   return paContinue;
 }
 
-static void
-safe_audiorecorder_stop (audiorecorder *recorder)
-{
-  recorder->stop ();
-}
-
 audiorecorder::audiorecorder (void)
   : octave_callback_function (nullptr),
     id (-1), fs (8000), nbits (8), channels (1), sample_number (0),
@@ -1836,9 +1822,7 @@
 
   unsigned int frames = seconds * get_fs ();
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_audiorecorder_stop, this);
+  octave::unwind_action stop_audiorecorder ([=] () { stop (); });
 
   for (unsigned int i = 0; i < frames; i += buffer_size)
     {
@@ -2429,7 +2413,7 @@
 
   audioplayer *pl = dynamic_cast<audioplayer *> (ncrep);
   if (! pl)
-    error ("audiodevinfo.cc get_player: dynamic_cast to audioplayer failed");
+    error ("audiodevinfo.cc (get_player): dynamic_cast to audioplayer failed");
 
   return pl;
 }
--- a/libinterp/dldfcn/audioread.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/audioread.cc	Sun May 16 09:44:35 2021 +0200
@@ -49,14 +49,6 @@
 #  include <sndfile.h>
 #endif
 
-#if defined (HAVE_SNDFILE)
-static void
-safe_close (SNDFILE *file)
-{
-  sf_close (file);
-}
-#endif
-
 DEFUN_DLD (audioread, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {[@var{y}, @var{fs}] =} audioread (@var{filename})
@@ -96,9 +88,7 @@
     error ("audioread: failed to open input file '%s': %s",
            filename.c_str (), sf_strerror (file));
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_close, file);
+  octave::unwind_action close_open_file ([=] () { sf_close (file); });
 
   OCTAVE_LOCAL_BUFFER (double, data, info.frames * info.channels);
 
@@ -431,9 +421,7 @@
     error ("audiowrite: failed to open output file '%s': %s",
            filename.c_str (), sf_strerror (file));
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_close, file);
+  octave::unwind_action close_open_file ([=] () { sf_close (file); });
 
   sf_command (file, SFC_SET_NORM_DOUBLE, nullptr, SF_TRUE);
   sf_command (file, SFC_SET_CLIPPING, nullptr, SF_TRUE) ;
@@ -626,9 +614,7 @@
     error ("audioinfo: failed to open input file '%s': %s",
            filename.c_str (), sf_strerror (file));
 
-  octave::unwind_protect frame;
-
-  frame.add_fcn (safe_close, file);
+  octave::unwind_action close_open_file ([=] () { sf_close (file); });
 
   octave_scalar_map result;
 
--- a/libinterp/dldfcn/convhulln.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/convhulln.cc	Sun May 16 09:44:35 2021 +0200
@@ -53,23 +53,17 @@
 
 #  include "oct-qhull.h"
 
-#  if defined (NEED_QHULL_VERSION)
+#  if defined (NEED_QHULL_R_VERSION)
 char qh_version[] = "convhulln.oct 2007-07-24";
 #  endif
 
 static void
-close_fcn (FILE *f)
+free_qhull_memory (qhT *qh)
 {
-  std::fclose (f);
-}
-
-static void
-free_qhull_memory ()
-{
-  qh_freeqhull (! qh_ALL);
+  qh_freeqhull (qh, ! qh_ALL);
 
   int curlong, totlong;
-  qh_memfreeshort (&curlong, &totlong);
+  qh_memfreeshort (qh, &curlong, &totlong);
 
   if (curlong || totlong)
     warning ("convhulln: did not free %d bytes of long memory (%d pieces)",
@@ -173,40 +167,26 @@
 
   boolT ismalloc = false;
 
-  octave::unwind_protect frame;
-
-  // Replace the outfile pointer with stdout for debugging information.
-#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)
-  FILE *outfile = std::fopen ("NUL", "w");
-#else
-  FILE *outfile = std::fopen ("/dev/null", "w");
-#endif
+  // Set the outfile pointer to stdout for status information.
+  FILE *outfile = nullptr;
   FILE *errfile = stderr;
 
-  if (! outfile)
-    error ("convhulln: unable to create temporary file for output");
-
-  frame.add_fcn (close_fcn, outfile);
-
-  // qh_new_qhull command and points arguments are not const...
+  qhT context = { };
+  qhT *qh = &context;
 
   std::string cmd = "qhull" + options;
 
-  OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1);
-
-  strcpy (cmd_str, cmd.c_str ());
-
-  int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (),
-                               ismalloc, cmd_str, outfile, errfile);
-
-  frame.add_fcn (free_qhull_memory);
+  int exitcode = qh_new_qhull (qh, dim, num_points, points.fortran_vec (),
+                               ismalloc, &cmd[0], outfile, errfile);
+ 
+  octave::unwind_action free_memory ([qh] () { free_qhull_memory (qh); });
 
   if (exitcode)
     error ("convhulln: qhull failed");
 
   bool nonsimp_seen = false;
 
-  octave_idx_type nf = qh num_facets;
+  octave_idx_type nf = qh->num_facets;
 
   Matrix idx (nf, dim + 1);
 
@@ -218,7 +198,7 @@
     {
       octave_idx_type j = 0;
 
-      if (! (nonsimp_seen || facet->simplicial || qh hull_dim == 2))
+      if (! (nonsimp_seen || facet->simplicial || qh->hull_dim == 2))
         {
           nonsimp_seen = true;
 
@@ -229,14 +209,14 @@
 
       if (dim == 3)
         {
-          setT *vertices = qh_facet3vertex (facet);
+          setT *vertices = qh_facet3vertex (qh, facet);
 
           vertexT *vertex, **vertexp;
 
           FOREACHvertex_ (vertices)
-            idx(i, j++) = 1 + qh_pointid(vertex->point);
+            idx(i, j++) = 1 + qh_pointid(qh, vertex->point);
 
-          qh_settempfree (&vertices);
+          qh_settempfree (qh, &vertices);
         }
       else
         {
@@ -245,14 +225,14 @@
               vertexT *vertex, **vertexp;
 
               FOREACHvertex_ (facet->vertices)
-                idx(i, j++) = 1 + qh_pointid(vertex->point);
+                idx(i, j++) = 1 + qh_pointid(qh, vertex->point);
             }
           else
             {
               vertexT *vertex, **vertexp;
 
               FOREACHvertexreverse12_ (facet->vertices)
-                idx(i, j++) = 1 + qh_pointid(vertex->point);
+                idx(i, j++) = 1 + qh_pointid(qh, vertex->point);
             }
         }
       if (j < dim)
@@ -280,26 +260,26 @@
           if (! facet->normal)
             continue;
 
-          if (facet->upperdelaunay && qh ATinfinity)
+          if (facet->upperdelaunay && qh->ATinfinity)
             continue;
 
-          facet->f.area = area = qh_facetarea (facet);
+          facet->f.area = area = qh_facetarea (qh, facet);
           facet->isarea = True;
 
-          if (qh DELAUNAY)
+          if (qh->DELAUNAY)
             {
-              if (facet->upperdelaunay == qh UPPERdelaunay)
-                qh totarea += area;
+              if (facet->upperdelaunay == qh->UPPERdelaunay)
+                qh->totarea += area;
             }
           else
             {
-              qh totarea += area;
-              qh_distplane (qh interior_point, facet, &dist);
-              qh totvol += -dist * area/ qh hull_dim;
+              qh->totarea += area;
+              qh_distplane (qh, qh->interior_point, facet, &dist);
+              qh->totvol += -dist * area / qh->hull_dim;
             }
         }
 
-      retval(1) = octave_value (qh totvol);
+      retval(1) = octave_value (qh->totvol);
     }
 
   retval(0) = idx;
--- a/libinterp/dldfcn/gzip.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/gzip.cc	Sun May 16 09:44:35 2021 +0200
@@ -508,13 +508,17 @@
             {
               X::zip (path, dest_path);
             }
+          catch (const interrupt_exception&)
+            {
+              throw;  // interrupts are special, just re-throw.
+            }
           catch (...)
             {
               // Error "handling" is not including filename on the output list.
-              // Also remove created file which maybe was not even created
+              // Also, remove created file which may not have been created
               // in the first place.  Note that it is possible for the file
-              // to exist in the first place and for X::zip to not have
-              // clobber it yet but we remove it anyway by design.
+              // to exist before the call to X::zip and that X::zip has not
+              // clobber it yet, but we remove it anyway.
               sys::unlink (dest_path);
               return;
             }
@@ -703,7 +707,7 @@
 %!      test_function (test_dir, z)
 %!    unwind_protect_cleanup
 %!      confirm_recursive_rmdir (false, "local");
-%!      rmdir (test_dir, "s");
+%!      sts = rmdir (test_dir, "s");
 %!    end_unwind_protect
 %!  endfor
 %!endfunction
@@ -783,7 +787,7 @@
 %!function test_xzip_dir (test_dir, z) # bug #43431
 %!  fpaths = fullfile (test_dir, {"test1", "test2", "test3"});
 %!  md5s = cell (1, 3);
-%!  for idx = 1:numel(fpaths)
+%!  for idx = 1:numel (fpaths)
 %!    create_file (fpaths{idx}, rand (100, 1));
 %!    md5s(idx) = hash ("md5", fileread (fpaths{idx}));
 %!  endfor
@@ -793,7 +797,7 @@
 %!  z_files = strcat (fpaths, z.ext);
 %!  z_filelist = z.zip (test_dir);
 %!  assert (sort (z_filelist), z_files(:))
-%!  for idx = 1:numel(fpaths)
+%!  for idx = 1:numel (fpaths)
 %!    assert (exist (z_files{idx}), 2)
 %!    unlink_or_error (fpaths{idx});
 %!  endfor
@@ -803,12 +807,12 @@
 %!    uz_filelist = z.unzip (test_dir);
 %!  else
 %!    uz_filelist = cell (1, numel (z_filelist));
-%!    for idx = 1:numel(z_filelist)
+%!    for idx = 1:numel (z_filelist)
 %!      uz_filelist(idx) = z.unzip (z_filelist{idx});
 %!    endfor
 %!  endif
 %!  assert (sort (uz_filelist), fpaths(:)) # bug #48598
-%!  for idx = 1:numel(fpaths)
+%!  for idx = 1:numel (fpaths)
 %!    assert (hash ("md5", fileread (fpaths{idx})), md5s{idx})
 %!  endfor
 %!endfunction
@@ -826,7 +830,7 @@
 %!    error ("unable to create directory for test");
 %!  endif
 %!  unwind_protect
-%!    for idx = 1:numel(out_dirs)
+%!    for idx = 1:numel (out_dirs)
 %!      out_dir = out_dirs{idx};
 %!      uz_file = fullfile (out_dir, filename);
 %!      z_file = [uz_file z.ext];
@@ -842,8 +846,8 @@
 %!    endfor
 %!  unwind_protect_cleanup
 %!    confirm_recursive_rmdir (false, "local");
-%!    for idx = 1:numel(out_dirs)
-%!      rmdir (out_dirs{idx}, "s");
+%!    for idx = 1:numel (out_dirs)
+%!      sts = rmdir (out_dirs{idx}, "s");
 %!    endfor
 %!  end_unwind_protect
 %!endfunction
--- a/libinterp/dldfcn/oct-qhull.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/dldfcn/oct-qhull.h	Sun May 16 09:44:35 2021 +0200
@@ -32,32 +32,18 @@
 
 extern "C" {
 
-#if defined (HAVE_LIBQHULL_LIBQHULL_H)
-#  include <libqhull/libqhull.h>
-#  include <libqhull/qset.h>
-#  include <libqhull/geom.h>
-#  include <libqhull/poly.h>
-#  include <libqhull/io.h>
-#elif defined (HAVE_QHULL_LIBQHULL_H) || defined (HAVE_QHULL_QHULL_H)
-#  if defined (HAVE_QHULL_LIBQHULL_H)
-#    include <qhull/libqhull.h>
-#  else
-#    include <qhull/qhull.h>
-#  endif
-#  include <qhull/qset.h>
-#  include <qhull/geom.h>
-#  include <qhull/poly.h>
-#  include <qhull/io.h>
-#  elif defined (HAVE_LIBQHULL_H) || defined (HAVE_QHULL_H)
-#  if defined (HAVE_LIBQHULL_H)
-#    include <libqhull.h>
-#  else
-#    include <qhull.h>
-#  endif
-#  include <qset.h>
-#  include <geom.h>
-#  include <poly.h>
-#  include <io.h>
+#if defined (HAVE_LIBQHULL_R_LIBQHULL_R_H)
+#  include <libqhull_r/libqhull_r.h>
+#  include <libqhull_r/qset_r.h>
+#  include <libqhull_r/geom_r.h>
+#  include <libqhull_r/poly_r.h>
+#  include <libqhull_r/io_r.h>
+#elif defined (HAVE_LIBQHULL_R_H)
+#  include <libqhull_r.h>
+#  include <qset_r.h>
+#  include <geom_r.h>
+#  include <poly_r.h>
+#  include <io_r.h>
 #endif
 
 }
--- a/libinterp/liboctinterp-build-info.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/liboctinterp-build-info.h	Sun May 16 09:44:35 2021 +0200
@@ -32,6 +32,6 @@
 
 #include <string>
 
-extern OCTAVE_API std::string liboctinterp_hg_id (void);
+extern OCTINTERP_API std::string liboctinterp_hg_id (void);
 
 #endif
--- a/libinterp/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -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
@@ -151,7 +151,7 @@
 ## to the rules in the etc/HACKING.md file:
 
 %canon_reldir%_liboctinterp_current = 8
-%canon_reldir%_liboctinterp_revision = 1
+%canon_reldir%_liboctinterp_revision = 0
 %canon_reldir%_liboctinterp_age = 0
 
 %canon_reldir%_liboctinterp_version_info = $(%canon_reldir%_liboctinterp_current):$(%canon_reldir%_liboctinterp_revision):$(%canon_reldir%_liboctinterp_age)
--- a/libinterp/octave-value/cdef-class.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-class.cc	Sun May 16 09:44:35 2021 +0200
@@ -864,12 +864,10 @@
     // this, we may pick up stray values from the current scope when
     // evaluating expressions found in things like attribute lists.
 
-    unwind_protect frame;
-
     tree_evaluator& tw = interp.get_evaluator ();
 
     tw.push_dummy_scope (full_class_name);
-    frame.add_method (tw, &octave::tree_evaluator::pop_scope);
+    unwind_action pop_scope (&tree_evaluator::pop_scope, &tw);
 
     std::list<cdef_class> slist;
 
--- a/libinterp/octave-value/cdef-class.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-class.h	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
           meta (false)
       { }
 
-      cdef_class_rep (const std::list<cdef_class>& superclasses);
+      OCTINTERP_API cdef_class_rep (const std::list<cdef_class>& superclasses);
 
       cdef_class_rep& operator = (const cdef_class_rep&) = delete;
 
@@ -80,51 +80,57 @@
 
       bool is_sealed (void) const { return get ("Sealed").bool_value (); }
 
-      cdef_method find_method (const std::string& nm, bool local = false);
-
-      void install_method (const cdef_method& meth);
+      OCTINTERP_API cdef_method
+      find_method (const std::string& nm, bool local = false);
 
-      Cell get_methods (bool include_ctor);
+      OCTINTERP_API void
+      install_method (const cdef_method& meth);
 
-      std::map<std::string, cdef_method>
+      OCTINTERP_API Cell
+      get_methods (bool include_ctor);
+
+      OCTINTERP_API std::map<std::string, cdef_method>
       get_method_map (bool only_inherited, bool include_ctor);
 
-      cdef_property find_property (const std::string& nm);
+      OCTINTERP_API cdef_property find_property (const std::string& nm);
 
-      void install_property (const cdef_property& prop);
+      OCTINTERP_API void install_property (const cdef_property& prop);
 
-      Cell get_properties (int mode);
+      OCTINTERP_API Cell get_properties (int mode);
 
-      std::map<std::string, cdef_property> get_property_map (int mode);
+      OCTINTERP_API std::map<std::string, cdef_property>
+      get_property_map (int mode);
 
-      string_vector get_names (void);
+      OCTINTERP_API string_vector get_names (void);
 
       void set_directory (const std::string& dir) { directory = dir; }
 
       std::string get_directory (void) const { return directory; }
 
-      void delete_object (const cdef_object& obj);
+      OCTINTERP_API void delete_object (const cdef_object& obj);
 
-      octave_value_list
+      OCTINTERP_API octave_value_list
       meta_subsref (const std::string& type,
                     const std::list<octave_value_list>& idx, int nargout);
 
-      void meta_release (void);
+      OCTINTERP_API void meta_release (void);
 
       bool meta_accepts_postfix_index (char type) const
       {
         return (type == '(' || type == '.');
       }
 
-      octave_value get_method (const std::string& name) const;
+      OCTINTERP_API octave_value get_method (const std::string& name) const;
 
-      octave_value construct (const octave_value_list& args);
+      OCTINTERP_API octave_value construct (const octave_value_list& args);
 
-      cdef_object construct_object (const octave_value_list& args);
+      OCTINTERP_API cdef_object
+      construct_object (const octave_value_list& args);
 
-      void initialize_object (cdef_object& obj);
+      OCTINTERP_API void initialize_object (cdef_object& obj);
 
-      void run_constructor (cdef_object& obj, const octave_value_list& args);
+      OCTINTERP_API void
+      run_constructor (cdef_object& obj, const octave_value_list& args);
 
       void mark_as_handle_class (void) { handle_class = true; }
 
@@ -157,15 +163,17 @@
 
     private:
 
-      void load_all_methods (void);
+      OCTINTERP_API void load_all_methods (void);
 
-      void find_names (std::set<std::string>& names, bool all);
+      OCTINTERP_API void find_names (std::set<std::string>& names, bool all);
 
-      void find_properties (std::map<std::string,cdef_property>& props,
-                            int mode = 0);
+      OCTINTERP_API void
+      find_properties (std::map<std::string,cdef_property>& props,
+                       int mode = 0);
 
-      void find_methods (std::map<std::string, cdef_method>& meths,
-                         bool only_inherited, bool include_ctor = false);
+      OCTINTERP_API void
+      find_methods (std::map<std::string, cdef_method>& meths,
+                    bool only_inherited, bool include_ctor = false);
 
       cdef_class wrap (void)
       {
@@ -249,7 +257,8 @@
 
     ~cdef_class (void) = default;
 
-    cdef_method find_method (const std::string& nm, bool local = false);
+    OCTINTERP_API cdef_method
+    find_method (const std::string& nm, bool local = false);
 
     void install_method (const cdef_method& meth)
     {
@@ -267,7 +276,7 @@
       return get_rep ()->get_method_map (only_inherited, include_ctor);
     }
 
-    cdef_property find_property (const std::string& nm);
+    OCTINTERP_API cdef_property find_property (const std::string& nm);
 
     void install_property (const cdef_property& prop)
     {
@@ -330,7 +339,7 @@
     //! will fail because each attempt to compute the metaclass of
     //! recursion_class will cause recursion_class to be parsed again.
 
-    static cdef_class
+    static OCTINTERP_API cdef_class
     make_meta_class (interpreter& interp, tree_classdef *t,
                      bool is_at_folder = false);
 
@@ -339,7 +348,7 @@
       return get_rep ()->get_method (nm);
     }
 
-    octave_value get_method_function (const std::string& nm);
+    OCTINTERP_API octave_value get_method_function (const std::string& nm);
 
     octave_value get_constructor_function (void)
     {
@@ -405,11 +414,11 @@
       return dynamic_cast<const cdef_class_rep *> (cdef_object::get_rep ());
     }
 
-    friend bool operator == (const cdef_class&, const cdef_class&);
-    friend bool operator != (const cdef_class&, const cdef_class&);
-    friend bool operator < (const cdef_class&, const cdef_class&);
+    friend OCTINTERP_API bool operator == (const cdef_class&, const cdef_class&);
+    friend OCTINTERP_API bool operator != (const cdef_class&, const cdef_class&);
+    friend OCTINTERP_API bool operator < (const cdef_class&, const cdef_class&);
 
-    friend void install_classdef (interpreter& interp);
+    friend OCTINTERP_API void install_classdef (interpreter& interp);
   };
 
   inline bool
--- a/libinterp/octave-value/cdef-manager.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-manager.h	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
   {
   public:
 
-    cdef_manager (interpreter& interp);
+    OCTINTERP_API cdef_manager (interpreter& interp);
 
     // No copying!
 
@@ -52,18 +52,20 @@
 
     ~cdef_manager (void) = default;
 
-    cdef_class find_class (const std::string& name,
-                           bool error_if_not_found = true,
-                           bool load_if_not_found = true);
+    OCTINTERP_API cdef_class
+    find_class (const std::string& name, bool error_if_not_found = true,
+                bool load_if_not_found = true);
 
-    octave_value find_method_symbol (const std::string& method_name,
-                                     const std::string& class_name);
+    OCTINTERP_API octave_value
+    find_method_symbol (const std::string& method_name,
+                        const std::string& class_name);
 
-    cdef_package find_package (const std::string& name,
-                               bool error_if_not_found = true,
-                               bool load_if_not_found = true);
+    OCTINTERP_API cdef_package
+    find_package (const std::string& name, bool error_if_not_found = true,
+                  bool load_if_not_found = true);
 
-    octave_value find_package_symbol (const std::string& pack_name);
+    OCTINTERP_API octave_value
+    find_package_symbol (const std::string& pack_name);
 
     void register_class (const cdef_class& cls)
     {
@@ -92,47 +94,50 @@
 
     const cdef_package& meta (void) const { return m_meta; }
 
-    cdef_class make_class (const std::string& name,
-                           const std::list<cdef_class>& super_list = std::list<cdef_class> ());
+    OCTINTERP_API cdef_class
+    make_class (const std::string& name,
+                const std::list<cdef_class>& super_list = std::list<cdef_class> ());
 
-    cdef_class make_class (const std::string& name, const cdef_class& super);
+    OCTINTERP_API cdef_class
+    make_class (const std::string& name, const cdef_class& super);
 
-    cdef_class make_meta_class (const std::string& name,
-                                const cdef_class& super);
+    OCTINTERP_API cdef_class
+     make_meta_class (const std::string& name, const cdef_class& super);
 
-    cdef_property make_property (const cdef_class& cls,
-                                 const std::string& name,
-                                 const octave_value& get_method = Matrix (),
-                                 const std::string& get_access = "public",
-                                 const octave_value& set_method = Matrix (),
-                                 const std::string& set_access = "public");
+    OCTINTERP_API cdef_property
+    make_property (const cdef_class& cls, const std::string& name,
+                   const octave_value& get_method = Matrix (),
+                   const std::string& get_access = "public",
+                   const octave_value& set_method = Matrix (),
+                   const std::string& set_access = "public");
 
-    cdef_property make_attribute (const cdef_class& cls,
-                                  const std::string& name);
+    OCTINTERP_API cdef_property
+    make_attribute (const cdef_class& cls, const std::string& name);
 
-    cdef_method make_method (const cdef_class& cls,
-                             const std::string& name,
-                             const octave_value& fcn,
-                             const std::string& m_access = "public",
-                             bool is_static = false);
+    OCTINTERP_API cdef_method
+    make_method (const cdef_class& cls, const std::string& name,
+                 const octave_value& fcn,
+                 const std::string& m_access = "public",
+                 bool is_static = false);
 
-    cdef_method make_method (const cdef_class& cls,
-                             const std::string& name,
-                             octave_builtin::fcn ff,
-                             const std::string& m_access = "public",
-                             bool is_static = false);
+    OCTINTERP_API cdef_method
+    make_method (const cdef_class& cls, const std::string& name,
+                 octave_builtin::fcn ff,
+                 const std::string& m_access = "public",
+                 bool is_static = false);
 
-    cdef_method make_method (const cdef_class& cls,
-                             const std::string& name,
-                             octave_builtin::meth mm,
-                             const std::string& m_access = "public",
-                             bool is_static = false);
+    OCTINTERP_API cdef_method
+    make_method (const cdef_class& cls, const std::string& name,
+                 octave_builtin::meth mm,
+                 const std::string& m_access = "public",
+                 bool is_static = false);
 
-    cdef_package make_package (const std::string& nm,
-                               const std::string& parent = "");
+    OCTINTERP_API cdef_package
+    make_package (const std::string& nm, const std::string& parent = "");
 
-    octave_value find_method (const std::string& class_name,
-                              const std::string& name) const;
+    OCTINTERP_API octave_value
+    find_method (const std::string& class_name,
+                 const std::string& name) const;
 
   private:
 
--- a/libinterp/octave-value/cdef-method.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-method.h	Sun May 16 09:44:35 2021 +0200
@@ -73,9 +73,9 @@
 
       void set_function (const octave_value& fcn) { function = fcn; }
 
-      std::string get_doc_string (void);
+      OCTINTERP_API std::string get_doc_string (void);
 
-      bool check_access (void) const;
+      OCTINTERP_API bool check_access (void) const;
 
       bool is_external (void) const { return ! dispatch_type.empty (); }
 
@@ -84,18 +84,18 @@
         dispatch_type = dtype;
       }
 
-      octave_value_list execute (const octave_value_list& args, int nargout,
-                                 bool do_check_access = true,
-                                 const std::string& who = "");
+      OCTINTERP_API octave_value_list
+      execute (const octave_value_list& args, int nargout,
+               bool do_check_access = true, const std::string& who = "");
 
-      octave_value_list execute (const cdef_object& obj,
-                                 const octave_value_list& args, int nargout,
-                                 bool do_check_access = true,
-                                 const std::string& who = "");
+      OCTINTERP_API octave_value_list
+      execute (const cdef_object& obj,
+               const octave_value_list& args, int nargout,
+               bool do_check_access = true, const std::string& who = "");
 
-      bool is_constructor (void) const;
+      OCTINTERP_API bool is_constructor (void) const;
 
-      bool is_defined_in_class (const std::string& cname) const;
+      OCTINTERP_API bool is_defined_in_class (const std::string& cname) const;
 
       octave_value_list
       meta_subsref (const std::string& type,
@@ -113,7 +113,7 @@
           dispatch_type (m.dispatch_type)
       { }
 
-      void check_method (void);
+      OCTINTERP_API void check_method (void);
 
       cdef_method wrap (void)
       {
--- a/libinterp/octave-value/cdef-object.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-object.cc	Sun May 16 09:44:35 2021 +0200
@@ -244,10 +244,10 @@
                 {
                   iv(i) = ival(i).index_vector ();
                 }
-              catch (index_exception& e)
+              catch (index_exception& ie)
                 {
                   // Rethrow to allow more info to be reported later.
-                  e.set_pos_if_unset (ival.length (), i+1);
+                  ie.set_pos_if_unset (ival.length (), i+1);
                   throw;
                 }
 
@@ -326,7 +326,7 @@
             cdef_object rhs_obj = to_cdef (rhs);
 
             if (rhs_obj.get_class () != get_class ())
-              error ("can't assign %s object into array of %s objects.",
+              error ("can't assign %s object into array of %s objects",
                      rhs_obj.class_name ().c_str (),
                      class_name ().c_str ());
 
@@ -340,9 +340,9 @@
                   {
                     iv(i) = ival(i).index_vector ();
                   }
-                catch (index_exception& e)
+                catch (index_exception& ie)
                   {
-                    e.set_pos_if_unset (ival.length (), i+1);
+                    ie.set_pos_if_unset (ival.length (), i+1);
                     throw;   // var name set in pt-idx.cc / pt-assign.cc
                   }
 
@@ -391,10 +391,10 @@
                   {
                     iv(i) = ival(i).index_vector ();
                   }
-                catch (index_exception& e)
+                catch (index_exception& ie)
                   {
                     // Rethrow to allow more info to be reported later.
-                    e.set_pos_if_unset (ival.length (), i+1);
+                    ie.set_pos_if_unset (ival.length (), i+1);
                     throw;
                   }
 
--- a/libinterp/octave-value/cdef-object.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-object.h	Sun May 16 09:44:35 2021 +0200
@@ -48,6 +48,7 @@
   // cdef_object, such that it can contain cdef_object objects.
 
   class
+  OCTINTERP_API
   cdef_object_rep
   {
   public:
@@ -142,7 +143,7 @@
 
     virtual bool is_valid (void) const { return false; }
 
-    std::string class_name (void) const;
+    OCTINTERP_API std::string class_name (void) const;
 
     virtual void mark_for_construction (const cdef_class&)
     {
@@ -178,7 +179,7 @@
 
     virtual void destroy (void) { delete this; }
 
-    void release (const cdef_object& obj);
+    OCTINTERP_API void release (const cdef_object& obj);
 
     virtual dim_vector dims (void) const { return dim_vector (); }
 
@@ -226,7 +227,7 @@
       return *this;
     }
 
-    cdef_class get_class (void) const;
+    OCTINTERP_API cdef_class get_class (void) const;
 
     void set_class (const cdef_class& cls) { rep->set_class (cls); }
 
@@ -303,7 +304,7 @@
 
     string_vector map_keys (void) const { return rep->map_keys (); }
 
-    octave_map map_value (void) const;
+    OCTINTERP_API octave_map map_value (void) const;
 
     const cdef_object_rep * get_rep (void) const { return rep; }
 
@@ -361,16 +362,16 @@
 
     ~cdef_object_base (void) { }
 
-    cdef_class get_class (void) const;
+    OCTINTERP_API cdef_class get_class (void) const;
 
-    void set_class (const cdef_class& cls);
+    OCTINTERP_API void set_class (const cdef_class& cls);
 
     cdef_object_rep * empty_clone (void) const
     {
       return new cdef_object_base (*this);
     }
 
-    cdef_object_rep * make_array (void) const;
+    OCTINTERP_API cdef_object_rep * make_array (void) const;
 
   protected:
 
@@ -413,12 +414,12 @@
 
     Array<cdef_object> array_value (void) const { return array; }
 
-    octave_value_list
+    OCTINTERP_API octave_value_list
     subsref (const std::string& type, const std::list<octave_value_list>& idx,
              int nargout, std::size_t& skip, const cdef_class& context,
              bool auto_add);
 
-    octave_value
+    OCTINTERP_API octave_value
     subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
               const octave_value& rhs);
 
@@ -444,7 +445,7 @@
 
     void fill_empty_values (void) { fill_empty_values (array); }
 
-    void fill_empty_values (Array<cdef_object>& arr);
+    OCTINTERP_API void fill_empty_values (Array<cdef_object>& arr);
 
     // Private copying!
     cdef_object_array (const cdef_object_array& obj)
@@ -500,24 +501,25 @@
       return get (pname);
     }
 
-    octave_value_list
+    OCTINTERP_API octave_value_list
     subsref (const std::string& type, const std::list<octave_value_list>& idx,
              int nargout, std::size_t& skip, const cdef_class& context,
              bool auto_add);
 
-    octave_value
+    OCTINTERP_API octave_value
     subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
               const octave_value& rhs);
 
-    void mark_for_construction (const cdef_class&);
+    OCTINTERP_API void mark_for_construction (const cdef_class&);
 
-    bool is_constructed_for (const cdef_class& cls) const;
+    OCTINTERP_API bool is_constructed_for (const cdef_class& cls) const;
 
-    bool is_partially_constructed_for (const cdef_class& cls) const;
+    OCTINTERP_API bool
+    is_partially_constructed_for (const cdef_class& cls) const;
 
     void mark_as_constructed (void) { ctor_list.clear (); }
 
-    void mark_as_constructed (const cdef_class& cls);
+    OCTINTERP_API void mark_as_constructed (const cdef_class& cls);
 
     bool is_constructed (void) const { return ctor_list.empty (); }
 
@@ -546,7 +548,7 @@
 
     handle_cdef_object& operator = (const handle_cdef_object&) = delete;
 
-    ~handle_cdef_object (void);
+    OCTINTERP_API ~handle_cdef_object (void);
 
     cdef_object_rep * clone (void) const
     {
@@ -581,7 +583,7 @@
 
     value_cdef_object& operator = (const value_cdef_object&) = delete;
 
-    ~value_cdef_object (void);
+    OCTINTERP_API ~value_cdef_object (void);
 
     cdef_object_rep * clone (void) const
     {
--- a/libinterp/octave-value/cdef-package.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-package.h	Sun May 16 09:44:35 2021 +0200
@@ -67,17 +67,20 @@
 
       void set_name (const std::string& nm) { put ("Name", nm); }
 
-      void install_class (const cdef_class& cls, const std::string& nm);
+      OCTINTERP_API void
+      install_class (const cdef_class& cls, const std::string& nm);
 
-      void install_function (const octave_value& fcn, const std::string& nm);
-
-      void install_package (const cdef_package& pack, const std::string& nm);
+      OCTINTERP_API void
+      install_function (const octave_value& fcn, const std::string& nm);
 
-      Cell get_classes (void) const;
+      OCTINTERP_API void
+      install_package (const cdef_package& pack, const std::string& nm);
 
-      Cell get_functions (void) const;
+      OCTINTERP_API Cell get_classes (void) const;
 
-      Cell get_packages (void) const;
+      OCTINTERP_API Cell get_functions (void) const;
+
+      OCTINTERP_API Cell get_packages (void) const;
 
       octave_idx_type static_count (void) const { return member_count; }
 
@@ -96,18 +99,18 @@
           delete this;
       }
 
-      octave_value_list
+      OCTINTERP_API octave_value_list
       meta_subsref (const std::string& type,
                     const std::list<octave_value_list>& idx, int nargout);
 
-      void meta_release (void);
+      OCTINTERP_API void meta_release (void);
 
       bool meta_accepts_postfix_index (char type) const
       {
         return (type == '.');
       }
 
-      octave_value find (const std::string& nm);
+      OCTINTERP_API octave_value find (const std::string& nm);
 
     private:
 
@@ -221,7 +224,7 @@
       return dynamic_cast<const cdef_package_rep *> (cdef_object::get_rep ());
     }
 
-    friend void install_classdef (interpreter& interp);
+    friend OCTINTERP_API void install_classdef (interpreter& interp);
   };
 }
 
--- a/libinterp/octave-value/cdef-property.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-property.cc	Sun May 16 09:44:35 2021 +0200
@@ -207,19 +207,24 @@
         args(0) = to_ov (obj);
         args(1) = val;
 
-        args = feval (set_fcn, args, 1);
+        if (obj.is_handle_object ())
+          feval (set_fcn, args, 0);
+        else
+          {
+            args = feval (set_fcn, args, 1);
 
-        if (args.length () > 0 && args(0).is_defined ())
-          {
-            if (args (0).is_classdef_object ())
+            if (args.length () > 0 && args(0).is_defined ())
               {
-                cdef_object new_obj = to_cdef (args(0));
+                if (args(0).is_classdef_object ())
+                  {
+                    cdef_object new_obj = to_cdef (args(0));
 
-                obj = new_obj;
+                    obj = new_obj;
+                  }
+                else
+                  ::warning ("set-method of property '%s' returned a non-classdef object",
+                             get_name ().c_str ());
               }
-            else
-              ::warning ("set-method of property '%s' returned a non-classdef object",
-                         get_name ().c_str ());
           }
       }
   }
--- a/libinterp/octave-value/cdef-property.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-property.h	Sun May 16 09:44:35 2021 +0200
@@ -82,16 +82,16 @@
                       bool do_check_access = true,
                       const std::string& who = "");
 
-      bool check_get_access (void) const;
+      OCTINTERP_API bool check_get_access (void) const;
 
-      bool check_set_access (void) const;
+      OCTINTERP_API bool check_set_access (void) const;
 
     private:
       cdef_property_rep (const cdef_property_rep& p)
         : cdef_meta_object_rep (p)
       { }
 
-      bool is_recursive_set (const cdef_object& obj) const;
+      OCTINTERP_API bool is_recursive_set (const cdef_object& obj) const;
 
       cdef_property wrap (void)
       {
@@ -99,7 +99,7 @@
         return cdef_property (this);
       }
 
-      OCTAVE_NORETURN
+      OCTINTERP_API OCTAVE_NORETURN
       void err_property_access (const std::string& from,
                                 bool is_set = false) const;
     };
--- a/libinterp/octave-value/cdef-utils.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/cdef-utils.h	Sun May 16 09:44:35 2021 +0200
@@ -39,70 +39,70 @@
   class cdef_class;
   class cdef_package;
 
-  extern std::string
+  extern OCTINTERP_API std::string
   get_base_name (const std::string& nm);
 
-  extern void
+  extern OCTINTERP_API void
   make_function_of_class (const std::string& class_name,
                           const octave_value& fcn);
 
-  extern void
+  extern OCTINTERP_API void
   make_function_of_class (const cdef_class& cls, const octave_value& fcn);
 
-  extern cdef_class
+  extern OCTINTERP_API cdef_class
   lookup_class (const std::string& name, bool error_if_not_found = true,
                 bool load_if_not_found = true);
 
-  extern cdef_class
+  extern OCTINTERP_API cdef_class
   lookup_class (const cdef_class& cls);
 
-  extern cdef_class
+  extern OCTINTERP_API cdef_class
   lookup_class (const octave_value& ov);
 
-  extern std::list<cdef_class>
+  extern OCTINTERP_API std::list<cdef_class>
   lookup_classes (const Cell& cls_list);
 
-  extern octave_value
+  extern OCTINTERP_API octave_value
   to_ov (const cdef_object& obj);
 
-  extern octave_value
+  extern OCTINTERP_API octave_value
   to_ov (const octave_value& ov);
 
-  extern cdef_object
+  extern OCTINTERP_API cdef_object
   to_cdef (const octave_value& val);
 
-  extern cdef_object&
+  extern OCTINTERP_API cdef_object&
   to_cdef_ref (const octave_value& val);
 
-  extern cdef_object
+  extern OCTINTERP_API cdef_object
   to_cdef (const cdef_object& obj);
 
-  extern octave_value
+  extern OCTINTERP_API octave_value
   to_ov (const std::list<cdef_class>& class_list);
 
-  extern bool
+  extern OCTINTERP_API bool
   is_dummy_method (const octave_value& fcn);
 
-  extern bool
+  extern OCTINTERP_API bool
   is_superclass (const cdef_class& clsa, const cdef_class& clsb,
                  bool allow_equal = true, int max_depth = -1);
-  extern bool
+  extern OCTINTERP_API bool
   is_strict_superclass (const cdef_class& clsa, const cdef_class& clsb);
 
-  extern bool
+  extern OCTINTERP_API bool
   is_direct_superclass (const cdef_class& clsa, const cdef_class& clsb);
 
-  extern cdef_package
+  extern OCTINTERP_API cdef_package
   lookup_package (const std::string& name, bool error_if_not_found = true,
                   bool load_if_not_found = true);
 
-  extern cdef_class
+  extern OCTINTERP_API cdef_class
   get_class_context (std::string& name, bool& in_constructor);
 
-  extern cdef_class
+  extern OCTINTERP_API cdef_class
   get_class_context (void);
 
-  extern bool
+  extern OCTINTERP_API bool
   check_access (const cdef_class& cls, const octave_value& acc,
                 const std::string& meth_name = "",
                 const std::string& prop_name = "",
--- a/libinterp/octave-value/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -52,10 +52,12 @@
   %reldir%/ov-flt-re-mat.h \
   %reldir%/ov-java.h \
   %reldir%/ov-lazy-idx.h \
+  %reldir%/ov-magic-int.h \
   %reldir%/ov-mex-fcn.h \
   %reldir%/ov-null-mat.h \
   %reldir%/ov-oncleanup.h \
   %reldir%/ov-perm.h \
+  %reldir%/ov-range-traits.h \
   %reldir%/ov-range.h \
   %reldir%/ov-re-diag.h \
   %reldir%/ov-re-mat.h \
@@ -116,6 +118,7 @@
   %reldir%/ov-flt-re-mat.cc \
   %reldir%/ov-java.cc \
   %reldir%/ov-lazy-idx.cc \
+  %reldir%/ov-magic-int.cc \
   %reldir%/ov-mex-fcn.cc \
   %reldir%/ov-null-mat.cc \
   %reldir%/ov-oncleanup.cc \
--- a/libinterp/octave-value/ov-base-diag.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-diag.cc	Sun May 16 09:44:35 2021 +0200
@@ -110,9 +110,9 @@
       int k = 0;        // index we're accessing when index_vector throws
       try
         {
-          idx_vector idx0 = idx(0).index_vector ();
+          octave::idx_vector idx0 = idx(0).index_vector ();
           k = 1;
-          idx_vector idx1 = idx(1).index_vector ();
+          octave::idx_vector idx1 = idx(1).index_vector ();
 
           if (idx0.is_scalar () && idx1.is_scalar ())
             {
@@ -130,18 +130,18 @@
                   retval = rm;
                 }
               else
-                retval = to_dense ().do_index_op (idx, resize_ok);
+                retval = to_dense ().index_op (idx, resize_ok);
             }
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
           // Rethrow to allow more info to be reported later.
-          e.set_pos_if_unset (2, k+1);
+          ie.set_pos_if_unset (2, k+1);
           throw;
         }
     }
   else
-    retval = to_dense ().do_index_op (idx, resize_ok);
+    retval = to_dense ().index_op (idx, resize_ok);
 
   return retval;
 }
@@ -180,12 +180,12 @@
             int k = 0;
             try
               {
-                idx_vector ind = jdx(0).index_vector ();
+                octave::idx_vector ind = jdx(0).index_vector ();
                 k = 1;
                 dim_vector dv (matrix.rows (), matrix.cols ());
-                Array<idx_vector> ivec = ind2sub (dv, ind);
-                idx_vector i0 = ivec(0);
-                idx_vector i1 = ivec(1);
+                Array<octave::idx_vector> ivec = ind2sub (dv, ind);
+                octave::idx_vector i0 = ivec(0);
+                octave::idx_vector i1 = ivec(1);
 
                 if (i0(0) == i1(0)
                     && chk_valid_scalar (rhs, val))
@@ -197,10 +197,10 @@
                     dense_cache = octave_value ();
                   }
               }
-            catch (octave::index_exception& e)
+            catch (octave::index_exception& ie)
               {
                 // Rethrow to allow more info to be reported later.
-                e.set_pos_if_unset (2, k+1);
+                ie.set_pos_if_unset (2, k+1);
                 throw;
               }
           }
@@ -211,9 +211,9 @@
             int k = 0;
             try
               {
-                idx_vector i0 = jdx(0).index_vector ();
+                octave::idx_vector i0 = jdx(0).index_vector ();
                 k = 1;
-                idx_vector i1 = jdx(1).index_vector ();
+                octave::idx_vector i1 = jdx(1).index_vector ();
                 if (i0(0) == i1(0)
                     && i0(0) < matrix.rows () && i1(0) < matrix.cols ()
                     && chk_valid_scalar (rhs, val))
@@ -225,10 +225,10 @@
                     dense_cache = octave_value ();
                   }
               }
-            catch (octave::index_exception& e)
+            catch (octave::index_exception& ie)
               {
                 // Rethrow to allow more info to be reported later.
-                e.set_pos_if_unset (2, k+1);
+                ie.set_pos_if_unset (2, k+1);
                 throw;
               }
           }
@@ -456,7 +456,7 @@
 }
 
 template <typename DMT, typename MT>
-idx_vector
+octave::idx_vector
 octave_base_diag<DMT, MT>::index_vector (bool require_integers) const
 {
   return to_dense ().index_vector (require_integers);
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-diag.h	Sun May 16 09:44:35 2021 +0200
@@ -44,6 +44,7 @@
 
 template <typename DMT, typename MT>
 class
+OCTINTERP_API
 octave_base_diag : public octave_base_value
 {
 
@@ -72,19 +73,19 @@
   // functions.
   using octave_base_value::subsref;
 
-  octave_value subsref (const std::string& type,
-                        const std::list<octave_value_list>& idx);
+  OCTINTERP_API octave_value
+  subsref (const std::string& type, const std::list<octave_value_list>& idx);
 
   octave_value_list subsref (const std::string& type,
                              const std::list<octave_value_list>& idx, int)
   { return subsref (type, idx); }
 
-  octave_value do_index_op (const octave_value_list& idx,
-                            bool resize_ok = false);
+  OCTINTERP_API octave_value
+  do_index_op (const octave_value_list& idx, bool resize_ok = false);
 
-  octave_value subsasgn (const std::string& type,
-                         const std::list<octave_value_list>& idx,
-                         const octave_value& rhs);
+  OCTINTERP_API octave_value
+  subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
+            const octave_value& rhs);
 
   dim_vector dims (void) const { return matrix.dims (); }
 
@@ -103,7 +104,8 @@
       return to_dense ().permute (vec, inv);
   }
 
-  octave_value resize (const dim_vector& dv, bool fill = false) const;
+  OCTINTERP_API octave_value
+  resize (const dim_vector& dv, bool fill = false) const;
 
   octave_value all (int dim = 0) const { return MT (matrix).all (dim); }
   octave_value any (int dim = 0) const { return MT (matrix).any (dim); }
@@ -117,7 +119,7 @@
   // functions.
   using octave_base_value::diag;
 
-  octave_value diag (octave_idx_type k = 0) const;
+  OCTINTERP_API octave_value diag (octave_idx_type k = 0) const;
 
   octave_value sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const
   { return to_dense ().sort (dim, mode); }
@@ -142,46 +144,50 @@
 
   bool is_constant (void) const { return true; }
 
-  bool is_true (void) const;
+  OCTINTERP_API bool is_true (void) const;
 
   bool is_diag_matrix (void) const { return true; }
 
-  double double_value (bool = false) const;
+  OCTINTERP_API double double_value (bool = false) const;
 
-  float float_value (bool = false) const;
+  OCTINTERP_API float float_value (bool = false) const;
 
   double scalar_value (bool frc_str_conv = false) const
   { return double_value (frc_str_conv); }
 
-  idx_vector index_vector (bool /* require_integers */ = false) const;
+  OCTINTERP_API octave::idx_vector
+  index_vector (bool /* require_integers */ = false) const;
 
-  Matrix matrix_value (bool = false) const;
+  OCTINTERP_API Matrix matrix_value (bool = false) const;
 
-  FloatMatrix float_matrix_value (bool = false) const;
+  OCTINTERP_API FloatMatrix float_matrix_value (bool = false) const;
 
-  Complex complex_value (bool = false) const;
+  OCTINTERP_API Complex complex_value (bool = false) const;
 
-  FloatComplex float_complex_value (bool = false) const;
+  OCTINTERP_API FloatComplex float_complex_value (bool = false) const;
 
-  ComplexMatrix complex_matrix_value (bool = false) const;
+  OCTINTERP_API ComplexMatrix complex_matrix_value (bool = false) const;
 
-  FloatComplexMatrix float_complex_matrix_value (bool = false) const;
+  OCTINTERP_API FloatComplexMatrix
+  float_complex_matrix_value (bool = false) const;
 
-  ComplexNDArray complex_array_value (bool = false) const;
-
-  FloatComplexNDArray float_complex_array_value (bool = false) const;
+  OCTINTERP_API ComplexNDArray complex_array_value (bool = false) const;
 
-  boolNDArray bool_array_value (bool warn = false) const;
+  OCTINTERP_API FloatComplexNDArray
+  float_complex_array_value (bool = false) const;
 
-  charNDArray char_array_value (bool = false) const;
+  OCTINTERP_API boolNDArray bool_array_value (bool warn = false) const;
+
+  OCTINTERP_API charNDArray char_array_value (bool = false) const;
 
-  NDArray array_value (bool = false) const;
+  OCTINTERP_API NDArray array_value (bool = false) const;
 
-  FloatNDArray float_array_value (bool = false) const;
+  OCTINTERP_API FloatNDArray float_array_value (bool = false) const;
 
-  SparseMatrix sparse_matrix_value (bool = false) const;
+  OCTINTERP_API SparseMatrix sparse_matrix_value (bool = false) const;
 
-  SparseComplexMatrix sparse_complex_matrix_value (bool = false) const;
+  OCTINTERP_API SparseComplexMatrix
+  sparse_complex_matrix_value (bool = false) const;
 
   int8NDArray
   int8_array_value (void) const { return to_dense ().int8_array_value (); }
@@ -207,40 +213,45 @@
   uint64NDArray
   uint64_array_value (void) const { return to_dense ().uint64_array_value (); }
 
-  octave_value convert_to_str_internal (bool pad, bool force, char type) const;
+  OCTINTERP_API octave_value
+  convert_to_str_internal (bool pad, bool force, char type) const;
 
-  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+  OCTINTERP_API void
+  print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  float_display_format get_edit_display_format (void) const;
+  OCTINTERP_API float_display_format get_edit_display_format (void) const;
 
-  std::string edit_display (const float_display_format& fmt,
-                            octave_idx_type i, octave_idx_type j) const;
+  OCTINTERP_API std::string
+  edit_display (const float_display_format& fmt,
+                octave_idx_type i, octave_idx_type j) const;
 
-  bool save_ascii (std::ostream& os);
+  OCTINTERP_API bool save_ascii (std::ostream& os);
 
-  bool load_ascii (std::istream& is);
+  OCTINTERP_API bool load_ascii (std::istream& is);
 
-  int write (octave::stream& os, int block_size,
-             oct_data_conv::data_type output_type, int skip,
-             octave::mach_info::float_format flt_fmt) const;
+  OCTINTERP_API int
+  write (octave::stream& os, int block_size,
+         oct_data_conv::data_type output_type, int skip,
+         octave::mach_info::float_format flt_fmt) const;
 
-  mxArray * as_mxArray (void) const;
+  OCTINTERP_API mxArray * as_mxArray (bool interleaved) const;
 
-  bool print_as_scalar (void) const;
+  OCTINTERP_API bool print_as_scalar (void) const;
 
-  void print (std::ostream& os, bool pr_as_read_syntax = false);
-
-  void print_info (std::ostream& os, const std::string& prefix) const;
+  OCTINTERP_API void print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  void short_disp (std::ostream& os) const;
+  OCTINTERP_API void
+  print_info (std::ostream& os, const std::string& prefix) const;
 
-  octave_value fast_elem_extract (octave_idx_type n) const;
+  OCTINTERP_API void short_disp (std::ostream& os) const;
+
+  OCTINTERP_API octave_value fast_elem_extract (octave_idx_type n) const;
 
 protected:
 
   DMT matrix;
 
-  octave_value to_dense (void) const;
+  OCTINTERP_API octave_value to_dense (void) const;
 
   virtual bool chk_valid_scalar (const octave_value&,
                                  typename DMT::element_type&) const = 0;
--- a/libinterp/octave-value/ov-base-int.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-int.cc	Sun May 16 09:44:35 2021 +0200
@@ -729,7 +729,7 @@
 #if defined (HAVE_HDF5)
 
   hid_t save_type_hid = save_type;
-  hsize_t dimens[3];
+  hsize_t dimens[3] = {0};
   hid_t space_hid, data_hid;
   space_hid = data_hid = -1;
 
--- a/libinterp/octave-value/ov-base-int.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-int.h	Sun May 16 09:44:35 2021 +0200
@@ -46,6 +46,7 @@
 
 template <typename T>
 class
+OCTINTERP_API
 octave_base_int_matrix : public octave_base_matrix<T>
 {
 public:
@@ -62,7 +63,7 @@
   octave_base_value * empty_clone (void) const
   { return new octave_base_int_matrix (); }
 
-  octave_base_value * try_narrowing_conversion (void);
+  OCTINTERP_API octave_base_value * try_narrowing_conversion (void);
 
   bool isreal (void) const { return true; }
 
@@ -70,48 +71,54 @@
 
   //  void decrement (void) { matrix -= 1; }
 
-  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+  OCTINTERP_API void
+  print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  octave_value convert_to_str_internal (bool, bool, char type) const;
+  OCTINTERP_API octave_value
+  convert_to_str_internal (bool, bool, char type) const;
 
-  octave_value as_double (void) const;
-  octave_value as_single (void) const;
+  OCTINTERP_API octave_value as_double (void) const;
+  OCTINTERP_API octave_value as_single (void) const;
 
-  octave_value as_int8 (void) const;
-  octave_value as_int16 (void) const;
-  octave_value as_int32 (void) const;
-  octave_value as_int64 (void) const;
+  OCTINTERP_API octave_value as_int8 (void) const;
+  OCTINTERP_API octave_value as_int16 (void) const;
+  OCTINTERP_API octave_value as_int32 (void) const;
+  OCTINTERP_API octave_value as_int64 (void) const;
 
-  octave_value as_uint8 (void) const;
-  octave_value as_uint16 (void) const;
-  octave_value as_uint32 (void) const;
-  octave_value as_uint64 (void) const;
+  OCTINTERP_API octave_value as_uint8 (void) const;
+  OCTINTERP_API octave_value as_uint16 (void) const;
+  OCTINTERP_API octave_value as_uint32 (void) const;
+  OCTINTERP_API octave_value as_uint64 (void) const;
 
-  std::string edit_display (const float_display_format& fmt,
-                            octave_idx_type i, octave_idx_type j) const;
+  OCTINTERP_API std::string
+  edit_display (const float_display_format& fmt,
+                octave_idx_type i, octave_idx_type j) const;
 
-  bool save_ascii (std::ostream& os);
+  OCTINTERP_API bool save_ascii (std::ostream& os);
 
-  bool load_ascii (std::istream& is);
+  OCTINTERP_API bool load_ascii (std::istream& is);
 
-  bool save_binary (std::ostream& os, bool);
+  OCTINTERP_API bool save_binary (std::ostream& os, bool);
 
-  bool load_binary (std::istream& is, bool swap,
-                    octave::mach_info::float_format);
+  OCTINTERP_API bool
+  load_binary (std::istream& is, bool swap, octave::mach_info::float_format);
 
 protected:
 
-  bool save_hdf5_internal (octave_hdf5_id loc_id, octave_hdf5_id save_type,
-                           const char *name, bool);
+  OCTINTERP_API bool
+  save_hdf5_internal (octave_hdf5_id loc_id, octave_hdf5_id save_type,
+                      const char *name, bool);
 
-  bool load_hdf5_internal (octave_hdf5_id loc_id, octave_hdf5_id save_type,
-                           const char *name);
+  OCTINTERP_API bool
+  load_hdf5_internal (octave_hdf5_id loc_id, octave_hdf5_id save_type,
+                      const char *name);
 };
 
 // base int scalar values.
 
 template <typename T>
 class
+OCTINTERP_API
 octave_base_int_scalar : public octave_base_scalar<T>
 {
 public:
@@ -137,39 +144,43 @@
 
   //  void decrement (void) { scalar -= 1; }
 
-  octave_value convert_to_str_internal (bool, bool, char type) const;
-
-  octave_value as_double (void) const;
-  octave_value as_single (void) const;
+  OCTINTERP_API octave_value
+  convert_to_str_internal (bool, bool, char type) const;
 
-  octave_value as_int8 (void) const;
-  octave_value as_int16 (void) const;
-  octave_value as_int32 (void) const;
-  octave_value as_int64 (void) const;
+  OCTINTERP_API octave_value as_double (void) const;
+  OCTINTERP_API octave_value as_single (void) const;
+
+  OCTINTERP_API octave_value as_int8 (void) const;
+  OCTINTERP_API octave_value as_int16 (void) const;
+  OCTINTERP_API octave_value as_int32 (void) const;
+  OCTINTERP_API octave_value as_int64 (void) const;
 
-  octave_value as_uint8 (void) const;
-  octave_value as_uint16 (void) const;
-  octave_value as_uint32 (void) const;
-  octave_value as_uint64 (void) const;
-
-  std::string edit_display (const float_display_format& fmt,
-                            octave_idx_type i, octave_idx_type j) const;
+  OCTINTERP_API octave_value as_uint8 (void) const;
+  OCTINTERP_API octave_value as_uint16 (void) const;
+  OCTINTERP_API octave_value as_uint32 (void) const;
+  OCTINTERP_API octave_value as_uint64 (void) const;
 
-  bool save_ascii (std::ostream& os);
+  OCTINTERP_API std::string
+  edit_display (const float_display_format& fmt,
+                octave_idx_type i, octave_idx_type j) const;
 
-  bool load_ascii (std::istream& is);
+  OCTINTERP_API bool save_ascii (std::ostream& os);
 
-  bool save_binary (std::ostream& os, bool);
+  OCTINTERP_API bool load_ascii (std::istream& is);
 
-  bool load_binary (std::istream& is, bool swap,
+  OCTINTERP_API bool save_binary (std::ostream& os, bool);
+
+  OCTINTERP_API bool load_binary (std::istream& is, bool swap,
                     octave::mach_info::float_format);
 protected:
 
-  bool save_hdf5_internal (octave_hdf5_id loc_id, octave_hdf5_id save_type,
-                           const char *name, bool);
+  OCTINTERP_API bool
+  save_hdf5_internal (octave_hdf5_id loc_id, octave_hdf5_id save_type,
+                      const char *name, bool);
 
-  bool load_hdf5_internal (octave_hdf5_id loc_id, octave_hdf5_id save_type,
-                           const char *name);
+  OCTINTERP_API bool
+  load_hdf5_internal (octave_hdf5_id loc_id, octave_hdf5_id save_type,
+                      const char *name);
 };
 
 #endif
--- a/libinterp/octave-value/ov-base-mat.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-mat.cc	Sun May 16 09:44:35 2021 +0200
@@ -157,7 +157,7 @@
 
         case 1:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             // optimize single scalar index.
             if (! resize_ok && i.is_scalar ())
@@ -169,10 +169,10 @@
 
         case 2:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             k=1;
-            idx_vector j = idx (1).index_vector ();
+            octave::idx_vector j = idx (1).index_vector ();
 
             // optimize two scalar indices.
             if (! resize_ok && i.is_scalar () && j.is_scalar ())
@@ -184,7 +184,7 @@
 
         default:
           {
-            Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
+            Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
             bool scalar_opt = n_idx == nd && ! resize_ok;
             const dim_vector dv = matrix.dims ();
 
@@ -203,10 +203,10 @@
           break;
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (n_idx, k+1);
+      ie.set_pos_if_unset (n_idx, k+1);
       throw;
     }
 
@@ -242,7 +242,7 @@
 
         case 1:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             matrix.assign (i, rhs);
           }
@@ -250,10 +250,10 @@
 
         case 2:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             k = 1;
-            idx_vector j = idx (1).index_vector ();
+            octave::idx_vector j = idx (1).index_vector ();
 
             matrix.assign (i, j, rhs);
           }
@@ -261,7 +261,7 @@
 
         default:
           {
-            Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
+            Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
 
             for (k = 0; k < n_idx; k++)
               idx_vec(k) = idx(k).index_vector ();
@@ -271,10 +271,10 @@
           break;
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (n_idx, k+1);
+      ie.set_pos_if_unset (n_idx, k+1);
       throw;
     }
 
@@ -318,7 +318,7 @@
 
         case 1:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             // optimize single scalar index.
             if (i.is_scalar () && i(0) < matrix.numel ())
@@ -330,10 +330,10 @@
 
         case 2:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             k = 1;
-            idx_vector j = idx (1).index_vector ();
+            octave::idx_vector j = idx (1).index_vector ();
 
             // optimize two scalar indices.
             if (i.is_scalar () && j.is_scalar () && nd == 2
@@ -346,7 +346,7 @@
 
         default:
           {
-            Array<idx_vector> idx_vec (dim_vector (n_idx, 1));
+            Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
             bool scalar_opt = n_idx == nd;
             const dim_vector dv = matrix.dims ().redim (n_idx);
 
@@ -377,10 +377,10 @@
           break;
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (n_idx, k+1);
+      ie.set_pos_if_unset (n_idx, k+1);
       throw;
     }
 
@@ -394,7 +394,7 @@
 {
   octave_idx_type len = idx.length ();
 
-  Array<idx_vector> ra_idx (dim_vector (len, 1));
+  Array<octave::idx_vector> ra_idx (dim_vector (len, 1));
 
   for (octave_idx_type i = 0; i < len; i++)
     ra_idx(i) = idx(i).index_vector ();
--- a/libinterp/octave-value/ov-base-mat.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-mat.h	Sun May 16 09:44:35 2021 +0200
@@ -46,10 +46,13 @@
 
 template <typename MT>
 class
+OCTINTERP_API
 octave_base_matrix : public octave_base_value
 {
 public:
 
+  typedef MT object_type;
+
   octave_base_matrix (void)
     : octave_base_value (), matrix (), typ (), idx_cache () { }
 
@@ -64,7 +67,7 @@
   octave_base_matrix (const octave_base_matrix& m)
     : octave_base_value (), matrix (m.matrix),
       typ (m.typ ? new MatrixType (*m.typ) : nullptr),
-      idx_cache (m.idx_cache ? new idx_vector (*m.idx_cache) : nullptr)
+      idx_cache (m.idx_cache ? new octave::idx_vector (*m.idx_cache) : nullptr)
   { }
 
   ~octave_base_matrix (void) { clear_cached_info (); }
@@ -82,19 +85,19 @@
   // functions.
   using octave_base_value::subsref;
 
-  octave_value subsref (const std::string& type,
-                        const std::list<octave_value_list>& idx);
+  OCTINTERP_API octave_value
+  subsref (const std::string& type, const std::list<octave_value_list>& idx);
 
   octave_value_list subsref (const std::string& type,
                              const std::list<octave_value_list>& idx, int)
   { return subsref (type, idx); }
 
-  octave_value subsasgn (const std::string& type,
-                         const std::list<octave_value_list>& idx,
-                         const octave_value& rhs);
+  OCTINTERP_API octave_value
+  subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
+            const octave_value& rhs);
 
-  octave_value do_index_op (const octave_value_list& idx,
-                            bool resize_ok = false);
+  OCTINTERP_API octave_value
+  do_index_op (const octave_value_list& idx,  bool resize_ok = false);
 
   // FIXME: should we import the functions from the base class and
   // overload them here, or should we use a different name so we don't
@@ -103,11 +106,12 @@
   // can also cause some confusion.
   using octave_base_value::assign;
 
-  void assign (const octave_value_list& idx, const MT& rhs);
+  OCTINTERP_API void assign (const octave_value_list& idx, const MT& rhs);
 
-  void assign (const octave_value_list& idx, typename MT::element_type rhs);
+  OCTINTERP_API void
+  assign (const octave_value_list& idx, typename MT::element_type rhs);
 
-  void delete_elements (const octave_value_list& idx);
+  OCTINTERP_API void delete_elements (const octave_value_list& idx);
 
   dim_vector dims (void) const { return matrix.dims (); }
 
@@ -160,20 +164,22 @@
 
   bool is_constant (void) const { return true; }
 
-  bool is_true (void) const;
+  OCTINTERP_API bool is_true (void) const;
 
-  bool print_as_scalar (void) const;
+  OCTINTERP_API bool print_as_scalar (void) const;
 
-  void print (std::ostream& os, bool pr_as_read_syntax = false);
+  OCTINTERP_API void print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  void print_info (std::ostream& os, const std::string& prefix) const;
+  OCTINTERP_API void
+  print_info (std::ostream& os, const std::string& prefix) const;
 
-  void short_disp (std::ostream& os) const;
+  OCTINTERP_API void short_disp (std::ostream& os) const;
 
-  float_display_format get_edit_display_format (void) const;
+  OCTINTERP_API float_display_format get_edit_display_format (void) const;
 
-  std::string edit_display (const float_display_format& fmt,
-                            octave_idx_type i, octave_idx_type j) const;
+  OCTINTERP_API std::string
+  edit_display (const float_display_format& fmt,
+                octave_idx_type i, octave_idx_type j) const;
 
   MT& matrix_ref (void)
   {
@@ -186,20 +192,20 @@
     return matrix;
   }
 
-  octave_value
+  OCTINTERP_API octave_value
   fast_elem_extract (octave_idx_type n) const;
 
-  bool
+  OCTINTERP_API bool
   fast_elem_insert (octave_idx_type n, const octave_value& x);
 
 protected:
 
   MT matrix;
 
-  idx_vector set_idx_cache (const idx_vector& idx) const
+  octave::idx_vector set_idx_cache (const octave::idx_vector& idx) const
   {
     delete idx_cache;
-    idx_cache = (idx ? new idx_vector (idx) : nullptr);
+    idx_cache = (idx ? new octave::idx_vector (idx) : nullptr);
     return idx;
   }
 
@@ -210,13 +216,13 @@
   }
 
   mutable MatrixType *typ;
-  mutable idx_vector *idx_cache;
+  mutable octave::idx_vector *idx_cache;
 
 private:
 
   // No assignment.
 
-  octave_base_matrix& operator = (const octave_base_matrix&);
+  OCTINTERP_API octave_base_matrix& operator = (const octave_base_matrix&);
 };
 
 #endif
--- a/libinterp/octave-value/ov-base-scalar.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-scalar.h	Sun May 16 09:44:35 2021 +0200
@@ -45,10 +45,13 @@
 
 template <typename ST>
 class
+OCTINTERP_API
 octave_base_scalar : public octave_base_value
 {
 public:
 
+  typedef ST scalar_type;
+
   octave_base_scalar (void)
     : octave_base_value (), scalar () { }
 
@@ -69,22 +72,22 @@
   // functions.
   using octave_base_value::subsref;
 
-  octave_value subsref (const std::string& type,
-                        const std::list<octave_value_list>& idx);
+  OCTINTERP_API octave_value
+  subsref (const std::string& type, const std::list<octave_value_list>& idx);
 
   octave_value_list subsref (const std::string& type,
                              const std::list<octave_value_list>& idx, int)
   { return subsref (type, idx); }
 
-  octave_value subsasgn (const std::string& type,
-                         const std::list<octave_value_list>& idx,
-                         const octave_value& rhs);
+  OCTINTERP_API octave_value
+  subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
+            const octave_value& rhs);
 
   bool is_constant (void) const { return true; }
 
   bool is_defined (void) const { return true; }
 
-  dim_vector dims (void) const;
+  OCTINTERP_API dim_vector dims (void) const;
 
   octave_idx_type numel (void) const { return 1; }
 
@@ -92,9 +95,9 @@
 
   octave_idx_type nnz (void) const { return (scalar != ST () ? 1 : 0); }
 
-  octave_value permute (const Array<int>&, bool = false) const;
+  OCTINTERP_API octave_value permute (const Array<int>&, bool = false) const;
 
-  octave_value reshape (const dim_vector& new_dims) const;
+  OCTINTERP_API octave_value reshape (const dim_vector& new_dims) const;
 
   std::size_t byte_size (void) const { return sizeof (ST); }
 
@@ -102,9 +105,9 @@
 
   octave_value any (int = 0) const { return (scalar != ST ()); }
 
-  octave_value diag (octave_idx_type k = 0) const;
+  OCTINTERP_API octave_value diag (octave_idx_type k = 0) const;
 
-  octave_value diag (octave_idx_type m, octave_idx_type n) const;
+  OCTINTERP_API octave_value diag (octave_idx_type m, octave_idx_type n) const;
 
   octave_value sort (octave_idx_type, sortmode) const
   { return octave_value (scalar); }
@@ -136,20 +139,23 @@
 
   bool isnumeric (void) const { return true; }
 
-  bool is_true (void) const;
+  OCTINTERP_API bool is_true (void) const;
 
-  void print (std::ostream& os, bool pr_as_read_syntax = false);
+  OCTINTERP_API void print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+  OCTINTERP_API void
+  print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  bool print_name_tag (std::ostream& os, const std::string& name) const;
+  OCTINTERP_API bool
+  print_name_tag (std::ostream& os, const std::string& name) const;
 
-  void short_disp (std::ostream& os) const;
+  OCTINTERP_API void short_disp (std::ostream& os) const;
 
-  float_display_format get_edit_display_format (void) const;
+  OCTINTERP_API float_display_format get_edit_display_format (void) const;
 
-  std::string edit_display (const float_display_format& fmt,
-                            octave_idx_type i, octave_idx_type j) const;
+  OCTINTERP_API std::string
+  edit_display (const float_display_format& fmt,
+                octave_idx_type i, octave_idx_type j) const;
 
   // Unsafe.  This function exists to support the MEX interface.
   // You should not use it anywhere else.
@@ -159,9 +165,10 @@
 
   ST& scalar_ref (void) { return scalar; }
 
-  octave_value fast_elem_extract (octave_idx_type n) const;
+  OCTINTERP_API octave_value fast_elem_extract (octave_idx_type n) const;
 
-  bool fast_elem_insert_self (void *where, builtin_type_t btyp) const;
+  OCTINTERP_API bool
+  fast_elem_insert_self (void *where, builtin_type_t btyp) const;
 
 protected:
 
--- a/libinterp/octave-value/ov-base-sparse.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-sparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -75,7 +75,7 @@
 
         case 1:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             retval = octave_value (matrix.index (i, resize_ok));
           }
@@ -83,10 +83,10 @@
 
         case 2:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             k = 1;
-            idx_vector j = idx (1).index_vector ();
+            octave::idx_vector j = idx (1).index_vector ();
 
             retval = octave_value (matrix.index (i, j, resize_ok));
           }
@@ -96,10 +96,10 @@
           error ("sparse indexing needs 1 or 2 indices");
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (n_idx, k+1);
+      ie.set_pos_if_unset (n_idx, k+1);
       throw;
     }
 
@@ -198,7 +198,7 @@
         {
         case 1:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             matrix.assign (i, rhs);
 
@@ -207,10 +207,10 @@
 
         case 2:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             k = 1;
-            idx_vector j = idx (1).index_vector ();
+            octave::idx_vector j = idx (1).index_vector ();
 
             matrix.assign (i, j, rhs);
 
@@ -221,10 +221,10 @@
           error ("sparse indexing needs 1 or 2 indices");
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (len, k+1);
+      ie.set_pos_if_unset (len, k+1);
       throw;
     }
 
@@ -250,7 +250,7 @@
         {
         case 1:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             matrix.delete_elements (i);
 
@@ -259,10 +259,10 @@
 
         case 2:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             k = 1;
-            idx_vector j = idx (1).index_vector ();
+            octave::idx_vector j = idx (1).index_vector ();
 
             matrix.delete_elements (i, j);
 
@@ -273,10 +273,10 @@
           error ("sparse indexing needs 1 or 2 indices");
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (len, k+1);
+      ie.set_pos_if_unset (len, k+1);
       throw;
     }
 
--- a/libinterp/octave-value/ov-base-sparse.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base-sparse.h	Sun May 16 09:44:35 2021 +0200
@@ -47,6 +47,7 @@
 
 template <typename T>
 class
+OCTINTERP_API
 octave_base_sparse : public octave_base_value
 {
 public:
@@ -91,16 +92,16 @@
   // functions.
   using octave_base_value::subsref;
 
-  octave_value subsref (const std::string& type,
-                        const std::list<octave_value_list>& idx);
+  OCTINTERP_API octave_value
+  subsref (const std::string& type, const std::list<octave_value_list>& idx);
 
   octave_value_list subsref (const std::string& type,
                              const std::list<octave_value_list>& idx, int)
   { return subsref (type, idx); }
 
-  octave_value subsasgn (const std::string& type,
-                         const std::list<octave_value_list>& idx,
-                         const octave_value& rhs);
+  OCTINTERP_API octave_value
+  subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
+            const octave_value& rhs);
 
   // FIXME: should we import the functions from the base class and
   // overload them here, or should we use a different name so we don't
@@ -109,14 +110,14 @@
   // can also cause some confusion.
   using octave_base_value::assign;
 
-  void assign (const octave_value_list& idx, const T& rhs);
+  OCTINTERP_API void assign (const octave_value_list& idx, const T& rhs);
 
-  void delete_elements (const octave_value_list& idx);
+  OCTINTERP_API void delete_elements (const octave_value_list& idx);
 
   dim_vector dims (void) const { return matrix.dims (); }
 
-  octave_value do_index_op (const octave_value_list& idx,
-                            bool resize_ok = false);
+  OCTINTERP_API octave_value
+  do_index_op (const octave_value_list& idx, bool resize_ok = false);
 
   octave_value reshape (const dim_vector& new_dims) const
   { return T (matrix.reshape (new_dims)); }
@@ -124,7 +125,7 @@
   octave_value permute (const Array<int>& vec, bool inv = false) const
   { return T (matrix.permute (vec, inv)); }
 
-  octave_value resize (const dim_vector& dv, bool = false) const;
+  OCTINTERP_API octave_value resize (const dim_vector& dv, bool = false) const;
 
   octave_value all (int dim = 0) const { return matrix.all (dim); }
   octave_value any (int dim = 0) const { return matrix.any (dim); }
@@ -160,24 +161,27 @@
 
   bool is_constant (void) const { return true; }
 
-  bool is_true (void) const;
+  OCTINTERP_API bool is_true (void) const;
 
-  bool print_as_scalar (void) const;
+  OCTINTERP_API bool print_as_scalar (void) const;
 
-  void print (std::ostream& os, bool pr_as_read_syntax = false);
+  OCTINTERP_API void print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  void print_info (std::ostream& os, const std::string& prefix) const;
+  OCTINTERP_API void
+  print_info (std::ostream& os, const std::string& prefix) const;
 
-  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+  OCTINTERP_API void
+  print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  bool save_ascii (std::ostream& os);
+  OCTINTERP_API bool save_ascii (std::ostream& os);
 
-  bool load_ascii (std::istream& is);
+  OCTINTERP_API bool load_ascii (std::istream& is);
+
+  OCTINTERP_API float_display_format get_edit_display_format (void) const;
 
-  float_display_format get_edit_display_format (void) const;
-
-  std::string edit_display (const float_display_format& fmt,
-                            octave_idx_type i, octave_idx_type j) const;
+  OCTINTERP_API std::string
+  edit_display (const float_display_format& fmt,
+                octave_idx_type i, octave_idx_type j) const;
 
   // Unsafe.  These functions exists to support the MEX interface.
   // You should not use them anywhere else.
@@ -187,11 +191,12 @@
 
   octave_idx_type * mex_get_jc (void) const { return matrix.mex_get_jc (); }
 
-  octave_value fast_elem_extract (octave_idx_type n) const;
+  OCTINTERP_API octave_value fast_elem_extract (octave_idx_type n) const;
 
 protected:
 
-  octave_value map (octave_base_value::unary_mapper_t umap) const;
+  OCTINTERP_API octave_value
+  map (octave_base_value::unary_mapper_t umap) const;
 
   T matrix;
 
--- a/libinterp/octave-value/ov-base.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base.cc	Sun May 16 09:44:35 2021 +0200
@@ -86,13 +86,13 @@
   return retval;
 }
 
-std::string btyp_class_name[btyp_num_types] =
+std::string btyp_class_name[btyp_num_types+1] =
 {
   "double", "single", "double", "single",
   "int8", "int16", "int32", "int64",
   "uint8", "uint16", "uint32", "uint64",
   "logical", "char",
-  "struct", "cell", "function_handle"
+  "struct", "cell", "function_handle", "unknown"
 };
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_base_value,
@@ -229,7 +229,7 @@
   error ("can't perform indexing operations for %s type", nm.c_str ());
 }
 
-idx_vector
+octave::idx_vector
 octave_base_value::index_vector (bool /* require_integers */) const
 {
   std::string nm = '<' + type_name () + '>';
@@ -470,9 +470,9 @@
       {                                                                 \
         d = double_value (frc_str_conv);                                \
       }                                                                 \
-    catch (octave::execution_exception& e)                               \
+    catch (octave::execution_exception& ee)                               \
       {                                                                 \
-        err_wrong_type_arg (e, "octave_base_value::" #F "_value ()", type_name ()); \
+        err_wrong_type_arg (ee, "octave_base_value::" #F "_value ()", type_name ()); \
       }                                                                 \
                                                                         \
     if (require_int && octave::math::x_nint (d) != d)                   \
@@ -508,9 +508,9 @@
     {
       d = double_value (frc_str_conv);
     }
-  catch (octave::execution_exception& e)
+  catch (octave::execution_exception& ee)
     {
-      err_wrong_type_arg (e, "octave_base_value::nint_value ()", type_name ());
+      err_wrong_type_arg (ee, "octave_base_value::nint_value ()", type_name ());
     }
 
   if (octave::math::isnan (d))
@@ -811,12 +811,66 @@
   err_wrong_type_arg ("octave_base_value::cellstr_value()", type_name ());
 }
 
-Range
+octave::range<float>
+octave_base_value::float_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::float_range_value()", type_name ());
+}
+
+octave::range<double>
 octave_base_value::range_value (void) const
 {
   err_wrong_type_arg ("octave_base_value::range_value()", type_name ());
 }
 
+octave::range<octave_int8>
+octave_base_value::int8_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::int8_range_value()", type_name ());
+}
+
+octave::range<octave_int16>
+octave_base_value::int16_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::int16_range_value()", type_name ());
+}
+
+octave::range<octave_int32>
+octave_base_value::int32_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::int32_range_value()", type_name ());
+}
+
+octave::range<octave_int64>
+octave_base_value::int64_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::int64_range_value()", type_name ());
+}
+
+octave::range<octave_uint8>
+octave_base_value::uint8_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::uint8_range_value()", type_name ());
+}
+
+octave::range<octave_uint16>
+octave_base_value::uint16_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::uint16_range_value()", type_name ());
+}
+
+octave::range<octave_uint32>
+octave_base_value::uint32_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::uint32_range_value()", type_name ());
+}
+
+octave::range<octave_uint64>
+octave_base_value::uint64_range_value (void) const
+{
+  err_wrong_type_arg ("octave_base_value::uint64_range_value()", type_name ());
+}
+
 octave_map
 octave_base_value::map_value (void) const
 {
@@ -965,7 +1019,7 @@
 }
 
 mxArray *
-octave_base_value::as_mxArray (void) const
+octave_base_value::as_mxArray (bool) const
 {
   return nullptr;
 }
--- a/libinterp/octave-value/ov-base.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-base.h	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
   // interpreter-private.h here and bringing in a lot of unnecessary
   // symbols that require even more header files.
 
-  extern type_info& __get_type_info__ (const std::string&);
+  extern OCTINTERP_API type_info& __get_type_info__ (const std::string&);
 }
 
 class Cell;
@@ -93,8 +93,7 @@
   btyp_num_types = btyp_unknown
 };
 
-extern OCTINTERP_API std::string
-btyp_class_name [btyp_num_types];
+extern OCTINTERP_API std::string btyp_class_name [];
 
 inline bool btyp_isnumeric (builtin_type_t btyp)
 { return btyp <= btyp_uint64; }
@@ -130,27 +129,40 @@
   static const builtin_type_t btyp = btyp_unknown;
 };
 
-#define DEF_CLASS_TO_BTYP(CLASS,BTYP)           \
+template <builtin_type_t BTYP>
+struct btyp_to_class
+{
+  typedef void type;
+};
+
+#define DEF_BTYP_TRAITS(BTYP, CLASS)            \
   template <>                                   \
   struct class_to_btyp<CLASS>                   \
   {                                             \
     static const builtin_type_t btyp = BTYP;    \
+  };                                            \
+                                                \
+  template <>                                   \
+  struct btyp_to_class<BTYP>                    \
+  {                                             \
+    typedef CLASS type;                         \
   }
 
-DEF_CLASS_TO_BTYP (double, btyp_double);
-DEF_CLASS_TO_BTYP (float, btyp_float);
-DEF_CLASS_TO_BTYP (Complex, btyp_complex);
-DEF_CLASS_TO_BTYP (FloatComplex, btyp_float_complex);
-DEF_CLASS_TO_BTYP (octave_int8, btyp_int8);
-DEF_CLASS_TO_BTYP (octave_int16, btyp_int16);
-DEF_CLASS_TO_BTYP (octave_int32, btyp_int32);
-DEF_CLASS_TO_BTYP (octave_int64, btyp_int64);
-DEF_CLASS_TO_BTYP (octave_uint8, btyp_uint8);
-DEF_CLASS_TO_BTYP (octave_uint16, btyp_uint16);
-DEF_CLASS_TO_BTYP (octave_uint32, btyp_uint32);
-DEF_CLASS_TO_BTYP (octave_uint64, btyp_uint64);
-DEF_CLASS_TO_BTYP (bool, btyp_bool);
-DEF_CLASS_TO_BTYP (char, btyp_char);
+DEF_BTYP_TRAITS (btyp_double, double);
+DEF_BTYP_TRAITS (btyp_float, float);
+DEF_BTYP_TRAITS (btyp_complex, Complex);
+DEF_BTYP_TRAITS (btyp_float_complex, FloatComplex);
+DEF_BTYP_TRAITS (btyp_int8, octave_int8);
+DEF_BTYP_TRAITS (btyp_int16, octave_int16);
+DEF_BTYP_TRAITS (btyp_int32, octave_int32);
+DEF_BTYP_TRAITS (btyp_int64, octave_int64);
+DEF_BTYP_TRAITS (btyp_uint8, octave_uint8);
+DEF_BTYP_TRAITS (btyp_uint16, octave_uint16);
+DEF_BTYP_TRAITS (btyp_uint32, octave_uint32);
+DEF_BTYP_TRAITS (btyp_uint64, octave_uint64);
+DEF_BTYP_TRAITS (btyp_bool, bool);
+DEF_BTYP_TRAITS (btyp_char, char);
+
 
 // T_ID is the type id of struct objects, set by register_type().
 // T_NAME is the type name of struct objects.
@@ -179,22 +191,35 @@
     static const std::string t_name;                                    \
     static const std::string c_name;
 
+#define DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS(cls, type)           \
+  template <> void cls<type>::register_type (void);                     \
+  template <> void cls<type>::register_type (octave::type_info&);       \
+  template <> int cls<type>::t_id;                                      \
+  template <> const std::string cls<type>::t_name;                      \
+  template <> const std::string cls<type>::c_name;
+
+#define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA_INTERNAL(tspec, t, n, c)    \
+  tspec int t::t_id (-1);                                               \
+  tspec const std::string t::t_name (n);                                \
+  tspec const std::string t::c_name (c);                                \
+  tspec void t::register_type (void)                                    \
+  {                                                                     \
+    octave::type_info& type_info                                        \
+      = octave::__get_type_info__ (#t "::register_type");               \
+                                                                        \
+    register_type (type_info);                                          \
+  }                                                                     \
+  tspec void t::register_type (octave::type_info& ti)                   \
+  {                                                                     \
+    octave_value v (new t ());                                          \
+    t_id = ti.register_type (t::t_name, t::c_name, v);                  \
+  }
+
+#define DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)           \
+  DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA_INTERNAL (template <>, t, n, c)
+
 #define DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(t, n, c)            \
-  int t::t_id (-1);                                             \
-  const std::string t::t_name (n);                              \
-  const std::string t::c_name (c);                              \
-  void t::register_type (void)                                  \
-  {                                                             \
-    octave::type_info& type_info                                \
-      = octave::__get_type_info__ (#t "::register_type");       \
-                                                                \
-    register_type (type_info);                                  \
-  }                                                             \
-  void t::register_type (octave::type_info& ti)                 \
-  {                                                             \
-    octave_value v (new t ());                                  \
-    t_id = ti.register_type (t::t_name, t::c_name, v);          \
-  }
+  DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA_INTERNAL ( , t, n, c)
 
 // A base value type, so that derived types only have to redefine what
 // they need (if they are derived from octave_base_value instead of
@@ -315,7 +340,7 @@
                   const std::list<octave_value_list>& idx,
                   const octave_value& rhs);
 
-  virtual idx_vector index_vector (bool require_integers = false) const;
+  virtual octave::idx_vector index_vector (bool require_integers = false) const;
 
   virtual dim_vector dims (void) const { return dim_vector (); }
 
@@ -358,6 +383,8 @@
 
   virtual bool is_defined (void) const { return false; }
 
+  virtual bool is_storable (void) const { return true; }
+
   bool isempty (void) const { return (dims ().any_zero ()); }
 
   bool is_zero_by_zero (void) const { return dims().zero_by_zero (); }
@@ -458,6 +485,8 @@
 
   virtual bool is_true (void) const { return false; }
 
+  virtual bool is_magic_int (void) const { return false; }
+
   virtual bool isnull (void) const { return false; }
 
   virtual bool is_constant (void) const { return false; }
@@ -599,7 +628,25 @@
 
   virtual Array<std::string> cellstr_value (void) const;
 
-  virtual Range range_value (void) const;
+  virtual octave::range<float> float_range_value (void) const;
+
+  virtual octave::range<double> range_value (void) const;
+
+  virtual octave::range<octave_int8> int8_range_value (void) const;
+
+  virtual octave::range<octave_int16> int16_range_value (void) const;
+
+  virtual octave::range<octave_int32> int32_range_value (void) const;
+
+  virtual octave::range<octave_int64> int64_range_value (void) const;
+
+  virtual octave::range<octave_uint8> uint8_range_value (void) const;
+
+  virtual octave::range<octave_uint16> uint16_range_value (void) const;
+
+  virtual octave::range<octave_uint32> uint32_range_value (void) const;
+
+  virtual octave::range<octave_uint64> uint64_range_value (void) const;
 
   virtual octave_map map_value (void) const;
 
@@ -698,7 +745,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;
 
@@ -835,9 +882,10 @@
 
   // This should only be called for derived types.
 
-  octave_value numeric_assign (const std::string& type,
-                               const std::list<octave_value_list>& idx,
-                               const octave_value& rhs);
+  OCTINTERP_API octave_value
+  numeric_assign (const std::string& type,
+                  const std::list<octave_value_list>& idx,
+                  const octave_value& rhs);
 
   void reset_indent_level (void) const
   { curr_print_indent_level = 0; }
@@ -851,11 +899,11 @@
   int current_print_indent_level (void) const
   { return curr_print_indent_level; }
 
-  void indent (std::ostream& os) const;
+  OCTINTERP_API void indent (std::ostream& os) const;
 
-  void newline (std::ostream& os) const;
+  OCTINTERP_API void newline (std::ostream& os) const;
 
-  void reset (void) const;
+  OCTINTERP_API void reset (void) const;
 
   // A reference count.
   // NOTE: the declaration is octave_idx_type because with 64-bit indexing,
@@ -863,14 +911,14 @@
   // (think of an empty cell array with >2G elements).
   octave::refcount<octave_idx_type> count;
 
-  static const char * get_umap_name (unary_mapper_t);
+  OCTINTERP_API static const char * get_umap_name (unary_mapper_t);
 
-  void warn_load (const char *type) const;
-  void warn_save (const char *type) const;
+  OCTINTERP_API void warn_load (const char *type) const;
+  OCTINTERP_API void warn_save (const char *type) const;
 
 private:
 
-  void wrong_type_arg_error (void) const;
+  OCTINTERP_API void wrong_type_arg_error (void) const;
 
   static int curr_print_indent_level;
   static bool beginning_of_line;
--- a/libinterp/octave-value/ov-bool-mat.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-bool-mat.cc	Sun May 16 09:44:35 2021 +0200
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-bool-mat.h	Sun May 16 09:44:35 2021 +0200
@@ -68,7 +68,7 @@
   octave_bool_matrix (const boolMatrix& bm, const MatrixType& t)
     : octave_base_matrix<boolNDArray> (bm, t) { }
 
-  octave_bool_matrix (const boolNDArray& bm, const idx_vector& cache)
+  octave_bool_matrix (const boolNDArray& bm, const octave::idx_vector& cache)
     : octave_base_matrix<boolNDArray> (bm)
   {
     set_idx_cache (cache);
@@ -89,9 +89,9 @@
 
   octave_base_value * try_narrowing_conversion (void);
 
-  idx_vector index_vector (bool /* require_integers */ = false) const
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
   {
-    return idx_cache ? *idx_cache : set_idx_cache (idx_vector (matrix));
+    return idx_cache ? *idx_cache : set_idx_cache (octave::idx_vector (matrix));
   }
 
   builtin_type_t builtin_type (void) const { return btyp_bool; }
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-bool-sparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 #include "ov-base-sparse.h"
 #include "ov-base-sparse.cc"
 
-template class OCTINTERP_API octave_base_sparse<SparseBoolMatrix>;
+template class octave_base_sparse<SparseBoolMatrix>;
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_sparse_bool_matrix,
                                      "sparse bool matrix", "logical");
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-bool-sparse.h	Sun May 16 09:44:35 2021 +0200
@@ -87,9 +87,9 @@
   octave_base_value * try_narrowing_conversion (void);
 
   // FIXME: Adapt idx_vector to allow sparse logical indexing without overflow!
-  idx_vector index_vector (bool /* require_integers */ = false) const
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
   {
-    return idx_vector (matrix);
+    return octave::idx_vector (matrix);
   }
 
   builtin_type_t builtin_type (void) const { return btyp_bool; }
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-bool.cc	Sun May 16 09:44:35 2021 +0200
@@ -54,7 +54,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_scalar<bool>;
 
@@ -91,7 +91,7 @@
 
   octave_value tmp (new octave_bool_matrix (bool_matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 octave_value
@@ -188,7 +188,7 @@
 {
   double d = double_value ();
 
-  octave_write_double (os, d);
+  octave::write_value<double> (os, d);
   os << "\n";
 
   return true;
@@ -197,7 +197,7 @@
 bool
 octave_bool::load_ascii (std::istream& is)
 {
-  scalar = (octave_read_value<double> (is) != 0.0);
+  scalar = (octave::read_value<double> (is) != 0.0);
 
   if (! is)
     error ("load: failed to load scalar constant");
@@ -233,7 +233,7 @@
 
 #if defined (HAVE_HDF5)
 
-  hsize_t dimens[3];
+  hsize_t dimens[3] = {0};
   hid_t space_hid, data_hid;
   space_hid = data_hid = -1;
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-bool.h	Sun May 16 09:44:35 2021 +0200
@@ -74,7 +74,8 @@
   octave_value do_index_op (const octave_value_list& idx,
                             bool resize_ok = false);
 
-  idx_vector index_vector (bool /* require_integers */ = false) const { return idx_vector (scalar); }
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
+  { return octave::idx_vector (scalar); }
 
   builtin_type_t builtin_type (void) const { return btyp_bool; }
 
@@ -246,7 +247,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-builtin.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-builtin.cc	Sun May 16 09:44:35 2021 +0200
@@ -55,14 +55,14 @@
 
   octave::profiler::enter<octave_builtin> block (profiler, *this);
 
-  if (f)
-    retval = (*f) (args, nargout);
+  if (m_fcn)
+    retval = (*m_fcn) (args, nargout);
   else
     {
       octave::interpreter& interp
         = octave::__get_interpreter__ ("octave_builtin::call");
 
-      retval = (*m) (interp, args, nargout);
+      retval = (*m_meth) (interp, args, nargout);
     }
 
   // Do not allow null values to be returned from functions.
@@ -90,35 +90,35 @@
 octave::jit_type *
 octave_builtin::to_jit (void) const
 {
-  return jtype;
+  return m_jtype;
 }
 
 void
 octave_builtin::stash_jit (octave::jit_type& type)
 {
-  jtype = &type;
+  m_jtype = &type;
 }
 
 octave_builtin::fcn
 octave_builtin::function (void) const
 {
-  return f;
+  return m_fcn;
 }
 
 octave_builtin::meth
 octave_builtin::method (void) const
 {
-  return m;
+  return m_meth;
 }
 
 void
 octave_builtin::push_dispatch_class (const std::string& dispatch_type)
 {
-  dispatch_classes.insert (dispatch_type);
+  m_dispatch_classes.insert (dispatch_type);
 }
 
 bool
 octave_builtin::handles_dispatch_class (const std::string& dispatch_type) const
 {
-  return dispatch_classes.find (dispatch_type) != dispatch_classes.end ();
+  return m_dispatch_classes.find (dispatch_type) != m_dispatch_classes.end ();
 }
--- a/libinterp/octave-value/ov-builtin.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-builtin.h	Sun May 16 09:44:35 2021 +0200
@@ -53,8 +53,9 @@
 {
 public:
 
-  octave_builtin (void) : octave_function (), f (nullptr), m (nullptr),
-                          file (), jtype (nullptr)
+  octave_builtin (void)
+    : octave_function (), m_fcn (nullptr), m_meth (nullptr), m_file (),
+      m_jtype (nullptr)
   { }
 
   typedef octave_value_list (*meth) (octave::interpreter&,
@@ -64,22 +65,26 @@
 
   octave_builtin (fcn ff, const std::string& nm = "",
                   const std::string& ds = "")
-    : octave_function (nm, ds), f (ff), m (nullptr), file (), jtype (nullptr)
+    : octave_function (nm, ds), m_fcn (ff), m_meth (nullptr), m_file (),
+      m_jtype (nullptr)
   { }
 
   octave_builtin (meth mm, const std::string& nm = "",
                   const std::string& ds = "")
-    : octave_function (nm, ds), f (nullptr), m (mm), file (), jtype (nullptr)
+    : octave_function (nm, ds), m_fcn (nullptr), m_meth (mm), m_file (),
+      m_jtype (nullptr)
   { }
 
   octave_builtin (fcn ff, const std::string& nm, const std::string& fnm,
                   const std::string& ds)
-    : octave_function (nm, ds), f (ff), m (nullptr), file (fnm), jtype (nullptr)
+    : octave_function (nm, ds), m_fcn (ff), m_meth (nullptr), m_file (fnm),
+      m_jtype (nullptr)
   { }
 
   octave_builtin (meth mm, const std::string& nm, const std::string& fnm,
                   const std::string& ds)
-    : octave_function (nm, ds), f (nullptr), m (mm), file (fnm), jtype (nullptr)
+    : octave_function (nm, ds), m_fcn (nullptr), m_meth (mm), m_file (fnm),
+      m_jtype (nullptr)
   { }
 
   // No copying!
@@ -90,7 +95,7 @@
 
   ~octave_builtin (void) = default;
 
-  std::string src_file_name (void) const { return file; }
+  std::string src_file_name (void) const { return m_file; }
 
   octave_function * function_value (bool = false) { return this; }
 
@@ -115,17 +120,17 @@
 protected:
 
   // A pointer to the actual function.
-  fcn f;
-  meth m;
+  fcn m_fcn;
+  meth m_meth;
 
   // The name of the file where this function was defined.
-  std::string file;
+  std::string m_file;
 
   // The types this function has been declared to handle (if any).
-  std::set<std::string> dispatch_classes;
+  std::set<std::string> m_dispatch_classes;
 
   // A pointer to the jit type that represents the function.
-  octave::jit_type *jtype;
+  octave::jit_type *m_jtype;
 
 private:
 
--- a/libinterp/octave-value/ov-cell.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-cell.cc	Sun May 16 09:44:35 2021 +0200
@@ -166,7 +166,7 @@
     case '{':
       {
         if (idx.front ().empty ())
-          error ("invalid empty index expression");
+          error ("invalid empty index expression {}, use {:} instead");
 
         octave_value tmp = do_index_op (idx.front ());
 
@@ -1282,7 +1282,7 @@
 /*
 ## This might work on some system someday, but for now, who has a system
 ## where a 16 yottabyte array can be allocated?  See bug #50934.
-%!error <out of memory> cell (1e24, 1);
+%!error <out of memory> cell (1e24, 1)
 */
 
 DEFUN (iscellstr, args, ,
@@ -1413,9 +1413,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 ());
 
@@ -1424,7 +1424,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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-cell.h	Sun May 16 09:44:35 2021 +0200
@@ -174,7 +174,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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-ch-mat.cc	Sun May 16 09:44:35 2021 +0200
@@ -57,14 +57,14 @@
 
 template class octave_base_matrix<charNDArray>;
 
-idx_vector
+octave::idx_vector
 octave_char_matrix::index_vector (bool /* require_integers */) const
 {
   const char *p = matrix.data ();
   if (numel () == 1 && *p == ':')
-    return idx_vector (':');
+    return octave::idx_vector (':');
   else
-    return idx_vector (array_value (true));
+    return octave::idx_vector (array_value (true));
 }
 
 double
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-ch-mat.h	Sun May 16 09:44:35 2021 +0200
@@ -89,7 +89,7 @@
   octave_base_value * empty_clone (void) const
   { return new octave_char_matrix (); }
 
-  idx_vector index_vector (bool require_integers = false) const;
+  octave::idx_vector index_vector (bool require_integers = false) const;
 
   builtin_type_t builtin_type (void) const { return btyp_char; }
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-class.cc	Sun May 16 09:44:35 2021 +0200
@@ -75,7 +75,7 @@
 
 octave_class::octave_class (const octave_map& m, const std::string& id,
                             const octave_value_list& parents)
-  : octave_base_value (), map (m), c_name (id), obsolete_copies (0)
+  : octave_base_value (), m_map (m), c_name (id), m_obsolete_copies (0)
 {
   octave_idx_type n = parents.length ();
 
@@ -91,9 +91,9 @@
       if (find_parent_class (pcnm))
         error ("duplicate class in parent tree");
 
-      parent_list.push_back (pcnm);
-
-      octave_idx_type nel = map.numel ();
+      m_parent_list.push_back (pcnm);
+
+      octave_idx_type nel = m_map.numel ();
       octave_idx_type p_nel = parent.numel ();
 
       if (nel == 0)
@@ -103,20 +103,20 @@
               // No elements in MAP or the parent class object,
               // so just add the field name.
 
-              map.assign (pcnm, Cell (map.dims ()));
+              m_map.assign (pcnm, Cell (m_map.dims ()));
             }
           else if (p_nel == 1)
             {
-              if (map.nfields () == 0)
+              if (m_map.nfields () == 0)
                 {
                   // No elements or fields in MAP, but the
                   // parent is class object with one element.
                   // Resize to match size of parent class and
                   // make the parent a field in MAP.
 
-                  map.resize (parent.dims ());
-
-                  map.assign (pcnm, parent);
+                  m_map.resize (parent.dims ());
+
+                  m_map.assign (pcnm, parent);
                 }
               else
                 {
@@ -124,10 +124,10 @@
                   // one field.  So don't resize, just add the
                   // field name.
 
-                  map.assign (pcnm, Cell (map.dims ()));
+                  m_map.assign (pcnm, Cell (m_map.dims ()));
                 }
             }
-          else if (map.nfields () == 0)
+          else if (m_map.nfields () == 0)
             {
               // No elements or fields in MAP and more than one
               // element in the parent class object, so we can
@@ -137,7 +137,7 @@
 
               dim_vector parent_dims = parent.dims ();
 
-              map.resize (parent_dims);
+              m_map.resize (parent_dims);
 
               Cell c (parent_dims);
 
@@ -149,7 +149,7 @@
               for (octave_idx_type i = 0; i < p_nel; i++)
                 c(i) = octave_value (pmap.index (i), pcnm, plist);
 
-              map.assign (pcnm, c);
+              m_map.assign (pcnm, c);
             }
           else
             error ("class: parent class dimension mismatch");
@@ -158,7 +158,7 @@
         {
           // Simple assignment.
 
-          map.assign (pcnm, parent);
+          m_map.assign (pcnm, parent);
         }
       else
         {
@@ -167,9 +167,9 @@
               // Broadcast the scalar parent class object to
               // each element of MAP.
 
-              Cell pcell (map.dims (), parent);
-
-              map.assign (pcnm, pcell);
+              Cell pcell (m_map.dims (), parent);
+
+              m_map.assign (pcnm, pcell);
             }
           else if (nel == p_nel)
             {
@@ -193,7 +193,7 @@
               for (octave_idx_type i = 0; i < p_nel; i++)
                 c(i) = octave_value (pmap.index (i), pcnm, plist);
 
-              map.assign (pcnm, c);
+              m_map.assign (pcnm, c);
             }
           else
             error ("class: parent class dimension mismatch");
@@ -202,13 +202,13 @@
 
   octave::symbol_table& symtab = octave::__get_symbol_table__ ("octave_class");
 
-  symtab.add_to_parent_map (id, parent_list);
+  symtab.add_to_parent_map (id, m_parent_list);
 }
 
 octave_base_value *
 octave_class::unique_clone (void)
 {
-  if (count == obsolete_copies)
+  if (count == m_obsolete_copies)
     {
       // All remaining copies are obsolete.  We don't actually need to clone.
       count++;
@@ -217,8 +217,8 @@
   else
     {
       // In theory, this shouldn't be happening, but it's here just in case.
-      if (count < obsolete_copies)
-        obsolete_copies = 0;
+      if (count < m_obsolete_copies)
+        m_obsolete_copies = 0;
 
       return clone ();
     }
@@ -269,9 +269,9 @@
 void
 octave_class::break_closure_cycles (const std::shared_ptr<octave::stack_frame>& frame)
 {
-  for (octave_idx_type j = 0; j < map.nfields (); j++)
+  for (octave_idx_type j = 0; j < m_map.nfields (); j++)
     {
-      Cell& c = map.contents (j);
+      Cell& c = m_map.contents (j);
 
       for (octave_idx_type i = 0; i < c.numel (); i++)
         c(i).break_closure_cycles (frame);
@@ -293,7 +293,7 @@
   if (obvp == nullptr)
     error ("malformed class");
 
-  octave_map my_map = (obvp != this) ? obvp->map_value () : map;
+  octave_map my_map = (obvp != this) ? obvp->map_value () : m_map;
 
   std::string nm = idx(0).xstring_value ("invalid index for class");
 
@@ -417,14 +417,14 @@
                 skip++;
               }
             else
-              retval(0) = octave_value (map.index (idx.front ()),
-                                        c_name, parent_list);
+              retval(0) = octave_value (m_map.index (idx.front ()),
+                                        c_name, m_parent_list);
           }
           break;
 
         case '.':
           {
-            if (map.numel () > 0)
+            if (m_map.numel () > 0)
               {
                 Cell t = dotref (idx.front ());
 
@@ -494,8 +494,8 @@
       else
         {
           if (type.length () == 1 && type[0] == '(')
-            retval(0) = octave_value (map.index (idx.front ()), c_name,
-                                      parent_list);
+            retval(0) = octave_value (m_map.index (idx.front ()), c_name,
+                                      m_parent_list);
           else
             err_invalid_index1 ();
         }
@@ -588,12 +588,11 @@
 
           octave_value_list tmp;
 
-          if (obsolete_copies == 0 && meth.is_user_function ()
+          if (m_obsolete_copies == 0 && meth.is_user_function ()
               && meth.user_function_value ()->subsasgn_optimization_ok ())
             {
-              octave::unwind_protect frame;
-              frame.protect_var (obsolete_copies);
-              obsolete_copies = 2;
+              octave::unwind_protect_var<int> restore_var (m_obsolete_copies);
+              m_obsolete_copies = 2;
 
               tmp = octave::feval (meth.function_value (), args);
             }
@@ -661,11 +660,11 @@
 
                 octave_value u;
 
-                if (! map.contains (key))
+                if (! m_map.contains (key))
                   u = octave_value::empty_conv (type.substr (2), rhs);
                 else
                   {
-                    Cell map_val = map.contents (key);
+                    Cell map_val = m_map.contents (key);
 
                     Cell map_elt = map_val.index (idx.front (), true);
 
@@ -704,11 +703,11 @@
             std::string next_type = type.substr (1);
 
             Cell tmpc (1, 1);
-            auto pkey = map.seek (key);
-            if (pkey != map.end ())
+            auto pkey = m_map.seek (key);
+            if (pkey != m_map.end ())
               {
-                map.contents (pkey).make_unique ();
-                tmpc = map.contents (pkey);
+                m_map.contents (pkey).make_unique ();
+                tmpc = m_map.contents (pkey);
               }
 
             // FIXME: better code reuse?
@@ -752,7 +751,7 @@
 
             std::string key = key_idx(0).xstring_value ("assignment to class element failed");
 
-            map.assign (idx.front (), key, t_rhs);
+            m_map.assign (idx.front (), key, t_rhs);
 
             count++;
             retval = octave_value (this);
@@ -763,7 +762,7 @@
               {
                 octave_map rhs_map = t_rhs.xmap_value ("invalid class assignment");
 
-                map.assign (idx.front (), rhs_map);
+                m_map.assign (idx.front (), rhs_map);
 
                 count++;
                 retval = octave_value (this);
@@ -773,7 +772,7 @@
                 if (! t_rhs.isempty ())
                   error ("invalid class assignment");
 
-                map.delete_elements (idx.front ());
+                m_map.delete_elements (idx.front ());
 
                 count++;
                 retval = octave_value (this);
@@ -801,13 +800,13 @@
             if (numel () == tmp_cell.numel ())
               tmp_cell = tmp_cell.reshape (dims ());
 
-            map.setfield (key, tmp_cell);
+            m_map.setfield (key, tmp_cell);
           }
         else
           {
             Cell tmp_cell(1, 1);
             tmp_cell(0) = t_rhs.storable_value ();
-            map.setfield (key, tmp_cell);
+            m_map.setfield (key, tmp_cell);
           }
 
         count++;
@@ -826,7 +825,7 @@
   return retval;
 }
 
-idx_vector
+octave::idx_vector
 octave_class::index_vector (bool require_integers) const
 {
   octave::symbol_table& symtab
@@ -839,7 +838,7 @@
            class_name ().c_str ());
 
   octave_value_list args;
-  args(0) = octave_value (new octave_class (map, c_name, parent_list));
+  args(0) = octave_value (new octave_class (m_map, c_name, m_parent_list));
 
   octave_value_list tmp = octave::feval (meth.function_value (), args, 1);
 
@@ -850,8 +849,8 @@
   // (why this inconsistency Mathworks?), and so we must
   // add one to the value returned as the index_vector method
   // expects it to be one based.
-  return do_binary_op (octave_value::op_add, tmp (0),
-                       octave_value (1.0)).index_vector (require_integers);
+  return octave::binary_op (octave_value::op_add, tmp (0),
+                               octave_value (1.0)).index_vector (require_integers);
 }
 
 std::size_t
@@ -861,11 +860,11 @@
 
   std::size_t retval = 0;
 
-  for (auto it = map.cbegin (); it != map.cend (); it++)
+  for (auto it = m_map.cbegin (); it != m_map.cend (); it++)
     {
-      std::string key = map.key (it);
-
-      octave_value val = octave_value (map.contents (it));
+      std::string key = m_map.key (it);
+
+      octave_value val = octave_value (m_map.contents (it));
 
       retval += val.byte_size ();
     }
@@ -909,11 +908,11 @@
     retval = this;
   else
     {
-      for (auto& par : parent_list)
+      for (auto& par : m_parent_list)
         {
-          octave_map::const_iterator smap = map.seek (par);
-
-          const Cell& tmp = map.contents (smap);
+          octave_map::const_iterator smap = m_map.seek (par);
+
+          const Cell& tmp = m_map.contents (smap);
 
           octave_value vtmp = tmp(0);
 
@@ -938,11 +937,11 @@
     retval = this;
   else
     {
-      for (auto& par : parent_list)
+      for (auto& par : m_parent_list)
         {
-          auto smap = map.seek (par);
-
-          Cell& tmp = map.contents (smap);
+          auto smap = m_map.seek (par);
+
+          Cell& tmp = m_map.contents (smap);
 
           octave_value& vtmp = tmp(0);
 
@@ -974,11 +973,11 @@
     retval = true;
   else
     {
-      for (auto& par : parent_list)
+      for (auto& par : m_parent_list)
         {
-          octave_map::const_iterator smap = map.seek (par);
-
-          const Cell& tmp = map.contents (smap);
+          octave_map::const_iterator smap = m_map.seek (par);
+
+          const Cell& tmp = m_map.contents (smap);
 
           const octave_value& vtmp = tmp(0);
 
@@ -1006,7 +1005,7 @@
     error ("no char method defined for class %s", class_name ().c_str ());
 
   octave_value_list args;
-  args(0) = octave_value (new octave_class (map, c_name, parent_list));
+  args(0) = octave_value (new octave_class (m_map, c_name, m_parent_list));
 
   octave_value_list tmp = octave::feval (meth.function_value (), args, 1);
 
@@ -1030,8 +1029,6 @@
 void
 octave_class::print_raw (std::ostream& os, bool) const
 {
-  octave::unwind_protect frame;
-
   indent (os);
   os << "  <class " << class_name () << '>';
   newline (os);
@@ -1128,10 +1125,10 @@
   std::string dbgstr = "dork";
 
   // First, check to see if there might be an issue with inheritance.
-  for (auto it = map.cbegin (); it != map.cend (); it++)
+  for (auto it = m_map.cbegin (); it != m_map.cend (); it++)
     {
-      std::string key = map.key (it);
-      Cell        val = map.contents (it);
+      std::string key = m_map.key (it);
+      Cell        val = m_map.contents (it);
       if (val(0).isobject ())
         {
           dbgstr = "blork";
@@ -1154,11 +1151,11 @@
       else
         {
           octave_class::exemplar_info exmplr = it->second;
-          parent_list = exmplr.parents ();
-          for (auto& par : parent_list)
+          m_parent_list = exmplr.parents ();
+          for (auto& par : m_parent_list)
             {
               dbgstr = par;
-              bool dbgbool = map.contains (par);
+              bool dbgbool = m_map.contains (par);
               if (! dbgbool)
                 {
                   retval = false;
@@ -1194,7 +1191,7 @@
   auto i = m.begin ();
   while (i != m.end ())
     {
-      octave_value val = map.contents (i);
+      octave_value val = m_map.contents (i);
 
       bool b = save_text_data (os, val, m.key (i), false, 0);
 
@@ -1221,7 +1218,7 @@
 
   if (len > 0)
     {
-      octave_map m (map);
+      octave_map m (m_map);
 
       for (octave_idx_type j = 0; j < len; j++)
         {
@@ -1246,7 +1243,7 @@
       c_name = classname;
       reconstruct_exemplar ();
 
-      map = m;
+      m_map = m;
 
       if (! reconstruct_parents ())
         warning ("load: unable to reconstruct object inheritance");
@@ -1258,12 +1255,12 @@
           octave_value in = new octave_class (*this);
           octave_value_list tmp = octave::feval ("loadobj", in, 1);
 
-          map = tmp(0).map_value ();
+          m_map = tmp(0).map_value ();
         }
     }
   else if (len == 0)
     {
-      map = octave_map (dim_vector (1, 1));
+      m_map = octave_map (dim_vector (1, 1));
       c_name = classname;
     }
   else
@@ -1300,7 +1297,7 @@
   auto i = m.begin ();
   while (i != m.end ())
     {
-      octave_value val = map.contents (i);
+      octave_value val = m_map.contents (i);
 
       bool b = save_binary_data (os, val, m.key (i), "", 0, save_as_floats);
 
@@ -1344,7 +1341,7 @@
 
   if (len > 0)
     {
-      octave_map m (map);
+      octave_map m (m_map);
 
       for (octave_idx_type j = 0; j < len; j++)
         {
@@ -1366,7 +1363,7 @@
 
       if (is)
         {
-          map = m;
+          m_map = m;
 
           if (! reconstruct_parents ())
             warning ("load: unable to reconstruct object inheritance");
@@ -1378,7 +1375,7 @@
               octave_value in = new octave_class (*this);
               octave_value_list tmp = octave::feval ("loadobj", in, 1);
 
-              map = tmp(0).map_value ();
+              m_map = tmp(0).map_value ();
             }
         }
       else
@@ -1388,7 +1385,7 @@
         }
     }
   else if (len == 0)
-    map = octave_map (dim_vector (1, 1));
+    m_map = octave_map (dim_vector (1, 1));
   else
     panic_impossible ();
 
@@ -1466,7 +1463,7 @@
   i = m.begin ();
   while (i != m.end ())
     {
-      octave_value val = map.contents (i);
+      octave_value val = m_map.contents (i);
 
       bool retval2 = add_hdf5_data (data_hid, val, m.key (i), "", false,
                                     save_as_floats);
@@ -1615,7 +1612,7 @@
 
   if (retval2 >= 0)
     {
-      map = m;
+      m_map = m;
 
       if (! reconstruct_parents ())
         warning ("load: unable to reconstruct object inheritance");
@@ -1627,7 +1624,7 @@
           octave_value in = new octave_class (*this);
           octave_value_list tmp = octave::feval ("loadobj", in, 1);
 
-          map = tmp(0).map_value ();
+          m_map = tmp(0).map_value ();
           retval = true;
         }
     }
@@ -1650,7 +1647,7 @@
 }
 
 mxArray *
-octave_class::as_mxArray (void) const
+octave_class::as_mxArray (bool) const
 {
   err_wrong_type_arg ("octave_class::as_mxArray ()", type_name ());
 }
@@ -1672,15 +1669,15 @@
 }
 
 octave_class::exemplar_info::exemplar_info (const octave_value& obj)
-  : field_names (), parent_class_names ()
+  : m_field_names (), m_parent_class_names ()
 {
   if (! obj.isobject ())
     error ("invalid call to exemplar_info constructor");
 
   octave_map m = obj.map_value ();
-  field_names = m.keys ();
-
-  parent_class_names = obj.parent_class_name_list ();
+  m_field_names = m.keys ();
+
+  m_parent_class_names = obj.parent_class_name_list ();
 }
 
 // A map from class names to lists of fields.
--- a/libinterp/octave-value/ov-class.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-class.h	Sun May 16 09:44:35 2021 +0200
@@ -55,46 +55,46 @@
 public:
 
   octave_class (void)
-    : octave_base_value (), map (), c_name (),
-      parent_list (), obsolete_copies (0)
+    : octave_base_value (), m_map (), c_name (),
+      m_parent_list (), m_obsolete_copies (0)
   { }
 
   octave_class (const octave_map& m, const std::string& id)
-    : octave_base_value (), map (m), c_name (id),
-      parent_list (), obsolete_copies (0)
+    : octave_base_value (), m_map (m), c_name (id),
+      m_parent_list (), m_obsolete_copies (0)
   { }
 
   octave_class (const octave_map& m, const std::string& id,
                 const std::list<std::string>& plist)
-    : octave_base_value (), map (m), c_name (id),
-      parent_list (plist), obsolete_copies (0)
+    : octave_base_value (), m_map (m), c_name (id),
+      m_parent_list (plist), m_obsolete_copies (0)
   { }
 
   octave_class (const octave_map& m, const std::string& id,
                 const octave_value_list& parents);
 
   octave_class (const octave_class& s)
-    : octave_base_value (s), map (s.map), c_name (s.c_name),
-      parent_list (s.parent_list), obsolete_copies (0)  { }
+    : octave_base_value (s), m_map (s.m_map), c_name (s.c_name),
+      m_parent_list (s.m_parent_list), m_obsolete_copies (0)  { }
 
   ~octave_class (void) = default;
 
   octave_base_value * clone (void) const { return new octave_class (*this); }
 
-  octave_base_value * unique_clone (void);
+  OCTINTERP_API octave_base_value * unique_clone (void);
 
   octave_base_value * empty_clone (void) const
   {
-    return new octave_class (octave_map (map.keys ()), c_name, parent_list);
+    return new octave_class (octave_map (m_map.keys ()), c_name, m_parent_list);
   }
 
   void break_closure_cycles (const std::shared_ptr<octave::stack_frame>& frame);
 
-  Cell dotref (const octave_value_list& idx);
+  OCTINTERP_API Cell dotref (const octave_value_list& idx);
 
-  Matrix size (void);
+  OCTINTERP_API Matrix size (void);
 
-  octave_idx_type xnumel (const octave_value_list&);
+  OCTINTERP_API octave_idx_type xnumel (const octave_value_list&);
 
   // We don't need to override all three forms of subsref.  The using
   // declaration will avoid warnings about partially-overloaded virtual
@@ -108,29 +108,31 @@
     return tmp.length () > 0 ? tmp(0) : octave_value ();
   }
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx,
-                             int nargout);
+  OCTINTERP_API octave_value_list
+  subsref (const std::string& type, const std::list<octave_value_list>& idx,
+           int nargout);
 
-  static octave_value numeric_conv (const Cell& val,
-                                    const std::string& type);
+  static OCTINTERP_API octave_value
+  numeric_conv (const Cell& val, const std::string& type);
 
   void assign(const std::string& k, const octave_value& rhs)
-  { map.assign (k, rhs); };
+  { m_map.assign (k, rhs); };
 
-  octave_value subsasgn (const std::string& type,
-                         const std::list<octave_value_list>& idx,
-                         const octave_value& rhs);
+  OCTINTERP_API octave_value
+   subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
+             const octave_value& rhs);
 
-  octave_value undef_subsasgn (const std::string& type,
-                               const std::list<octave_value_list>& idx,
-                               const octave_value& rhs);
+  OCTINTERP_API octave_value
+  undef_subsasgn (const std::string& type,
+                  const std::list<octave_value_list>& idx,
+                  const octave_value& rhs);
 
-  idx_vector index_vector (bool require_integers = false) const;
+  OCTINTERP_API octave::idx_vector
+  index_vector (bool require_integers = false) const;
 
-  dim_vector dims (void) const { return map.dims (); }
+  dim_vector dims (void) const { return m_map.dims (); }
 
-  std::size_t byte_size (void) const;
+  OCTINTERP_API std::size_t byte_size (void) const;
 
   // This is the number of elements in each field.  The total number
   // of elements is numel () * nfields ().
@@ -140,21 +142,21 @@
     return dv.numel ();
   }
 
-  octave_idx_type nfields (void) const { return map.nfields (); }
+  octave_idx_type nfields (void) const { return m_map.nfields (); }
 
-  std::size_t nparents (void) const { return parent_list.size (); }
+  std::size_t nparents (void) const { return m_parent_list.size (); }
 
   octave_value reshape (const dim_vector& new_dims) const
   {
     octave_class retval = octave_class (*this);
-    retval.map = retval.map_value ().reshape (new_dims);
+    retval.m_map = retval.map_value ().reshape (new_dims);
     return octave_value (new octave_class (retval));
   }
 
   octave_value resize (const dim_vector& dv, bool = false) const
   {
     octave_class retval = octave_class (*this);
-    retval.map.resize (dv);
+    retval.m_map.resize (dv);
     return octave_value (new octave_class (retval));
   }
 
@@ -164,53 +166,56 @@
 
   bool isobject (void) const { return true; }
 
-  bool is_true (void) const;
+  OCTINTERP_API bool is_true (void) const;
 
-  octave_map map_value (void) const { return map; }
+  octave_map map_value (void) const { return m_map; }
 
-  string_vector map_keys (void) const;
+  OCTINTERP_API string_vector map_keys (void) const;
 
   std::list<std::string> parent_class_name_list (void) const
-  { return parent_list; }
+  { return m_parent_list; }
 
   string_vector parent_class_names (void) const
-  { return string_vector (parent_list); }
+  { return string_vector (m_parent_list); }
 
-  octave_base_value * find_parent_class (const std::string&);
+  OCTINTERP_API octave_base_value * find_parent_class (const std::string&);
 
-  octave_base_value * unique_parent_class (const std::string&);
+  OCTINTERP_API octave_base_value * unique_parent_class (const std::string&);
 
-  bool is_instance_of (const std::string&) const;
+  OCTINTERP_API bool is_instance_of (const std::string&) const;
 
-  string_vector string_vector_value (bool pad) const;
+  OCTINTERP_API string_vector string_vector_value (bool pad) const;
 
-  void print (std::ostream& os, bool pr_as_read_syntax = false);
+  OCTINTERP_API void print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+  OCTINTERP_API void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  bool reconstruct_exemplar (void);
+  OCTINTERP_API bool reconstruct_exemplar (void);
+
+  OCTINTERP_API static void clear_exemplar_map (void);
 
-  static void clear_exemplar_map (void);
+  OCTINTERP_API bool reconstruct_parents (void);
 
-  bool reconstruct_parents (void);
+  OCTINTERP_API bool save_ascii (std::ostream& os);
 
-  bool save_ascii (std::ostream& os);
+  OCTINTERP_API bool load_ascii (std::istream& is);
 
-  bool load_ascii (std::istream& is);
+  OCTINTERP_API bool save_binary (std::ostream& os, bool save_as_floats);
 
-  bool save_binary (std::ostream& os, bool save_as_floats);
-
-  bool load_binary (std::istream& is, bool swap,
-                    octave::mach_info::float_format fmt);
+  OCTINTERP_API bool
+  load_binary (std::istream& is, bool swap,
+               octave::mach_info::float_format fmt);
 
-  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
+  OCTINTERP_API bool
+  save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
 
-  bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
+  OCTINTERP_API bool
+  load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  OCTINTERP_API mxArray * as_mxArray (bool interleaved) const;
 
 private:
-  octave_map map;
+  octave_map m_map;
 
 public:
   int type_id (void) const { return t_id; }
@@ -220,24 +225,24 @@
   static int static_type_id (void) { return t_id; }
   static std::string static_type_name (void) { return t_name; }
   static std::string static_class_name (void) { return "<unknown>"; }
-  static void register_type (octave::type_info&);
+  static OCTINTERP_API void register_type (octave::type_info&);
 
 private:
   static int t_id;
 
   static const std::string t_name;
   std::string c_name;
-  std::list<std::string> parent_list;
+  std::list<std::string> m_parent_list;
 
-  bool in_class_method (void);
-  std::string get_current_method_class (void);
+  OCTINTERP_API bool in_class_method (void);
+  OCTINTERP_API std::string get_current_method_class (void);
 
-  octave_value subsasgn_common (const octave_value& obj,
-                                const std::string& type,
-                                const std::list<octave_value_list>& idx,
-                                const octave_value& rhs);
+  OCTINTERP_API octave_value
+  subsasgn_common (const octave_value& obj, const std::string& type,
+                   const std::list<octave_value_list>& idx,
+                   const octave_value& rhs);
 
-  int obsolete_copies;
+  int m_obsolete_copies;
 
 public:
   // The list of field names and parent classes defines a class.  We
@@ -246,38 +251,38 @@
   {
   public:
 
-    exemplar_info (void) : field_names (), parent_class_names () { }
+    exemplar_info (void) : m_field_names (), m_parent_class_names () { }
 
-    exemplar_info (const octave_value& obj);
+    OCTINTERP_API exemplar_info (const octave_value& obj);
 
     exemplar_info (const exemplar_info& x)
-      : field_names (x.field_names),
-        parent_class_names (x.parent_class_names) { }
+      : m_field_names (x.m_field_names),
+        m_parent_class_names (x.m_parent_class_names) { }
 
     exemplar_info& operator = (const exemplar_info& x)
     {
       if (&x != this)
         {
-          field_names = x.field_names;
-          parent_class_names = x.parent_class_names;
+          m_field_names = x.m_field_names;
+          m_parent_class_names = x.m_parent_class_names;
         }
       return *this;
     }
 
-    octave_idx_type nfields (void) const { return field_names.numel (); }
+    octave_idx_type nfields (void) const { return m_field_names.numel (); }
 
-    std::size_t nparents (void) const { return parent_class_names.size (); }
+    std::size_t nparents (void) const { return m_parent_class_names.size (); }
 
-    string_vector fields (void) const { return field_names; }
+    string_vector fields (void) const { return m_field_names; }
 
-    std::list<std::string> parents (void) const { return parent_class_names; }
+    std::list<std::string> parents (void) const { return m_parent_class_names; }
 
-    bool compare (const octave_value& obj) const;
+    OCTINTERP_API bool compare (const octave_value& obj) const;
 
   private:
 
-    string_vector field_names;
-    std::list<std::string> parent_class_names;
+    string_vector m_field_names;
+    std::list<std::string> m_parent_class_names;
   };
 
   // A map from class names to lists of fields.
--- a/libinterp/octave-value/ov-classdef.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-classdef.cc	Sun May 16 09:44:35 2021 +0200
@@ -76,7 +76,7 @@
   std::size_t skip = 0;
   octave_value_list retval;
 
-  octave::cdef_class cls = object.get_class ();
+  octave::cdef_class cls = m_object.get_class ();
 
   if (! in_class_method (cls) && ! called_from_builtin ())
     {
@@ -99,7 +99,7 @@
 
   // At this point, the default subsref mechanism must be used.
 
-  retval = object.subsref (type, idx, nargout, skip, octave::cdef_class ());
+  retval = m_object.subsref (type, idx, nargout, skip, octave::cdef_class ());
 
   if (type.length () > skip && idx.size () > skip)
     retval = retval(0).next_subsref (nargout, type, idx, skip);
@@ -119,7 +119,7 @@
   // assignment with multi-level indexing.  AFAIK this is only used for internal
   // purpose (not sure we should even implement this).
 
-  octave::cdef_class cls = object.get_class ();
+  octave::cdef_class cls = m_object.get_class ();
 
   if (! in_class_method (cls))
     {
@@ -140,7 +140,7 @@
         }
     }
 
-  retval = object.subsref (type, idx, 1, skip, octave::cdef_class (), auto_add);
+  retval = m_object.subsref (type, idx, 1, skip, octave::cdef_class (), auto_add);
 
   if (type.length () > skip && idx.size () > skip)
     retval = retval(0).next_subsref (1, type, idx, skip);
@@ -155,7 +155,7 @@
 {
   octave_value retval;
 
-  octave::cdef_class cls = object.get_class ();
+  octave::cdef_class cls = m_object.get_class ();
 
   if (! in_class_method (cls) && ! called_from_builtin ())
     {
@@ -183,7 +183,7 @@
     }
 
   if (! retval.is_defined ())
-    retval = object.subsasgn (type, idx, rhs);
+    retval = m_object.subsasgn (type, idx, rhs);
 
   return retval;
 }
@@ -195,7 +195,7 @@
 {
   if (type.length () == 1 && type[0] == '(')
     {
-      object = object.make_array ();
+      m_object = m_object.make_array ();
 
       return subsasgn (type, idx, rhs);
     }
@@ -208,7 +208,7 @@
 Matrix
 octave_classdef::size (void)
 {
-  octave::cdef_class cls = object.get_class ();
+  octave::cdef_class cls = m_object.get_class ();
 
   if (! in_class_method (cls) && ! called_from_builtin ())
     {
@@ -236,7 +236,7 @@
 {
   octave_idx_type retval = -1;
 
-  octave::cdef_class cls = object.get_class ();
+  octave::cdef_class cls = m_object.get_class ();
 
   if (! in_class_method (cls) && ! called_from_builtin ())
     {
@@ -287,16 +287,16 @@
 void
 octave_classdef::print_raw (std::ostream& os, bool) const
 {
-  octave::cdef_class cls = object.get_class ();
+  octave::cdef_class cls = m_object.get_class ();
 
   if (cls.ok ())
     {
-      bool is_array = object.is_array ();
+      bool is_array = m_object.is_array ();
 
       increment_indent_level ();
 
       indent (os);
-      os << class_name () << " object";
+      os << class_name () << " m_object";
       if (is_array)
         os << " array";
       os << " with properties:";
@@ -357,7 +357,7 @@
             os << "  " << nm;
           else
             {
-              octave_value val = prop.get_value (object, false);
+              octave_value val = prop.get_value (m_object, false);
               dim_vector dims = val.dims ();
 
               os << std::setw (max_len+2) << nm << ": ";
@@ -383,7 +383,7 @@
   octave::cdef_class cls = octave::lookup_class (cls_name, false, false);
 
   if (cls.ok ())
-    return is_superclass (cls, object.get_class ());
+    return is_superclass (cls, m_object.get_class ());
 
   return false;
 }
@@ -405,13 +405,13 @@
 {
   bool retval = false;
 
-  if (object.is_method ())
+  if (m_object.is_method ())
     {
       if (cname.empty ())
         retval = true;
       else
         {
-          octave::cdef_method meth (object);
+          octave::cdef_method meth (m_object);
 
           return meth.is_defined_in_class (cname);
         }
@@ -424,13 +424,13 @@
 {
   bool retval = false;
 
-  if (object.is_class ())
+  if (m_object.is_class ())
     {
       if (cname.empty ())
         retval = true;
       else
         {
-          octave::cdef_class cls (object);
+          octave::cdef_class cls (m_object);
 
           if (cls.get_name () == cname)
             retval = true;
@@ -442,9 +442,9 @@
 
 std::string octave_classdef_meta::doc_string (const std::string& meth_name) const
 {
-  if (object.is_class ())
+  if (m_object.is_class ())
     {
-      octave::cdef_class cls (object);
+      octave::cdef_class cls (m_object);
 
       if (meth_name.empty ())
         return cls.doc_string ();
--- a/libinterp/octave-value/ov-classdef.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-classdef.h	Sun May 16 09:44:35 2021 +0200
@@ -48,10 +48,10 @@
 public:
 
   octave_classdef (void)
-    : octave_base_value (), object () { }
+    : octave_base_value (), m_object () { }
 
   octave_classdef (const octave::cdef_object& obj)
-    : octave_base_value (), object (obj) { }
+    : octave_base_value (), m_object (obj) { }
 
   octave_classdef (const octave_classdef&) = delete;
 
@@ -61,19 +61,19 @@
 
   octave_base_value * clone (void) const
   {
-    return new octave_classdef (object.clone ());
+    return new octave_classdef (m_object.clone ());
   }
 
   octave_base_value * empty_clone (void) const
   {
-    return new octave_classdef (object.empty_clone ());
+    return new octave_classdef (m_object.empty_clone ());
   }
 
   octave_classdef * classdef_object_value (bool = false) { return this; }
 
-  octave::cdef_object get_object (void) const { return object; }
+  octave::cdef_object get_object (void) const { return m_object; }
 
-  octave::cdef_object& get_object_ref (void) { return object; }
+  octave::cdef_object& get_object_ref (void) { return m_object; }
 
   bool is_defined (void) const { return true; }
 
@@ -83,20 +83,21 @@
 
   bool is_classdef_object (void) const { return true; }
 
-  void print (std::ostream& os, bool pr_as_read_syntax = false);
+  OCTINTERP_API void print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+  OCTINTERP_API void
+  print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  bool is_instance_of (const std::string& cls_name) const;
+  OCTINTERP_API bool is_instance_of (const std::string& cls_name) const;
 
   void break_closure_cycles (const std::shared_ptr<octave::stack_frame>& frame)
   {
-    object.break_closure_cycles (frame);
+    m_object.break_closure_cycles (frame);
   }
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx,
-                             int nargout);
+  OCTINTERP_API octave_value_list
+  subsref (const std::string& type, const std::list<octave_value_list>& idx,
+           int nargout);
 
   octave_value subsref (const std::string& type,
                         const std::list<octave_value_list>& idx)
@@ -105,60 +106,60 @@
     return (retval.length () > 0 ? retval(0) : octave_value ());
   }
 
-  octave_value subsref (const std::string& type,
-                        const std::list<octave_value_list>& idx,
-                        bool auto_add);
+  OCTINTERP_API octave_value
+  subsref (const std::string& type, const std::list<octave_value_list>& idx,
+           bool auto_add);
 
-  octave_value subsasgn (const std::string& type,
-                         const std::list<octave_value_list>& idx,
-                         const octave_value& rhs);
+  OCTINTERP_API octave_value
+  subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
+            const octave_value& rhs);
 
-  octave_value
+  OCTINTERP_API octave_value
   undef_subsasgn (const std::string& type,
                   const std::list<octave_value_list>& idx,
                   const octave_value& rhs);
 
-  Matrix size (void);
+  OCTINTERP_API Matrix size (void);
 
-  octave_idx_type xnumel (const octave_value_list&);
+  OCTINTERP_API octave_idx_type xnumel (const octave_value_list&);
 
-  string_vector map_keys (void) const { return object.map_keys (); }
+  string_vector map_keys (void) const { return m_object.map_keys (); }
 
-  octave_map map_value (void) const { return object.map_value (); }
+  octave_map map_value (void) const { return m_object.map_value (); }
 
-  dim_vector dims (void) const { return object.dims (); }
+  dim_vector dims (void) const { return m_object.dims (); }
 
   void set_property (octave_idx_type idx, const std::string& name,
                      const octave_value& pval)
   {
-    object.set_property (idx, name, pval);
+    m_object.set_property (idx, name, pval);
   }
 
   octave_value
   get_property (octave_idx_type idx, const std::string& name) const
   {
-    return object.get_property (idx, name);
+    return m_object.get_property (idx, name);
   }
 
-  static octave_value superclass_ref (const std::string& meth,
-                                      const std::string& cls);
+  static OCTINTERP_API octave_value
+  superclass_ref (const std::string& meth, const std::string& cls);
 
-  static octave_value metaclass_query (const std::string& cls);
+  static OCTINTERP_API octave_value metaclass_query (const std::string& cls);
 
 public:
 
   int type_id (void) const { return t_id; }
   std::string type_name (void) const { return t_name; }
-  std::string class_name (void) const { return object.class_name (); }
+  std::string class_name (void) const { return m_object.class_name (); }
 
   static int static_type_id (void) { return t_id; }
   static std::string static_type_name (void) { return t_name; }
   static std::string static_class_name (void) { return "<unknown>"; }
-  static void register_type (octave::type_info&);
+  static OCTINTERP_API void register_type (octave::type_info&);
 
 private:
 
-  octave::cdef_object object;
+  octave::cdef_object m_object;
 
   static int t_id;
 
@@ -172,18 +173,18 @@
 public:
 
   octave_classdef_meta (const octave::cdef_meta_object& obj)
-    : object (obj)
+    : m_object (obj)
   { }
 
   octave_classdef_meta (const octave_classdef_meta&) = delete;
 
   octave_classdef_meta& operator = (const octave_classdef_meta&) = delete;
 
-  ~octave_classdef_meta (void) { object.meta_release (); }
+  ~octave_classdef_meta (void) { m_object.meta_release (); }
 
   bool is_classdef_meta (void) const { return true; }
 
-  bool is_package (void) const { return object.is_package(); }
+  bool is_package (void) const { return m_object.is_package(); }
 
   octave_function * function_value (bool = false) { return this; }
 
@@ -197,7 +198,7 @@
            const std::list<octave_value_list>& idx,
            int nargout)
   {
-    return object.meta_subsref (type, idx, nargout);
+    return m_object.meta_subsref (type, idx, nargout);
   }
 
   // Override default call method because we don't push a new stack
@@ -221,17 +222,18 @@
   }
 
   bool accepts_postfix_index (char type) const
-  { return object.meta_accepts_postfix_index (type); }
+  { return m_object.meta_accepts_postfix_index (type); }
 
-  bool is_classdef_method (const std::string& cname = "") const;
+  OCTINTERP_API bool is_classdef_method (const std::string& cname = "") const;
 
-  bool is_classdef_constructor (const std::string& cname = "") const;
+  OCTINTERP_API bool
+  is_classdef_constructor (const std::string& cname = "") const;
 
-  std::string doc_string (const std::string& meth_name) const;
+  OCTINTERP_API std::string doc_string (const std::string& meth_name) const;
 
 private:
 
-  octave::cdef_meta_object object;
+  octave::cdef_meta_object m_object;
 };
 
 class octave_classdef_superclass_ref : public octave_function
@@ -263,13 +265,14 @@
     return execute (tw, nargout, args);
   }
 
-  octave_value_list execute (octave::tree_evaluator& tw, int nargout,
-                             const octave_value_list& idx);
+  OCTINTERP_API octave_value_list
+  execute (octave::tree_evaluator& tw, int nargout,
+           const octave_value_list& idx);
 
 private:
 
-  bool is_constructed_object (octave::tree_evaluator& tw,
-                              const std::string& nm);
+  OCTINTERP_API bool
+  is_constructed_object (octave::tree_evaluator& tw, const std::string& nm);
 
 private:
 
--- a/libinterp/octave-value/ov-colon.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-colon.h	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,8 @@
   octave_base_value * empty_clone (void) const
   { return new octave_magic_colon (); }
 
-  idx_vector index_vector (bool /* require_integers */ = false) const { return idx_vector (':'); }
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
+  { return octave::idx_vector (':'); }
 
   bool is_defined (void) const { return true; }
 
@@ -70,9 +71,9 @@
 
   bool is_magic_colon (void) const { return true; }
 
-  void print (std::ostream& os, bool pr_as_read_syntax = false);
+  OCTINTERP_API void print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+  OCTINTERP_API void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
 private:
 
--- a/libinterp/octave-value/ov-complex.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-complex.cc	Sun May 16 09:44:35 2021 +0200
@@ -57,8 +57,8 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
-extern template class OCTINTERP_API octave_base_scalar<FloatComplex>;
+extern template class octave_base_scalar<double>;
+extern template class octave_base_scalar<FloatComplex>;
 
 template class octave_base_scalar<Complex>;
 
@@ -140,18 +140,18 @@
 
   octave_value tmp (new octave_complex_matrix (complex_matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 // Can't make an index_vector from a complex number.  Throw an error.
-idx_vector
+octave::idx_vector
 octave_complex::index_vector (bool) const
 {
   std::ostringstream buf;
   buf << scalar.real () << std::showpos << scalar.imag () << 'i';
-  octave::complex_index_exception e (buf.str ());
+  octave::complex_index_exception cie (buf.str ());
 
-  throw e;
+  throw cie;
 }
 
 double
@@ -313,7 +313,7 @@
 {
   Complex c = complex_value ();
 
-  octave_write_complex (os, c);
+  octave::write_value<Complex> (os, c);
 
   os << "\n";
 
@@ -323,7 +323,7 @@
 bool
 octave_complex::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<Complex> (is);
+  scalar = octave::read_value<Complex> (is);
 
   if (! is)
     error ("load: failed to load complex scalar constant");
@@ -369,7 +369,7 @@
 
 #if defined (HAVE_HDF5)
 
-  hsize_t dimens[3];
+  hsize_t dimens[3] = {0};
   hid_t space_hid, type_hid, data_hid;
   space_hid = type_hid = data_hid = -1;
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-complex.h	Sun May 16 09:44:35 2021 +0200
@@ -82,7 +82,7 @@
                             bool resize_ok = false);
 
   // Use this to give a more specific error message.
-  idx_vector index_vector (bool /* require_integers */ = false) const;
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const;
 
   octave_value any (int = 0) const
   {
@@ -101,9 +101,9 @@
 
   bool isfloat (void) const { return true; }
 
-  double double_value (bool = false) const;
+  OCTINTERP_API double double_value (bool = false) const;
 
-  float float_value (bool = false) const;
+  OCTINTERP_API float float_value (bool = false) const;
 
   double scalar_value (bool frc_str_conv = false) const
   { return double_value (frc_str_conv); }
@@ -111,13 +111,13 @@
   float float_scalar_value (bool frc_str_conv = false) const
   { return float_value (frc_str_conv); }
 
-  Matrix matrix_value (bool = false) const;
+  OCTINTERP_API Matrix matrix_value (bool = false) const;
 
-  FloatMatrix float_matrix_value (bool = false) const;
+  OCTINTERP_API FloatMatrix float_matrix_value (bool = false) const;
 
-  NDArray array_value (bool = false) const;
+  OCTINTERP_API NDArray array_value (bool = false) const;
 
-  FloatNDArray float_array_value (bool = false) const;
+  OCTINTERP_API FloatNDArray float_array_value (bool = false) const;
 
   SparseMatrix sparse_matrix_value (bool = false) const
   { return SparseMatrix (matrix_value ()); }
@@ -125,19 +125,22 @@
   SparseComplexMatrix sparse_complex_matrix_value (bool = false) const
   { return SparseComplexMatrix (complex_matrix_value ()); }
 
-  octave_value resize (const dim_vector& dv, bool fill = false) const;
+  OCTINTERP_API octave_value
+  resize (const dim_vector& dv, bool fill = false) const;
 
-  Complex complex_value (bool = false) const;
+  OCTINTERP_API Complex complex_value (bool = false) const;
 
-  FloatComplex float_complex_value (bool = false) const;
+  OCTINTERP_API FloatComplex float_complex_value (bool = false) const;
 
-  ComplexMatrix complex_matrix_value (bool = false) const;
+  OCTINTERP_API ComplexMatrix complex_matrix_value (bool = false) const;
 
-  FloatComplexMatrix float_complex_matrix_value (bool = false) const;
+  OCTINTERP_API FloatComplexMatrix
+  float_complex_matrix_value (bool = false) const;
 
-  ComplexNDArray complex_array_value (bool = false) const;
+  OCTINTERP_API ComplexNDArray complex_array_value (bool = false) const;
 
-  FloatComplexNDArray float_complex_array_value (bool = false) const;
+  OCTINTERP_API FloatComplexNDArray
+  float_complex_array_value (bool = false) const;
 
   bool bool_value (bool warn = false) const
   {
@@ -159,32 +162,34 @@
     return boolNDArray (dim_vector (1, 1), scalar != 0.0);
   }
 
-  octave_value as_double (void) const;
-  octave_value as_single (void) const;
+  OCTINTERP_API octave_value as_double (void) const;
+  OCTINTERP_API octave_value as_single (void) const;
 
   // We don't need to override both forms of the diag method.  The using
   // declaration will avoid warnings about partially-overloaded virtual
   // functions.
   using octave_base_scalar<Complex>::diag;
 
-  octave_value diag (octave_idx_type m, octave_idx_type n) const;
+  OCTINTERP_API octave_value diag (octave_idx_type m, octave_idx_type n) const;
 
   void increment (void) { scalar += 1.0; }
 
   void decrement (void) { scalar -= 1.0; }
 
-  bool save_ascii (std::ostream& os);
+  OCTINTERP_API bool save_ascii (std::ostream& os);
 
-  bool load_ascii (std::istream& is);
+  OCTINTERP_API bool load_ascii (std::istream& is);
 
-  bool save_binary (std::ostream& os, bool save_as_floats);
+  OCTINTERP_API bool save_binary (std::ostream& os, bool save_as_floats);
 
-  bool load_binary (std::istream& is, bool swap,
-                    octave::mach_info::float_format fmt);
+  OCTINTERP_API bool
+  load_binary (std::istream& is, bool swap,
+               octave::mach_info::float_format fmt);
 
-  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
+  OCTINTERP_API bool
+  save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
 
-  bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
+  OCTINTERP_API bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
   int write (octave::stream& os, int block_size,
              oct_data_conv::data_type output_type, int skip,
@@ -195,9 +200,9 @@
                      skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  OCTINTERP_API mxArray * as_mxArray (bool interleaved) const;
 
-  octave_value map (unary_mapper_t umap) const;
+  OCTINTERP_API octave_value map (unary_mapper_t umap) const;
 
 private:
 
--- a/libinterp/octave-value/ov-cs-list.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-cs-list.h	Sun May 16 09:44:35 2021 +0200
@@ -79,11 +79,12 @@
   // functions.
   using octave_base_value::subsref;
 
-  octave_value subsref (const std::string& type,
-                        const std::list<octave_value_list>& idx);
+  OCTINTERP_API octave_value
+  subsref (const std::string& type, const std::list<octave_value_list>& idx);
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx, int);
+  OCTINTERP_API octave_value_list
+  subsref (const std::string& type, const std::list<octave_value_list>& idx,
+           int);
 
 private:
 
--- a/libinterp/octave-value/ov-cx-diag.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-cx-diag.h	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,6 @@
 // Real diagonal matrix values.
 
 class
-OCTINTERP_API
 octave_complex_diag_matrix
   : public octave_base_diag<ComplexDiagMatrix, ComplexMatrix>
 {
@@ -58,11 +57,11 @@
   octave_base_value * empty_clone (void) const
   { return new octave_complex_diag_matrix (); }
 
-  type_conv_info numeric_conversion_function (void) const;
+  OCTINTERP_API type_conv_info numeric_conversion_function (void) const;
 
-  type_conv_info numeric_demotion_function (void) const;
+  OCTINTERP_API type_conv_info numeric_demotion_function (void) const;
 
-  octave_base_value * try_narrowing_conversion (void);
+  OCTINTERP_API octave_base_value * try_narrowing_conversion (void);
 
   builtin_type_t builtin_type (void) const { return btyp_complex; }
 
@@ -74,28 +73,30 @@
 
   bool isfloat (void) const { return true; }
 
-  DiagMatrix diag_matrix_value (bool = false) const;
+  OCTINTERP_API DiagMatrix diag_matrix_value (bool = false) const;
 
-  FloatDiagMatrix float_diag_matrix_value (bool = false) const;
+  OCTINTERP_API FloatDiagMatrix float_diag_matrix_value (bool = false) const;
 
-  ComplexDiagMatrix complex_diag_matrix_value (bool = false) const;
+  OCTINTERP_API ComplexDiagMatrix
+  complex_diag_matrix_value (bool = false) const;
 
-  FloatComplexDiagMatrix float_complex_diag_matrix_value (bool = false) const;
+  OCTINTERP_API FloatComplexDiagMatrix
+  float_complex_diag_matrix_value (bool = false) const;
 
-  octave_value as_double (void) const;
-  octave_value as_single (void) const;
+  OCTINTERP_API octave_value as_double (void) const;
+  OCTINTERP_API octave_value as_single (void) const;
 
-  bool save_binary (std::ostream& os, bool save_as_floats);
+  OCTINTERP_API bool save_binary (std::ostream& os, bool save_as_floats);
 
-  bool load_binary (std::istream& is, bool swap,
-                    octave::mach_info::float_format fmt);
+  OCTINTERP_API bool
+  load_binary (std::istream& is, bool swap,
+               octave::mach_info::float_format fmt);
 
-  octave_value map (unary_mapper_t umap) const;
+  OCTINTERP_API octave_value map (unary_mapper_t umap) const;
 
 private:
 
-  bool chk_valid_scalar (const octave_value&,
-                         Complex&) const;
+  OCTINTERP_API bool chk_valid_scalar (const octave_value&, Complex&) const;
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
--- a/libinterp/octave-value/ov-cx-mat.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-cx-mat.cc	Sun May 16 09:44:35 2021 +0200
@@ -516,7 +516,7 @@
         return false;
       ComplexMatrix m (nr, nc);
       Complex *im = m.fortran_vec ();
-      octave_idx_type len = nr * nc;
+      octave_idx_type len = static_cast<octave_idx_type> (nr) * nc;
       read_doubles (is, reinterpret_cast<double *> (im),
                     static_cast<save_type> (tmp), 2*len, swap, fmt);
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-cx-mat.h	Sun May 16 09:44:35 2021 +0200
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-cx-sparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
 #include "ov-bool-sparse.h"
 
 
-template class OCTINTERP_API octave_base_sparse<SparseComplexMatrix>;
+template class octave_base_sparse<SparseComplexMatrix>;
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_sparse_complex_matrix,
                                      "sparse complex matrix", "double");
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-cx-sparse.h	Sun May 16 09:44:35 2021 +0200
@@ -149,7 +149,7 @@
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-fcn-handle.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Sun May 16 09:44:35 2021 +0200
@@ -575,6 +575,32 @@
     std::string m_dispatch_class;
   };
 
+  // Handles to anonymous functions are similar to handles to nested
+  // functions.  If they are created in a context that contains nested
+  // functions, then they store a link to the parent call stack frames
+  // that are active when they are created.  These call stack frames
+  // (closure frames) provide access to variables needed by any nested
+  // functions that are called from the anonymous function.  Anonymous
+  // functions also store a list of values from their parent scope
+  // corresponding to the symbols in the anonymous function.  This list
+  // of values captures the variable values that are visible in the
+  // scope where they are created.
+  //
+  // Note that because handles to anonymous and nested functions capture
+  // call stack frames when they are created, they will cause deletion
+  // of the values in those frames to be deferred until the handles to
+  // the anonymous or nested functions are deleted.
+  //
+  // Would it be possible to avoid storing the closure frames for
+  // handles to anonymous functions if we can determine that the
+  // anonymous function has no unbound variables (or parameters, which
+  // could be handles to nested functions?) or if it is not created in a
+  // context that contains nested functions?
+  //
+  // Would it be possible to define anonymous functions as a special
+  // type of nested function object that also has an variable
+  // initialization list associated with it?
+
   class base_anonymous_fcn_handle : public base_fcn_handle
   {
   public:
@@ -777,7 +803,6 @@
       case '{':
       case '.':
         error ("function handle cannot be indexed with %c", type[0]);
-        break;
 
       default:
         panic_impossible ();
@@ -1017,7 +1042,7 @@
 
                     arg_list.clear ();
                   }
-                catch (index_exception&)
+                catch (const index_exception&)
                   {
                     err_invalid_fcn_handle (m_name);
                   }
@@ -1210,7 +1235,7 @@
   }
 
   bool simple_fcn_handle::load_binary (std::istream& is, bool,
-                                       octave::mach_info::float_format)
+                                       mach_info::float_format)
   {
     return is.good ();
   }
@@ -1516,7 +1541,7 @@
   }
 
   bool scoped_fcn_handle::load_binary (std::istream& is, bool swap,
-                                       octave::mach_info::float_format fmt)
+                                       mach_info::float_format fmt)
   {
     octave_cell ov_cell;
     ov_cell.load_binary (is, swap, fmt);
@@ -2087,8 +2112,6 @@
 
     std::streampos pos = is.tellg ();
 
-    unwind_protect_safe frame;
-
     // Set up temporary scope to use for evaluating the text that
     // defines the anonymous function.
 
@@ -2098,7 +2121,7 @@
     tree_evaluator& tw = interp.get_evaluator ();
 
     tw.push_dummy_scope (buf);
-    frame.add_method (tw, &tree_evaluator::pop_scope);
+    unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
 
     octave_idx_type len = 0;
 
@@ -2206,8 +2229,6 @@
     is.read (ctmp2, tmp);
     ctmp2[tmp] = 0;
 
-    unwind_protect_safe frame;
-
     // Set up temporary scope to use for evaluating the text that
     // defines the anonymous function.
 
@@ -2217,7 +2238,7 @@
     tree_evaluator& tw = interp.get_evaluator ();
 
     tw.push_dummy_scope (ctmp2);
-    frame.add_method (tw, &tree_evaluator::pop_scope);
+    unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
 
     if (len > 0)
       {
@@ -2523,8 +2544,6 @@
     H5Eset_auto (err_func, err_func_data);
 #endif
 
-    unwind_protect_safe frame;
-
     // Set up temporary scope to use for evaluating the text that
     // defines the anonymous function.
 
@@ -2534,7 +2553,7 @@
     tree_evaluator& tw = interp.get_evaluator ();
 
     tw.push_dummy_scope (fcn_tmp);
-    frame.add_method (tw, &tree_evaluator::pop_scope);
+    unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
 
     if (len > 0 && success)
       {
--- a/libinterp/octave-value/ov-float.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-float.cc	Sun May 16 09:44:35 2021 +0200
@@ -79,7 +79,7 @@
 
   octave_value tmp (new octave_float_matrix (float_matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 octave_value
@@ -200,7 +200,7 @@
 {
   float d = float_value ();
 
-  octave_write_float (os, d);
+  octave::write_value<float> (os, d);
 
   os << "\n";
 
@@ -210,7 +210,7 @@
 bool
 octave_float_scalar::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<float> (is);
+  scalar = octave::read_value<float> (is);
   if (! is)
     error ("load: failed to load scalar constant");
 
@@ -254,7 +254,7 @@
 
 #if defined (HAVE_HDF5)
 
-  hsize_t dimens[3];
+  hsize_t dimens[3] = {0};
   hid_t space_hid, data_hid;
   space_hid = data_hid = -1;
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-float.h	Sun May 16 09:44:35 2021 +0200
@@ -79,7 +79,8 @@
   octave_value do_index_op (const octave_value_list& idx,
                             bool resize_ok = false);
 
-  idx_vector index_vector (bool /* require_integers */ = false) const { return idx_vector (scalar); }
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
+  { return octave::idx_vector (scalar); }
 
   octave_value any (int = 0) const
   { return (scalar != 0 && ! lo_ieee_isnan (scalar)); }
@@ -266,7 +267,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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-flt-complex.cc	Sun May 16 09:44:35 2021 +0200
@@ -56,7 +56,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<float>;
+extern template class octave_base_scalar<float>;
 
 template class octave_base_scalar<FloatComplex>;
 
@@ -91,7 +91,7 @@
 
   octave_value tmp (new octave_float_complex_matrix (float_complex_matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 double
@@ -254,7 +254,7 @@
 {
   FloatComplex c = float_complex_value ();
 
-  octave_write_float_complex (os, c);
+  octave::write_value<FloatComplex> (os, c);
 
   os << "\n";
 
@@ -264,7 +264,7 @@
 bool
 octave_float_complex::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<FloatComplex> (is);
+  scalar = octave::read_value<FloatComplex> (is);
 
   if (! is)
     error ("load: failed to load complex scalar constant");
@@ -310,7 +310,7 @@
 
 #if defined (HAVE_HDF5)
 
-  hsize_t dimens[3];
+  hsize_t dimens[3] = {0};
   hid_t space_hid, type_hid, data_hid;
   space_hid = type_hid = data_hid = -1;
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-flt-complex.h	Sun May 16 09:44:35 2021 +0200
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-flt-cx-mat.cc	Sun May 16 09:44:35 2021 +0200
@@ -480,7 +480,7 @@
         return false;
       FloatComplexMatrix m (nr, nc);
       FloatComplex *im = m.fortran_vec ();
-      octave_idx_type len = nr * nc;
+      octave_idx_type len = static_cast<octave_idx_type> (nr) * nc;
       read_floats (is, reinterpret_cast<float *> (im),
                    static_cast<save_type> (tmp), 2*len, swap, fmt);
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-flt-cx-mat.h	Sun May 16 09:44:35 2021 +0200
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-flt-re-mat.cc	Sun May 16 09:44:35 2021 +0200
@@ -556,7 +556,7 @@
         return false;
       FloatMatrix m (nr, nc);
       float *re = m.fortran_vec ();
-      octave_idx_type len = nr * nc;
+      octave_idx_type len = static_cast<octave_idx_type> (nr) * nc;
       read_floats (is, re, static_cast<save_type> (tmp), len, swap, fmt);
 
       if (! is)
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-flt-re-mat.h	Sun May 16 09:44:35 2021 +0200
@@ -90,9 +90,9 @@
 
   octave_base_value * try_narrowing_conversion (void);
 
-  idx_vector index_vector (bool /* require_integers */ = false) const
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
   {
-    return idx_cache ? *idx_cache : set_idx_cache (idx_vector (matrix));
+    return idx_cache ? *idx_cache : set_idx_cache (octave::idx_vector (matrix));
   }
 
   builtin_type_t builtin_type (void) const { return btyp_float; }
@@ -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-int16.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-int16.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_matrix<int16NDArray>;
 
--- a/libinterp/octave-value/ov-int32.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-int32.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_matrix<int32NDArray>;
 
--- a/libinterp/octave-value/ov-int64.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-int64.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_matrix<int64NDArray>;
 
--- a/libinterp/octave-value/ov-int8.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-int8.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_matrix<int8NDArray>;
 
--- a/libinterp/octave-value/ov-intx.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-intx.h	Sun May 16 09:44:35 2021 +0200
@@ -301,9 +301,9 @@
     matrix_ref ().changesign ();
   }
 
-  idx_vector index_vector (bool /* require_integers */ = false) const
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
   {
-    return idx_cache ? *idx_cache : set_idx_cache (idx_vector (matrix));
+    return idx_cache ? *idx_cache : set_idx_cache (octave::idx_vector (matrix));
   }
 
   int write (octave::stream& os, int block_size,
@@ -315,19 +315,20 @@
   // You should not use it anywhere else.
   void * mex_get_data (void) const { return matrix.mex_get_data (); }
 
-  mxArray * as_mxArray (void) const
+  mxArray * as_mxArray (bool interleaved) const
   {
-    mxArray *retval = new mxArray (OCTAVE_INT_MX_CLASS, dims (), mxREAL);
+    mxArray *retval = new mxArray (interleaved, OCTAVE_INT_MX_CLASS, dims (),
+                                   mxREAL);
 
-    OCTAVE_INT_T::val_type *pr = static_cast<OCTAVE_INT_T::val_type *>
-                                 (retval->get_data ());
+    OCTAVE_INT_T::val_type *pd
+      = static_cast<OCTAVE_INT_T::val_type *> (retval->get_data ());
 
     mwSize nel = numel ();
 
-    const OCTAVE_INT_T *p = matrix.data ();
+    const OCTAVE_INT_T *pdata = matrix.data ();
 
     for (mwIndex i = 0; i < nel; i++)
-      pr[i] = p[i].value ();
+      pd[i] = pdata[i].value ();
 
     return retval;
   }
@@ -426,7 +427,7 @@
     (new OCTAVE_VALUE_INT_MATRIX_T
      (OCTAVE_VALUE_INT_NDARRAY_EXTRACTOR_FUNCTION ()));
 
-    return tmp.do_index_op (idx, resize_ok);
+    return tmp.index_op (idx, resize_ok);
   }
 
   bool OCTAVE_TYPE_PREDICATE_FUNCTION (void) const { return true; }
@@ -623,7 +624,8 @@
     scalar -= OCTAVE_INT_T (1);
   }
 
-  idx_vector index_vector (bool /* require_integers */ = false) const { return idx_vector (scalar); }
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
+  { return octave::idx_vector (scalar); }
 
   int write (octave::stream& os, int block_size,
              oct_data_conv::data_type output_type, int skip,
@@ -637,14 +639,15 @@
   // You should not use it anywhere else.
   void * mex_get_data (void) const { return scalar.mex_get_data (); }
 
-  mxArray * as_mxArray (void) const
+  mxArray * as_mxArray (bool interleaved) const
   {
-    mxArray *retval = new mxArray (OCTAVE_INT_MX_CLASS, 1, 1, mxREAL);
+    mxArray *retval = new mxArray (interleaved, OCTAVE_INT_MX_CLASS, 1, 1,
+                                   mxREAL);
 
-    OCTAVE_INT_T::val_type *pr = static_cast<OCTAVE_INT_T::val_type *>
-                                 (retval->get_data ());
+    OCTAVE_INT_T::val_type *pd
+      = static_cast<OCTAVE_INT_T::val_type *> (retval->get_data ());
 
-    pr[0] = scalar.value ();
+    pd[0] = scalar.value ();
 
     return retval;
   }
--- a/libinterp/octave-value/ov-java.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-java.cc	Sun May 16 09:44:35 2021 +0200
@@ -37,6 +37,7 @@
 #endif
 
 #include <algorithm>
+#include <array>
 #include <fstream>
 #include <map>
 #include <string>
@@ -513,16 +514,16 @@
   // This assumes that whatever architectures are installed are appropriate for
   // this machine
 #if defined (OCTAVE_USE_WINDOWS_API)
-  std::string subdirs[] = {"bin/client", "bin/server"};
+  const std::array<const std::string, 2> subdirs = {"bin/client", "bin/server"};
 #else
-  std::string subdirs[] = {"jre/lib/server", "jre/lib",
-                           "lib/client", "lib/server",
-                           "jre/lib/amd64/client", "jre/lib/amd64/server",
-                           "jre/lib/i386/client", "jre/lib/i386/server"
-                          };
+  const std::array<const std::string, 8> subdirs =
+    {"jre/lib/server", "jre/lib", "lib/client", "lib/server",
+     "jre/lib/amd64/client", "jre/lib/amd64/server",
+     "jre/lib/i386/client", "jre/lib/i386/server"
+    };
 #endif
 
-  for (std::size_t i = 0; i < sizeof (subdirs) / sizeof (subdirs[0]); i++)
+  for (std::size_t i = 0; i < subdirs.size (); i++)
     {
       std::string candidate = java_home_path + "/" + subdirs[i]
                               + "/" LIBJVM_FILE_NAME;
@@ -786,7 +787,6 @@
 
         case JNI_EVERSION:
           error ("JVM internal error, the required JNI version is not supported");
-          break;
 
         case JNI_OK:
           // Don't do anything, the current thread is already attached to JVM
@@ -1121,7 +1121,7 @@
   for (int i = 0; i < idx.length (); i++)
     try
       {
-        idx_vector v = idx(i).index_vector ();
+        octave::idx_vector v = idx(i).index_vector ();
 
         jintArray_ref i_array (jni_env, jni_env->NewIntArray (v.length ()));
         jint *buf = jni_env->GetIntArrayElements (i_array, nullptr);
@@ -1137,10 +1137,10 @@
 
         check_exception (jni_env);
       }
-    catch (octave::index_exception& e)
+    catch (octave::index_exception& ie)
       {
         // Rethrow to allow more info to be reported later.
-        e.set_pos_if_unset (idx.length (), i + 1);
+        ie.set_pos_if_unset (idx.length (), i + 1);
         throw;
       }
 
@@ -2018,7 +2018,7 @@
 
           octave_thread_ID = get_current_thread_ID (current_env);
         }
-      catch (std::string msg)
+      catch (const std::string msg)
         {
           error ("%s", msg.c_str ());
         }
--- a/libinterp/octave-value/ov-lazy-idx.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-lazy-idx.cc	Sun May 16 09:44:35 2021 +0200
@@ -81,8 +81,8 @@
 octave_value
 octave_lazy_index::reshape (const dim_vector& new_dims) const
 {
-  return idx_vector (index.as_array ().reshape (new_dims),
-                     index.extent (0));
+  return octave::idx_vector (index.as_array ().reshape (new_dims),
+                             index.extent (0));
 }
 
 octave_value
@@ -92,15 +92,14 @@
   if (value.is_defined ())
     return value.permute (vec, inv);
   else
-    return idx_vector (index.as_array ().permute (vec, inv),
-                       index.extent (0));
+    return octave::idx_vector (index.as_array ().permute (vec, inv),
+                               index.extent (0));
 }
 
 octave_value
 octave_lazy_index::squeeze (void) const
 {
-  return idx_vector (index.as_array ().squeeze (),
-                     index.extent (0));
+  return octave::idx_vector (index.as_array ().squeeze (), index.extent (0));
 }
 
 octave_value
@@ -112,8 +111,8 @@
       && (dim >= 0 && dim <= 1) && odims(1-dim) == 1)
     return index_vector ().sorted ();
   else
-    return idx_vector (index.as_array ().sort (dim, mode),
-                       index.extent (0));
+    return octave::idx_vector (index.as_array ().sort (dim, mode),
+                               index.extent (0));
 }
 
 octave_value
@@ -126,8 +125,8 @@
       && (dim >= 0 && dim <= 1) && odims(1-dim) == 1)
     return index_vector ().sorted (sidx);
   else
-    return idx_vector (index.as_array ().sort (sidx, dim, mode),
-                       index.extent (0));
+    return octave::idx_vector (index.as_array ().sort (sidx, dim, mode),
+                               index.extent (0));
 }
 
 sortmode
--- a/libinterp/octave-value/ov-lazy-idx.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-lazy-idx.h	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
   octave_lazy_index (void)
     : octave_base_value (), index (), value () { }
 
-  octave_lazy_index (const idx_vector& idx)
+  octave_lazy_index (const octave::idx_vector& idx)
     : octave_base_value (), index (idx), value () { }
 
   octave_lazy_index (const octave_lazy_index& i)
@@ -66,7 +66,8 @@
 
   octave_value full_value (void) const { return make_value (); }
 
-  idx_vector index_vector (bool /* require_integers */ = false) const { return index; }
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
+  { return index; }
 
   builtin_type_t builtin_type (void) const { return btyp_double; }
 
@@ -93,7 +94,7 @@
 
   octave_value do_index_op (const octave_value_list& idx,
                             bool resize_ok = false)
-  { return make_value ().do_index_op (idx, resize_ok); }
+  { return make_value ().index_op (idx, resize_ok); }
 
   dim_vector dims (void) const { return index.orig_dimensions (); }
 
@@ -241,9 +242,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
@@ -269,7 +270,7 @@
     return value;
   }
 
-  idx_vector index;
+  octave::idx_vector index;
   mutable octave_value value;
 
   static octave_base_value *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-magic-int.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,323 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <istream>
+#include <ostream>
+
+#include "oct-inttypes.h"
+
+#include "data-conv.h"
+#include "mach-info.h"
+#include "lo-specfun.h"
+#include "lo-mappers.h"
+
+#include "defun.h"
+#include "errwarn.h"
+#include "mxarray.h"
+#include "ovl.h"
+#include "oct-hdf5.h"
+#include "oct-stream.h"
+#include "ov-scalar.h"
+#include "ov-float.h"
+#include "ov-base.h"
+#include "ov-magic-int.h"
+#include "ov-base-scalar.h"
+#include "ov-re-mat.h"
+#include "ov-typeinfo.h"
+#include "pr-output.h"
+#include "xdiv.h"
+#include "xpow.h"
+#include "ops.h"
+
+#include "ls-oct-text.h"
+#include "ls-hdf5.h"
+
+// NOTE: Although there is some additional overhead, for all but the
+// simplest data type extraction operations, we convert to an
+// octave_scalar object and forward the operation to avoid code
+// duplication and ensure that operations on magic_int objects are
+// identical to operations on octave_scalar objects.  We could also
+// avoid code duplication by deriving octave_magic_int from
+// octave_scalar, but then we would need to store both the double and
+// octave_uint64 or octave_int64 values, doubling the storage
+// requirement.
+
+static octave_base_value *
+default_numeric_conv_fcn (const octave_base_value& a)
+{
+  return new octave_scalar (a.double_value ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::do_index_op (const octave_value_list& idx,
+                                       bool resize_ok)
+{
+  octave_value tmp (double_value ());
+
+  return tmp.index_op (idx, resize_ok);
+}
+
+template <typename T>
+octave::idx_vector
+octave_base_magic_int<T>::index_vector (bool require_integers) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.index_vector (require_integers);
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::resize (const dim_vector& dv, bool fill) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.resize (dv, fill);
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_double (void) const
+{
+  return static_cast<double> (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_single (void) const
+{
+  return static_cast<float> (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_int8 (void) const
+{
+  return octave_int8 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_int16 (void) const
+{
+  return octave_int16 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_int32 (void) const
+{
+  return octave_int32 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_int64 (void) const
+{
+  return octave_int64 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_uint8 (void) const
+{
+  return octave_uint8 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_uint16 (void) const
+{
+  return octave_uint16 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_uint32 (void) const
+{
+  return octave_uint32 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::as_uint64 (void) const
+{
+  return octave_uint64 (scalar_ref ());
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::diag (octave_idx_type m, octave_idx_type n) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.diag (m, n);
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::convert_to_str_internal (bool, bool, char type) const
+{
+  octave_value retval;
+
+  int ival;
+
+  if (scalar_ref ().value () > std::numeric_limits<unsigned char>::max ())
+    {
+      // FIXME: is there something better we could do?
+
+      ival = 0;
+
+      ::warning ("range error for conversion to character value");
+    }
+  else
+    ival = scalar_ref ().value ();
+
+  retval = octave_value (std::string (1, static_cast<char> (ival)), type);
+
+  return retval;
+}
+
+
+template <typename T>
+bool
+octave_base_magic_int<T>::save_ascii (std::ostream& os)
+{
+  octave_value tmp (double_value ());
+
+  return tmp.save_ascii (os);
+}
+
+template <typename T>
+OCTAVE_NORETURN bool
+octave_base_magic_int<T>::load_ascii (std::istream&)
+{
+  error ("octave_base_magic_int<T>::load_ascii: internal error");
+}
+
+template <typename T>
+bool
+octave_base_magic_int<T>::save_binary (std::ostream& os, bool save_as_floats)
+{
+  octave_value tmp (double_value ());
+
+  return tmp.save_binary (os, save_as_floats);
+}
+
+template <typename T>
+OCTAVE_NORETURN bool
+octave_base_magic_int<T>::load_binary (std::istream&, bool,
+                                       octave::mach_info::float_format)
+{
+  error ("octave_base_magic_int<T>::load_binary: internal error");
+}
+
+template <typename T>
+bool
+octave_base_magic_int<T>::save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                                     bool save_as_floats)
+{
+  bool retval = false;
+
+#if defined (HAVE_HDF5)
+
+  octave_value tmp (double_value ());
+
+  return tmp.save_hdf5 (loc_id, name, save_as_floats);
+
+#else
+
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+  octave_unused_parameter (save_as_floats);
+
+  octave_base_value::warn_save ("hdf5");
+
+#endif
+
+  return retval;
+}
+
+template <typename T>
+bool
+octave_base_magic_int<T>::load_hdf5 (octave_hdf5_id, const char *)
+{
+#if defined (HAVE_HDF5)
+
+  error ("octave_base_magic_int<T>::load_binary: internal error");
+
+  return false;
+
+#else
+
+  octave_base_value::warn_load ("hdf5");
+
+  return false;
+
+#endif
+}
+
+template <typename T>
+mxArray *
+octave_base_magic_int<T>::as_mxArray (bool interleaved) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.as_mxArray (interleaved);
+}
+
+template <typename T>
+octave_value
+octave_base_magic_int<T>::map (octave_base_value::unary_mapper_t umap) const
+{
+  octave_value tmp (double_value ());
+
+  return tmp.map (umap);
+}
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_magic_uint, "magic_uint",
+                                     "double");
+
+octave_base_value::type_conv_info
+octave_magic_uint::numeric_conversion_function (void) const
+{
+  return octave_base_value::type_conv_info (default_numeric_conv_fcn,
+                                            octave_scalar::static_type_id ());
+}
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_magic_int, "magic_int",
+                                     "double");
+
+octave_base_value::type_conv_info
+octave_magic_int::numeric_conversion_function (void) const
+{
+  return octave_base_value::type_conv_info (default_numeric_conv_fcn,
+                                            octave_scalar::static_type_id ());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-magic-int.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,328 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_ov_magic_int_h)
+#define octave_ov_magic_int_h 1
+
+#include "octave-config.h"
+
+#include <iosfwd>
+#include <string>
+
+#include "oct-inttypes.h"
+
+#include "ov-base.h"
+#include "ov-re-mat.h"
+#include "ov-base-scalar.h"
+#include "ov-typeinfo.h"
+
+class octave_value_list;
+
+// Large integer scalar values.  The uint64 or int64 value they contain may be
+// accessed without loss of precision when needed (for example, when
+// directly converted to a uint64 or int64 value).  Otherwise, they
+// behave like real scalars, so any operation on them will result in
+// type conversion.
+
+template <typename T>
+class
+octave_base_magic_int : public octave_base_scalar<T>
+{
+public:
+
+  octave_base_magic_int (void)
+    : octave_base_scalar<T> (0) { }
+
+  octave_base_magic_int (const T& val)
+    : octave_base_scalar<T> (val) { }
+
+  ~octave_base_magic_int (void) = default;
+
+  // We return an octave_matrix here instead of an octave_scalar so
+  // that in expressions like A(2,2,2) = 2 (for A previously
+  // undefined), A will be empty instead of a 1x1 object.
+  octave_base_value * empty_clone (void) const { return new octave_matrix (); }
+
+  // Although SCALAR is a protected member of the base class, it is not
+  // directly visible here without the explicit octave_base_slalar<T>::
+  // qualification.  Why not?
+
+  const T& scalar_ref (void) const { return octave_base_scalar<T>::scalar; }
+
+  T& scalar_ref (void) { return octave_base_scalar<T>::scalar; }
+
+  octave_value do_index_op (const octave_value_list& idx,
+                            bool resize_ok = false);
+
+  octave::idx_vector index_vector (bool require_integers = false) const;
+
+  octave_value any (int = 0) const { return scalar_ref () != T (0); }
+
+  builtin_type_t builtin_type (void) const { return btyp_double; }
+
+  bool is_storable (void) const { return false; }
+
+  bool is_magic_int (void) const { return true; }
+
+  bool is_real_scalar (void) const { return true; }
+
+  bool isreal (void) const { return true; }
+
+  bool is_double_type (void) const { return true; }
+
+  bool isfloat (void) const { return true; }
+
+  int8NDArray int8_array_value (void) const
+  { return int8NDArray (dim_vector (1, 1), double_value ()); }
+
+  int16NDArray int16_array_value (void) const
+  { return int16NDArray (dim_vector (1, 1), double_value ()); }
+
+  int32NDArray int32_array_value (void) const
+  { return int32NDArray (dim_vector (1, 1), double_value ()); }
+
+  int64NDArray int64_array_value (void) const
+  { return int64NDArray (dim_vector (1, 1), double_value ()); }
+
+  uint8NDArray uint8_array_value (void) const
+  { return uint8NDArray (dim_vector (1, 1), double_value ()); }
+
+  uint16NDArray uint16_array_value (void) const
+  { return uint16NDArray (dim_vector (1, 1), double_value ()); }
+
+  uint32NDArray uint32_array_value (void) const
+  { return uint32NDArray (dim_vector (1, 1), double_value ()); }
+
+  uint64NDArray uint64_array_value (void) const
+  { return uint64NDArray (dim_vector (1, 1), double_value ()); }
+
+  octave_int8 int8_scalar_value (void) const
+  { return octave_int8 (double_value ()); }
+
+  octave_int16 int16_scalar_value (void) const
+  { return octave_int16 (double_value ()); }
+
+  octave_int32 int32_scalar_value (void) const
+  { return octave_int32 (double_value ()); }
+
+  octave_int64 int64_scalar_value (void) const
+  { return octave_int64 (double_value ()); }
+
+  octave_uint8 uint8_scalar_value (void) const
+  { return octave_uint8 (double_value ()); }
+
+  octave_uint16 uint16_scalar_value (void) const
+  { return octave_uint16 (double_value ()); }
+
+  octave_uint32 uint32_scalar_value (void) const
+  { return octave_uint32 (double_value ()); }
+
+  octave_uint64 uint64_scalar_value (void) const
+  { return octave_uint64 (double_value ()); }
+
+  double double_value (bool = false) const
+  {
+    return scalar_ref ().double_value ();
+  }
+
+  float float_value (bool = false) const
+  { return static_cast<float> (double_value ()); }
+
+  double scalar_value (bool = false) const
+  { return double_value (); }
+
+  float float_scalar_value (bool = false) const
+  { return float_value (); }
+
+  Matrix matrix_value (bool = false) const
+  { return Matrix (1, 1, double_value ()); }
+
+  FloatMatrix float_matrix_value (bool = false) const
+  { return FloatMatrix (1, 1, float_value ()); }
+
+  NDArray array_value (bool = false) const
+  { return NDArray (dim_vector (1, 1), double_value ()); }
+
+  FloatNDArray float_array_value (bool = false) const
+  { return FloatNDArray (dim_vector (1, 1), float_value ()); }
+
+  SparseMatrix sparse_matrix_value (bool = false) const
+  { return SparseMatrix (Matrix (1, 1, double_value ())); }
+
+  // FIXME: Need SparseComplexMatrix (Matrix) constructor!
+  SparseComplexMatrix sparse_complex_matrix_value (bool = false) const
+  { return SparseComplexMatrix (sparse_matrix_value ()); }
+
+  octave_value resize (const dim_vector& dv, bool fill = false) const;
+
+  Complex complex_value (bool = false) const { return double_value (); }
+
+  FloatComplex float_complex_value (bool = false) const
+  { return FloatComplex (float_value ()); }
+
+  ComplexMatrix complex_matrix_value (bool = false) const
+  { return ComplexMatrix (1, 1, Complex (double_value ())); }
+
+  FloatComplexMatrix float_complex_matrix_value (bool = false) const
+  { return FloatComplexMatrix (1, 1, FloatComplex (float_value ())); }
+
+  ComplexNDArray complex_array_value (bool = false) const
+  { return ComplexNDArray (dim_vector (1, 1), Complex (double_value ())); }
+
+  FloatComplexNDArray float_complex_array_value (bool = false) const
+  {
+    return FloatComplexNDArray (dim_vector (1, 1),
+                                FloatComplex (float_value ()));
+  }
+
+  charNDArray
+  char_array_value (bool = false) const
+  {
+    charNDArray retval (dim_vector (1, 1));
+    retval(0) = static_cast<char> (double_value ());
+    return retval;
+  }
+
+  bool bool_value (bool warn = false) const
+  {
+    if (warn && scalar_ref () != T (0) && scalar_ref () != T (1))
+      warn_logical_conversion ();
+
+    return double_value ();
+  }
+
+  boolNDArray bool_array_value (bool warn = false) const
+  {
+    if (warn && scalar_ref () != T (0) && scalar_ref () != T (1))
+      warn_logical_conversion ();
+
+    return boolNDArray (dim_vector (1, 1), double_value ());
+  }
+
+  octave_value as_double (void) const;
+  octave_value as_single (void) const;
+
+  octave_value as_int8 (void) const;
+  octave_value as_int16 (void) const;
+  octave_value as_int32 (void) const;
+  octave_value as_int64 (void) const;
+
+  octave_value as_uint8 (void) const;
+  octave_value as_uint16 (void) const;
+  octave_value as_uint32 (void) const;
+  octave_value as_uint64 (void) const;
+
+  // We don't need to override both forms of the diag method.  The using
+  // declaration will avoid warnings about partially-overloaded virtual
+  // functions.
+  using octave_base_scalar<T>::diag;
+
+  octave_value diag (octave_idx_type m, octave_idx_type n) const;
+
+  octave_value convert_to_str_internal (bool pad, bool force, char type) const;
+
+  void increment (void) { scalar_ref () += T (1); }
+
+  void decrement (void) { scalar_ref () -= T (1); }
+
+  bool save_ascii (std::ostream& os);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap,
+                    octave::mach_info::float_format fmt);
+
+  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
+
+  bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
+
+  int write (octave::stream& os, int block_size,
+             oct_data_conv::data_type output_type, int skip,
+             octave::mach_info::float_format flt_fmt) const
+  {
+    return os.write (array_value (), block_size, output_type,
+                     skip, flt_fmt);
+  }
+
+  mxArray * as_mxArray (bool interleaved) const;
+
+  octave_value map (octave_base_value::unary_mapper_t umap) const;
+};
+
+class
+OCTINTERP_API
+octave_magic_uint : public octave_base_magic_int<octave_uint64>
+{
+public:
+
+  octave_magic_uint (void)
+    : octave_base_magic_int<octave_uint64> (0) { }
+
+  octave_magic_uint (const octave_uint64& val)
+    : octave_base_magic_int<octave_uint64> (val) { }
+
+  ~octave_magic_uint (void) = default;
+
+  octave_base_value * clone (void) const
+  {
+    return new octave_magic_uint (*this);
+  }
+
+  type_conv_info numeric_conversion_function (void) const;
+
+private:
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+class
+OCTINTERP_API
+octave_magic_int : public octave_base_magic_int<octave_int64>
+{
+public:
+
+  octave_magic_int (void)
+    : octave_base_magic_int<octave_int64> (0) { }
+
+  octave_magic_int (const octave_int64& val)
+    : octave_base_magic_int<octave_int64> (val) { }
+
+  ~octave_magic_int (void) = default;
+
+  octave_base_value * clone (void) const
+  {
+    return new octave_magic_int (*this);
+  }
+
+  type_conv_info numeric_conversion_function (void) const;
+
+private:
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+#endif
--- a/libinterp/octave-value/ov-mex-fcn.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-mex-fcn.cc	Sun May 16 09:44:35 2021 +0200
@@ -47,10 +47,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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-mex-fcn.h	Sun May 16 09:44:35 2021 +0200
@@ -52,10 +52,12 @@
 public:
 
   octave_mex_function (void)
-    : m_mex_fcn_ptr (), m_exit_fcn_ptr (), m_is_fmex (), m_sh_lib (),
-      m_time_checked (), m_is_system_fcn_file () { }
+    : m_mex_fcn_ptr (nullptr), m_exit_fcn_ptr (nullptr), m_sh_lib (),
+      m_time_checked (), m_interleaved (false), m_is_fmex (false),
+      m_is_system_fcn_file (false)
+  { }
 
-  octave_mex_function (void *fptr, bool fmex,
+  octave_mex_function (void *fptr, bool interleaved, bool fmex,
                        const octave::dynamic_library& shl,
                        const std::string& nm = "");
 
@@ -88,6 +90,8 @@
 
   bool is_mex_function (void) const { return true; }
 
+  bool use_interleaved_complex (void) const { return m_interleaved; }
+
   octave_value_list
   execute (octave::tree_evaluator& tw, int nargout = 0,
            const octave_value_list& args = octave_value_list ());
@@ -106,14 +110,16 @@
 
   void (*m_exit_fcn_ptr) (void);
 
-  bool m_is_fmex;
-
   octave::dynamic_library m_sh_lib;
 
   // The time the file was last checked to see if it needs to be
   // parsed again.
   mutable octave::sys::time m_time_checked;
 
+  bool m_interleaved;
+
+  bool m_is_fmex;
+
   // True if this function came from a file that is considered to be a
   // system function.  This affects whether we check the time stamp
   // on the file to see if it has changed.
--- a/libinterp/octave-value/ov-null-mat.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-null-mat.h	Sun May 16 09:44:35 2021 +0200
@@ -72,6 +72,8 @@
 
   static const octave_value instance;
 
+  bool is_storable (void) const { return false; }
+
   bool isnull (void) const { return true; }
 
   type_conv_info numeric_conversion_function (void) const;
@@ -93,6 +95,8 @@
 
   static const octave_value instance;
 
+  bool is_storable (void) const { return false; }
+
   bool isnull (void) const { return true; }
 
   type_conv_info numeric_conversion_function (void) const;
--- a/libinterp/octave-value/ov-perm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-perm.cc	Sun May 16 09:44:35 2021 +0200
@@ -74,7 +74,7 @@
 {
   octave_value retval;
   octave_idx_type nidx = idx.length ();
-  idx_vector idx0, idx1;
+  octave::idx_vector idx0, idx1;
   if (nidx == 2)
     {
       int k = 0;    // index we're processing when index_vector throws
@@ -84,10 +84,10 @@
           k = 1;
           idx1 = idx(1).index_vector ();
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
           // Rethrow to allow more info to be reported later.
-          e.set_pos_if_unset (2, k+1);
+          ie.set_pos_if_unset (2, k+1);
           throw;
         }
     }
@@ -128,7 +128,7 @@
       if (nidx == 2 && ! resize_ok && idx0.is_scalar () && idx1.is_scalar ())
         retval = matrix.checkelem (idx0(0), idx1(0));
       else
-        retval = to_dense ().do_index_op (idx, resize_ok);
+        retval = to_dense ().index_op (idx, resize_ok);
     }
 
   return retval;
@@ -240,7 +240,7 @@
 FORWARD_MATRIX_VALUE (boolNDArray, bool_array)
 FORWARD_MATRIX_VALUE (charNDArray, char_array)
 
-idx_vector
+octave::idx_vector
 octave_perm_matrix::index_vector (bool require_integers) const
 {
   return to_dense ().index_vector (require_integers);
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-perm.h	Sun May 16 09:44:35 2021 +0200
@@ -146,7 +146,7 @@
   double scalar_value (bool frc_str_conv = false) const
   { return double_value (frc_str_conv); }
 
-  idx_vector index_vector (bool require_integers = false) const;
+  octave::idx_vector index_vector (bool require_integers = false) const;
 
   PermMatrix perm_matrix_value (void) const
   { return matrix; }
@@ -240,7 +240,7 @@
              oct_data_conv::data_type output_type, int skip,
              octave::mach_info::float_format flt_fmt) const;
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   bool print_as_scalar (void) const;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-range-traits.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,154 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_ov_range_traits_h)
+#define octave_ov_range_traits_h 1
+
+#include "octave-config.h"
+
+#include "ov-bool-mat.h"
+#include "ov-bool.h"
+#include "ov-float.h"
+#include "ov-flt-re-mat.h"
+#include "ov-int16.h"
+#include "ov-int32.h"
+#include "ov-int64.h"
+#include "ov-int8.h"
+#include "ov-re-mat.h"
+#include "ov-scalar.h"
+#include "ov-uint16.h"
+#include "ov-uint32.h"
+#include "ov-uint64.h"
+#include "ov-uint8.h"
+
+template <typename T>
+class
+octave_value_range_traits
+{
+public:
+  typedef T scalar_type;
+  typedef T matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<bool>
+{
+public:
+  typedef octave_bool scalar_type;
+  typedef octave_bool_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<float>
+{
+public:
+  typedef octave_float_scalar scalar_type;
+  typedef octave_float_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<double>
+{
+public:
+  typedef octave_scalar scalar_type;
+  typedef octave_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_int8>
+{
+public:
+  typedef octave_int8_scalar scalar_type;
+  typedef octave_int8_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_int16>
+{
+public:
+  typedef octave_int16_scalar scalar_type;
+  typedef octave_int16_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_int32>
+{
+public:
+  typedef octave_int32_scalar scalar_type;
+  typedef octave_int32_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_int64>
+{
+public:
+  typedef octave_int64_scalar scalar_type;
+  typedef octave_int64_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_uint8>
+{
+public:
+  typedef octave_uint8_scalar scalar_type;
+  typedef octave_uint8_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_uint16>
+{
+public:
+  typedef octave_uint16_scalar scalar_type;
+  typedef octave_uint16_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_uint32>
+{
+public:
+  typedef octave_uint32_scalar scalar_type;
+  typedef octave_uint32_matrix matrix_type;
+};
+
+template <>
+class
+octave_value_range_traits<octave_uint64>
+{
+public:
+  typedef octave_uint64_scalar scalar_type;
+  typedef octave_uint64_matrix matrix_type;
+};
+
+#endif
--- a/libinterp/octave-value/ov-range.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-range.cc	Sun May 16 09:44:35 2021 +0200
@@ -23,9 +23,9 @@
 //
 ////////////////////////////////////////////////////////////////////////
 
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
+// This file should not include config.h.  It is only included in other
+// C++ source files that should have included config.h before including
+// this file.
 
 #include <istream>
 #include <ostream>
@@ -49,9 +49,11 @@
 #include "variables.h"
 #include "errwarn.h"
 #include "mxarray.h"
+#include "mx-type-traits.h"
 #include "ops.h"
 #include "ovl.h"
 #include "oct-hdf5.h"
+#include "ov-range-traits.h"
 #include "ov-range.h"
 #include "ov-re-mat.h"
 #include "ov-scalar.h"
@@ -62,41 +64,148 @@
 #include "ls-hdf5.h"
 #include "ls-utils.h"
 
+#if defined (HAVE_HDF5)
 
-DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range", "double");
+template <>
+octave_hdf5_id ov_range<float>::hdf5_save_type = H5T_NATIVE_FLOAT;
+
+template <>
+octave_hdf5_id ov_range<double>::hdf5_save_type = H5T_NATIVE_DOUBLE;
+
+template <>
+octave_hdf5_id ov_range<octave_int8>::hdf5_save_type = H5T_NATIVE_INT8;
+
+template <>
+octave_hdf5_id ov_range<octave_int16>::hdf5_save_type = H5T_NATIVE_INT16;
+
+template <>
+octave_hdf5_id ov_range<octave_int32>::hdf5_save_type = H5T_NATIVE_INT32;
+
+template <>
+octave_hdf5_id ov_range<octave_int64>::hdf5_save_type = H5T_NATIVE_INT64;
+
+template <>
+octave_hdf5_id ov_range<octave_uint8>::hdf5_save_type = H5T_NATIVE_UINT8;
+
+template <>
+octave_hdf5_id ov_range<octave_uint16>::hdf5_save_type = H5T_NATIVE_UINT16;
+
+template <>
+octave_hdf5_id ov_range<octave_uint32>::hdf5_save_type = H5T_NATIVE_UINT32;
+
+template <>
+octave_hdf5_id ov_range<octave_uint64>::hdf5_save_type = H5T_NATIVE_UINT64;
+
+#else
+
+template <>
+octave_hdf5_id ov_range<float>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<double>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_int8>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_int16>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_int32>::hdf5_save_type = 0;
 
+template <>
+octave_hdf5_id ov_range<octave_int64>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_uint8>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_uint16>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_uint32>::hdf5_save_type = 0;
+
+template <>
+octave_hdf5_id ov_range<octave_uint64>::hdf5_save_type = 0;
+
+#endif
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<float>,
+                                              "float_range", "single");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<double>,
+                                              "range", "double");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int8>,
+                                              "int8_range", "int8");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int16>,
+                                              "int16_range", "int16");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int32>,
+                                              "int32_range", "int32");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_int64>,
+                                              "int64_range", "int64");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint8>,
+                                              "uint8_range", "uint8");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint16>,
+                                              "uint16_range", "uint16");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint32>,
+                                              "uint32_range", "uint32");
+
+DEFINE_TEMPLATE_OV_TYPEID_FUNCTIONS_AND_DATA (ov_range<octave_uint64>,
+                                              "uint64_range", "uint64");
+
+template <typename T>
 static octave_base_value *
 default_numeric_conversion_function (const octave_base_value& a)
 {
-  const octave_range& v = dynamic_cast<const octave_range&> (a);
+  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
 
-  return new octave_matrix (v.matrix_value ());
+  const ov_range<T>& v = dynamic_cast<const ov_range<T>&> (a);
+
+  return new ov_mx_type (v.raw_array_value ());
 }
 
+template <typename T>
 octave_base_value::type_conv_info
-octave_range::numeric_conversion_function (void) const
+ov_range<T>::numeric_conversion_function (void) const
 {
-  return octave_base_value::type_conv_info (default_numeric_conversion_function,
-                                            octave_matrix::static_type_id ());
+  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+
+  return octave_base_value::type_conv_info
+    (default_numeric_conversion_function<T>, ov_mx_type::static_type_id ());
 }
 
+template <typename T>
 octave_base_value *
-octave_range::try_narrowing_conversion (void)
+ov_range<T>::try_narrowing_conversion (void)
 {
   octave_base_value *retval = nullptr;
 
-  switch (range.numel ())
+  switch (numel ())
     {
     case 1:
-      retval = new octave_scalar (range.base ());
+      retval = new typename octave_value_range_traits<T>::scalar_type (m_range.elem (0));
       break;
 
     case 0:
-      retval = new octave_matrix (Matrix (1, 0));
+      {
+        typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+        typename ov_mx_type::object_type m (dim_vector (1, 0));
+        retval = new ov_mx_type (m);
+      }
       break;
 
     case -2:
-      retval = new octave_matrix (range.matrix_value ());
+      // FIXME: is this case possible now?  It would have to be due to
+      // conversion from Range to range<double>, but even in that case,
+      // is the invalid numel value preserved?
+      retval = new typename octave_value_range_traits<T>::matrix_type (raw_array_value ());
       break;
 
     default:
@@ -106,9 +215,10 @@
   return retval;
 }
 
+template <typename T>
 octave_value
-octave_range::subsref (const std::string& type,
-                       const std::list<octave_value_list>& idx)
+ov_range<T>::subsref (const std::string& type,
+                      const std::list<octave_value_list>& idx)
 {
   octave_value retval;
 
@@ -133,8 +243,10 @@
   return retval.next_subsref (type, idx);
 }
 
+template <typename T>
 octave_value
-octave_range::do_index_op (const octave_value_list& idx, bool resize_ok)
+ov_range<T>::do_index_op (const octave_value_list& idx,
+                                   bool resize_ok)
 {
   if (idx.length () == 1 && ! resize_ok)
     {
@@ -144,18 +256,18 @@
 
       try
         {
-          idx_vector i = idx(0).index_vector ();
+          octave::idx_vector i = idx(0).index_vector ();
 
-          if (i.is_scalar () && i(0) < range.numel ())
-            retval = range.elem (i(0));
+          if (i.is_scalar () && i(0) < numel ())
+            retval = m_range.elem (i(0));
           else
-            retval = range.index (i);
+            retval = m_range.index (i);
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
           // More info may be added later before displaying error.
 
-          e.set_pos_if_unset (1, 1);
+          ie.set_pos_if_unset (1, 1);
           throw;
         }
 
@@ -163,35 +275,25 @@
     }
   else
     {
-      octave_value tmp (new octave_matrix (range.matrix_value ()));
+      octave_value tmp (new typename octave_value_range_traits<T>::matrix_type (raw_array_value ()));
 
-      return tmp.do_index_op (idx, resize_ok);
+      return tmp.index_op (idx, resize_ok);
     }
 }
 
-idx_vector
-octave_range::index_vector (bool require_integers) const
+template <typename T>
+octave::idx_vector
+ov_range<T>::index_vector (bool require_integers) const
 {
-  if (idx_cache)
-    return *idx_cache;
-  else
-    {
-      if (require_integers || range.all_elements_are_ints ())
-        return set_idx_cache (idx_vector (range));
-      else
-        {
-          warning_with_id ("Octave:noninteger-range-as-index",
-                           "non-integer range used as index");
-
-          return octave_value (matrix_value ()).round ().index_vector ();
-        }
-    }
+  octave_value tmp (raw_array_value ());
+  return tmp.index_vector (require_integers);
 }
 
+template <typename T>
 double
-octave_range::double_value (bool) const
+ov_range<T>::double_value (bool) const
 {
-  octave_idx_type nel = range.numel ();
+  octave_idx_type nel = numel ();
 
   if (nel == 0)
     err_invalid_conversion ("range", "real scalar");
@@ -199,13 +301,14 @@
   warn_implicit_conversion ("Octave:array-to-scalar",
                             "range", "real scalar");
 
-  return range.base ();
+  return m_range.base ();
 }
 
+template <typename T>
 float
-octave_range::float_value (bool) const
+ov_range<T>::float_value (bool) const
 {
-  octave_idx_type nel = range.numel ();
+  octave_idx_type nel = numel ();
 
   if (nel == 0)
     err_invalid_conversion ("range", "real scalar");
@@ -213,13 +316,14 @@
   warn_implicit_conversion ("Octave:array-to-scalar",
                             "range", "real scalar");
 
-  return range.base ();
+  return m_range.base ();
 }
 
+template <typename T>
 charNDArray
-octave_range::char_array_value (bool) const
+ov_range<T>::char_array_value (bool) const
 {
-  const Matrix matrix = range.matrix_value ();
+  const Array<T> matrix = raw_array_value ();
   charNDArray retval (dims ());
 
   octave_idx_type nel = numel ();
@@ -230,85 +334,11 @@
   return retval;
 }
 
-octave_value
-octave_range::all (int dim) const
-{
-  // FIXME: this is a potential waste of memory.
-
-  Matrix m = range.matrix_value ();
-
-  return m.all (dim);
-}
-
-octave_value
-octave_range::any (int dim) const
-{
-  // FIXME: this is a potential waste of memory.
-
-  Matrix m = range.matrix_value ();
-
-  return m.any (dim);
-}
-
-octave_value
-octave_range::diag (octave_idx_type k) const
-{
-  return
-    (k == 0
-       ? octave_value (DiagMatrix (DiagArray2<double> (range.matrix_value ())))
-       : octave_value (range.diag (k)));
-}
-
-octave_value
-octave_range::diag (octave_idx_type m, octave_idx_type n) const
+template <typename T>
+Complex
+ov_range<T>::complex_value (bool) const
 {
-  Matrix mat = range.matrix_value ();
-
-  return mat.diag (m, n);
-}
-
-// Return true if this range has all true elements (non-zero, not NaN/NA).
-// A range cannot have NaN/NA.
-bool
-octave_range::is_true (void) const
-{
-  bool retval = false;
-
-  if (! range.isempty ())
-    {
-      if (dims ().numel () > 1)
-        warn_array_as_logical (dims ());
-
-      Range r = range_value ();
-      double base = r.base ();
-      double limit = r.limit ();
-
-      // Can't be zero if we start and finish on the same size of 0
-      if (((base > 0 && limit > 0) || (base < 0 && limit < 0)) && numel () > 0)
-        retval = true;
-      else
-        {
-          /*
-          // This tells us whether one element is 0, if arithmetic is exact.
-          double steps_to_zero = base / r.inc ();
-
-          retval = (steps_to_zero != floor (steps_to_zero));
-          */
-
-          // FIXME: this is a waste of memory.
-          Matrix m ((range.matrix_value ().all ()).all ());
-
-          retval = ! m.isempty () && m(0, 0) != 0.0;
-        }
-    }
-
-  return retval;
-}
-
-Complex
-octave_range::complex_value (bool) const
-{
-  octave_idx_type nel = range.numel ();
+  octave_idx_type nel = numel ();
 
   if (nel == 0)
     err_invalid_conversion ("range", "complex scalar");
@@ -316,17 +346,18 @@
   warn_implicit_conversion ("Octave:array-to-scalar",
                             "range", "complex scalar");
 
-  return Complex (range.base (), 0);
+  return Complex (m_range.base (), 0);
 }
 
+template <typename T>
 FloatComplex
-octave_range::float_complex_value (bool) const
+ov_range<T>::float_complex_value (bool) const
 {
   float tmp = lo_ieee_float_nan_value ();
 
   FloatComplex retval (tmp, tmp);
 
-  octave_idx_type nel = range.numel ();
+  octave_idx_type nel = numel ();
 
   if (nel == 0)
     err_invalid_conversion ("range", "complex scalar");
@@ -334,28 +365,28 @@
   warn_implicit_conversion ("Octave:array-to-scalar",
                             "range", "complex scalar");
 
-  retval = range.base ();
+  retval = m_range.base ();
 
   return retval;
 }
 
+template <typename T>
 boolNDArray
-octave_range::bool_array_value (bool warn) const
+ov_range<T>::bool_array_value (bool warn) const
 {
-  Matrix m = range.matrix_value ();
+  Array<T> matrix = raw_array_value ();
 
-  if (m.any_element_is_nan ())
-    octave::err_nan_to_logical_conversion ();
-  if (warn && m.any_element_not_one_or_zero ())
+  if (warn && ! matrix.test_all (xis_one_or_zero<T>))
     warn_logical_conversion ();
 
-  return boolNDArray (m);
+  return boolNDArray (matrix);
 }
 
+template <typename T>
 octave_value
-octave_range::resize (const dim_vector& dv, bool fill) const
+ov_range<T>::resize (const dim_vector& dv, bool fill) const
 {
-  NDArray retval = array_value ();
+  Array<T> retval = raw_array_value ();
   if (fill)
     retval.resize (dv, 0);
   else
@@ -363,93 +394,184 @@
   return retval;
 }
 
+template <typename T>
+octave::range<float>
+ov_range<T>::float_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::float_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<double>
+ov_range<T>::range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::range_value()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_int8>
+ov_range<T>::int8_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::int8_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_int16>
+ov_range<T>::int16_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::int16_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_int32>
+ov_range<T>::int32_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::int32_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_int64>
+ov_range<T>::int64_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::int64_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_uint8>
+ov_range<T>::uint8_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::uint8_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_uint16>
+ov_range<T>::uint16_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::uint16_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_uint32>
+ov_range<T>::uint32_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::uint32_range_value ()", type_name ());
+}
+
+template <typename T>
+octave::range<octave_uint64>
+ov_range<T>::uint64_range_value (void) const
+{
+  err_wrong_type_arg ("ov_range<T>::uint64_range_value ()", type_name ());
+}
+
+template <typename T>
 octave_value
-octave_range::convert_to_str_internal (bool pad, bool force, char type) const
+ov_range<T>::convert_to_str_internal (bool pad, bool force, char type) const
 {
-  octave_value tmp (range.matrix_value ());
+  octave_value tmp (raw_array_value ());
   return tmp.convert_to_str (pad, force, type);
 }
 
+// FIXME: could most of these fucntions preserve range type now?
+
+template <typename T>
 octave_value
-octave_range::as_double (void) const
+ov_range<T>::as_double (void) const
 {
-  return range;
+  return NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_single (void) const
+ov_range<T>::as_single (void) const
 {
-  return FloatMatrix (range.matrix_value ());
+  return FloatMatrix (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_int8 (void) const
+ov_range<T>::as_int8 (void) const
 {
-  return int8NDArray (range.matrix_value ());
+  return int8NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_int16 (void) const
+ov_range<T>::as_int16 (void) const
 {
-  return int16NDArray (range.matrix_value ());
+  return int16NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_int32 (void) const
+ov_range<T>::as_int32 (void) const
 {
-  return int32NDArray (range.matrix_value ());
+  return int32NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_int64 (void) const
+ov_range<T>::as_int64 (void) const
 {
-  return int64NDArray (range.matrix_value ());
+  return int64NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_uint8 (void) const
+ov_range<T>::as_uint8 (void) const
 {
-  return uint8NDArray (range.matrix_value ());
+  return uint8NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_uint16 (void) const
+ov_range<T>::as_uint16 (void) const
 {
-  return uint16NDArray (range.matrix_value ());
+  return uint16NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_uint32 (void) const
+ov_range<T>::as_uint32 (void) const
 {
-  return uint32NDArray (range.matrix_value ());
+  return uint32NDArray (raw_array_value ());
 }
 
+template <typename T>
 octave_value
-octave_range::as_uint64 (void) const
+ov_range<T>::as_uint64 (void) const
 {
-  return uint64NDArray (range.matrix_value ());
+  return uint64NDArray (raw_array_value ());
 }
 
+template <typename T>
 void
-octave_range::print (std::ostream& os, bool pr_as_read_syntax)
+ov_range<T>::print (std::ostream& os, bool pr_as_read_syntax)
 {
   print_raw (os, pr_as_read_syntax);
   newline (os);
 }
 
+template <typename T>
 void
-octave_range::print_raw (std::ostream& os, bool pr_as_read_syntax) const
+ov_range<T>::print_raw (std::ostream& os, bool pr_as_read_syntax) const
 {
-  octave_print_internal (os, range, pr_as_read_syntax,
+  // FIXME: this is a potential waste of memory.
+
+  typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+  typename ov_mx_type::object_type tmp (raw_array_value ());
+
+  octave_print_internal (os, tmp, pr_as_read_syntax,
                          current_print_indent_level ());
 }
 
+template <typename T>
 bool
-octave_range::print_name_tag (std::ostream& os, const std::string& name) const
+ov_range<T>::print_name_tag (std::ostream& os, const std::string& name) const
 {
   bool retval = false;
 
-  octave_idx_type n = range.numel ();
+  octave_idx_type n = numel ();
 
   indent (os);
 
@@ -468,23 +590,24 @@
   return retval;
 }
 
+template <typename T>
 void
-octave_range::short_disp (std::ostream& os) const
+ov_range<T>::short_disp (std::ostream& os) const
 {
-  octave_idx_type len = range.numel ();
+  octave_idx_type len = numel ();
 
   if (len == 0)
     os << "[]";
   else
     {
-      os << range.base () << ':';
+      os << m_range.base () << ':';
 
       if (len > 1)
         {
-          if (range.inc () != 1)
-            os << range.inc () << ':';
+          if (m_range.increment () != T (1))
+            os << m_range.increment () << ':';
 
-          os << range.limit ();
+          os << m_range.limit ();
         }
     }
 }
@@ -506,111 +629,127 @@
   skip_until_newline (is, false);
 }
 
+template <typename T>
 float_display_format
-octave_range::get_edit_display_format (void) const
+ov_range<T>::get_edit_display_format (void) const
 {
-  return make_format (range_value ());
+  return make_format (m_range);
 }
 
+template <typename T>
 std::string
-octave_range::edit_display (const float_display_format& fmt,
-                            octave_idx_type, octave_idx_type j) const
+ov_range<T>::edit_display (const float_display_format& fmt,
+                           octave_idx_type, octave_idx_type j) const
 {
   std::ostringstream buf;
-  octave_print_internal (buf, fmt, range.elem (j));
+  octave_print_internal (buf, fmt, m_range.elem (j));
   return buf.str ();
 }
 
+template <typename T>
 bool
-octave_range::save_ascii (std::ostream& os)
+ov_range<T>::save_ascii (std::ostream& os)
 {
-  Range r = range_value ();
-  double base = r.base ();
-  double limit = r.limit ();
-  double inc = r.inc ();
+  octave::range<T> r = m_range;
+  T base = r.base ();
+  T limit = r.limit ();
+  T inc = r.increment ();
   octave_idx_type len = r.numel ();
 
-  if (inc != 0)
+  if (inc != T (0))
     os << "# base, limit, increment\n";
   else
     os << "# base, length, increment\n";
 
-  octave_write_double (os, base);
+  octave::write_value<T> (os, base);
   os << ' ';
-  if (inc != 0)
-    octave_write_double (os, limit);
+  if (inc != T (0))
+    octave::write_value<T> (os, limit);
   else
     os << len;
   os << ' ';
-  octave_write_double (os, inc);
+  octave::write_value<T> (os, inc);
   os << "\n";
 
   return true;
 }
 
+template <typename T>
 bool
-octave_range::load_ascii (std::istream& is)
+ov_range<T>::load_ascii (std::istream& is)
 {
   // # base, limit, range comment added by save ().
   skip_comments (is);
 
-  double base, limit, inc;
+  T base, limit, inc;
   is >> base >> limit >> inc;
 
   if (! is)
     error ("load: failed to load range constant");
 
-  if (inc != 0)
-    range = Range (base, limit, inc);
+  if (inc != T (0))
+    m_range = octave::range<T> (base, limit, inc);
   else
-    range = Range (base, inc, static_cast<octave_idx_type> (limit));
+    {
+      octave_idx_type numel = static_cast<octave_idx_type> (limit);
+      m_range = octave::range<T>::make_constant (base, numel);
+    }
 
   return true;
 }
 
+template <typename T>
 bool
-octave_range::save_binary (std::ostream& os, bool /* save_as_floats */)
+ov_range<T>::save_binary (std::ostream& os, bool /* save_as_floats */)
 {
+  // FIXME: Not always double!
+
   char tmp = LS_DOUBLE;
   os.write (reinterpret_cast<char *> (&tmp), 1);
-  Range r = range_value ();
-  double bas = r.base ();
-  double lim = r.limit ();
-  double inc = r.inc ();
-  if (inc == 0)
+  octave::range<T> r = m_range;
+  T bas = r.base ();
+  T lim = r.limit ();
+  T inc = r.increment ();
+  if (inc == T (0))
     lim = r.numel ();
 
-  os.write (reinterpret_cast<char *> (&bas), 8);
-  os.write (reinterpret_cast<char *> (&lim), 8);
-  os.write (reinterpret_cast<char *> (&inc), 8);
+  os.write (reinterpret_cast<char *> (&bas), sizeof (T));
+  os.write (reinterpret_cast<char *> (&lim), sizeof (T));
+  os.write (reinterpret_cast<char *> (&inc), sizeof (T));
 
   return true;
 }
 
+template <typename T>
 bool
-octave_range::load_binary (std::istream& is, bool swap,
-                           octave::mach_info::float_format /* fmt */)
+ov_range<T>::load_binary (std::istream& is, bool swap,
+                                   octave::mach_info::float_format /* fmt */)
 {
+  // FIXME: Not always double!
+
   char tmp;
   if (! is.read (reinterpret_cast<char *> (&tmp), 1))
     return false;
-  double bas, lim, inc;
-  if (! is.read (reinterpret_cast<char *> (&bas), 8))
+  T bas, lim, inc;
+  if (! is.read (reinterpret_cast<char *> (&bas), sizeof (T)))
     return false;
   if (swap)
-    swap_bytes<8> (&bas);
-  if (! is.read (reinterpret_cast<char *> (&lim), 8))
+    swap_bytes<sizeof (T)> (&bas);
+  if (! is.read (reinterpret_cast<char *> (&lim), sizeof (T)))
     return false;
   if (swap)
-    swap_bytes<8> (&lim);
-  if (! is.read (reinterpret_cast<char *> (&inc), 8))
+    swap_bytes<sizeof (T)> (&lim);
+  if (! is.read (reinterpret_cast<char *> (&inc), sizeof (T)))
     return false;
   if (swap)
-    swap_bytes<8> (&inc);
-  if (inc != 0)
-    range = Range (bas, lim, inc);
+    swap_bytes<sizeof (T)> (&inc);
+  if (inc != T (0))
+    m_range = octave::range<T> (bas, inc, lim);
   else
-    range = Range (bas, inc, static_cast<octave_idx_type> (lim));
+    {
+      octave_idx_type numel = static_cast<octave_idx_type> (lim);
+      m_range = octave::range<T>::make_constant (bas, numel);
+    }
 
   return true;
 }
@@ -623,23 +762,25 @@
 // H5T_NATIVE_DOUBLE to save as 'double').  Note that any necessary
 // conversions are handled automatically by HDF5.
 
+template <typename T>
 static hid_t
 hdf5_make_range_type (hid_t num_type)
 {
-  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
+  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (T) * 3);
 
-  H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
-  H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
-  H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
+  H5Tinsert (type_id, "base", 0 * sizeof (T), num_type);
+  H5Tinsert (type_id, "limit", 1 * sizeof (T), num_type);
+  H5Tinsert (type_id, "increment", 2 * sizeof (T), num_type);
 
   return type_id;
 }
 
 #endif
 
+template <typename T>
 bool
-octave_range::save_hdf5 (octave_hdf5_id loc_id, const char *name,
-                         bool /* save_as_floats */)
+ov_range<T>::save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                        bool /* save_as_floats */)
 {
   bool retval = false;
 
@@ -652,7 +793,7 @@
   space_hid = H5Screate_simple (0, dimens, nullptr);
   if (space_hid < 0) return false;
 
-  type_hid = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
+  type_hid = hdf5_make_range_type<T> (hdf5_save_type);
   if (type_hid < 0)
     {
       H5Sclose (space_hid);
@@ -671,11 +812,11 @@
       return false;
     }
 
-  Range r = range_value ();
-  double range_vals[3];
+  octave::range<T> r = m_range;
+  T range_vals[3];
   range_vals[0] = r.base ();
-  range_vals[1] = (r.inc () != 0 ? r.limit () : r.numel ());
-  range_vals[2] = r.inc ();
+  range_vals[1] = (r.increment () != T (0) ? r.limit () : r.numel ());
+  range_vals[2] = r.increment ();
 
   if (H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
                 octave_H5P_DEFAULT, range_vals)
@@ -702,8 +843,9 @@
   return retval;
 }
 
+template <typename T>
 bool
-octave_range::load_hdf5 (octave_hdf5_id loc_id, const char *name)
+ov_range<T>::load_hdf5 (octave_hdf5_id loc_id, const char *name)
 {
   bool retval = false;
 
@@ -716,7 +858,7 @@
 #endif
   hid_t type_hid = H5Dget_type (data_hid);
 
-  hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
+  hid_t range_type = hdf5_make_range_type<T> (hdf5_save_type);
 
   if (! hdf5_types_compatible (type_hid, range_type))
     {
@@ -736,23 +878,21 @@
       return false;
     }
 
-  double rangevals[3];
+  T rangevals[3];
   if (H5Dread (data_hid, range_type, octave_H5S_ALL, octave_H5S_ALL,
                octave_H5P_DEFAULT, rangevals)
       >= 0)
     {
       retval = true;
-      octave_idx_type nel;
-      if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX,
-                                "OCTAVE_RANGE_NELEM", &nel))
-        range = Range (rangevals[0], rangevals[2], nel);
+
+      // Don't use OCTAVE_RANGE_NELEM attribute, just reconstruct the range.
+
+      if (rangevals[2] != T (0))
+        m_range = octave::range<T> (rangevals[0], rangevals[1], rangevals[2]);
       else
         {
-          if (rangevals[2] != 0)
-            range = Range (rangevals[0], rangevals[1], rangevals[2]);
-          else
-            range = Range (rangevals[0], rangevals[2],
-                           static_cast<octave_idx_type> (rangevals[1]));
+          octave_idx_type numel = static_cast<octave_idx_type> (rangevals[1]);
+          m_range = octave::range<T>::make_constant (rangevals[0], numel);
         }
     }
 
@@ -770,28 +910,161 @@
   return retval;
 }
 
+template <typename T>
 mxArray *
-octave_range::as_mxArray (void) const
+ov_range<T>::as_mxArray (bool interleaved) const
 {
-  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
+  mxClassID mx_class = mx_type_traits<T>::mx_class;
 
-  double *pr = static_cast<double *> (retval->get_data ());
+  mxArray *retval = new mxArray (interleaved, mx_class, dims (), mxREAL);
+
+  typedef typename mx_type_traits<T>::mx_type mx_type;
+  mx_type *pd = static_cast<mx_type *> (retval->get_data ());
 
   mwSize nel = numel ();
 
-  Matrix m = matrix_value ();
+  Array<T> matrix = raw_array_value ();
 
-  const double *p = m.data ();
+  const T *pdata = matrix.data ();
 
   for (mwSize i = 0; i < nel; i++)
-    pr[i] = p[i];
+    pd[i] = pdata[i];
 
   return retval;
 }
 
+template <typename T>
 octave_value
-octave_range::fast_elem_extract (octave_idx_type n) const
+ov_range<T>::fast_elem_extract (octave_idx_type n) const
+{
+  return (n < numel () ? octave_value (m_range.elem (n)) : octave_value ());
+}
+
+// Specializations.
+
+template <>
+octave::range<float>
+ov_range<float>::float_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<double>
+ov_range<double>::range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_int8>
+ov_range<octave_int8>::int8_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_int16>
+ov_range<octave_int16>::int16_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_int32>
+ov_range<octave_int32>::int32_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_int64>
+ov_range<octave_int64>::int64_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_uint8>
+ov_range<octave_uint8>::uint8_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_uint16>
+ov_range<octave_uint16>::uint16_range_value (void) const
 {
-  return (n < range.numel ()) ? octave_value (range.elem (n))
-                              : octave_value ();
+  return m_range;
+}
+
+template <>
+octave::range<octave_uint32>
+ov_range<octave_uint32>::uint32_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::range<octave_uint64>
+ov_range<octave_uint64>::uint64_range_value (void) const
+{
+  return m_range;
+}
+
+template <>
+octave::idx_vector
+ov_range<double>::index_vector (bool require_integers) const
+{
+  if (m_idx_cache)
+    return *m_idx_cache;
+
+  if (require_integers || m_range.all_elements_are_ints ())
+    return set_idx_cache (octave::idx_vector (m_range));
+
+  warning_with_id ("Octave:noninteger-range-as-index",
+                   "non-integer range used as index");
+
+  return octave_value (matrix_value ()).round ().index_vector ();
 }
+
+template <>
+octave_idx_type
+ov_range<double>::nnz (void) const
+{
+  return m_range.nnz ();
+}
+
+// The following specialization is also historical baggage.  For double
+// ranges, we can produce special double-valued diagnoal matrix objects
+// but Octave currently provides only double and Complex diagonal matrix
+// objects.
+
+template <>
+octave_value
+ov_range<double>::diag (octave_idx_type k) const
+{
+  // FIXME: this is a potential waste of memory.
+
+  return
+    (k == 0
+     ? octave_value (DiagMatrix (DiagArray2<double> (matrix_value ())))
+     : octave_value (m_range.diag (k)));
+}
+
+template <>
+octave_value
+ov_range<double>::diag (octave_idx_type nr, octave_idx_type nc) const
+{
+  Matrix mat = matrix_value ();
+
+  return mat.diag (nr, nc);
+}
+
+template <>
+void
+ov_range<double>::print_raw (std::ostream& os, bool pr_as_read_syntax) const
+{
+  octave_print_internal (os, m_range, pr_as_read_syntax,
+                         current_print_indent_level ());
+}
--- a/libinterp/octave-value/ov-range.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-range.h	Sun May 16 09:44:35 2021 +0200
@@ -43,6 +43,7 @@
 #include "error.h"
 #include "oct-stream.h"
 #include "ov-base.h"
+#include "ov-range-traits.h"
 #include "ov-re-mat.h"
 #include "ov-typeinfo.h"
 
@@ -50,51 +51,58 @@
 
 // Range values.
 
+template <typename T>
 class
-octave_range : public octave_base_value
+ov_range : public octave_base_value
 {
 public:
 
-  octave_range (void)
-    : octave_base_value (), range (), idx_cache () { }
+  ov_range (void)
+    : octave_base_value (), m_range (), m_idx_cache () { }
 
-  octave_range (double base, double limit, double inc)
-    : octave_base_value (), range (base, limit, inc), idx_cache ()
+  ov_range (const octave::range<T>& r)
+    : octave_base_value (), m_range (r), m_idx_cache ()
   {
-    if (range.numel () < 0)
+    if (numel () < 0 && numel () != -2)
       error ("invalid range");
   }
 
-  octave_range (const Range& r)
-    : octave_base_value (), range (r), idx_cache ()
-  {
-    if (range.numel () < 0 && range.numel () != -2)
-      error ("invalid range");
-  }
-
-  octave_range (const octave_range& r)
-    : octave_base_value (), range (r.range),
-      idx_cache (r.idx_cache ? new idx_vector (*r.idx_cache) : nullptr)
+  ov_range (const ov_range<T>& r)
+    : octave_base_value (), m_range (r.m_range),
+      m_idx_cache (r.m_idx_cache
+                   ? new octave::idx_vector (*r.m_idx_cache) : nullptr)
   { }
 
-  octave_range (const Range& r, const idx_vector& cache)
-    : octave_base_value (), range (r), idx_cache ()
+  ov_range (const octave::range<T>& r, const octave::idx_vector& cache)
+    : octave_base_value (), m_range (r), m_idx_cache ()
   {
     set_idx_cache (cache);
   }
 
-  ~octave_range (void) { clear_cached_info (); }
+  // No assignment.
+  ov_range& operator = (const ov_range&) = delete;
+
+  ~ov_range (void) { clear_cached_info (); }
 
-  octave_base_value * clone (void) const { return new octave_range (*this); }
+  octave_base_value * clone (void) const
+  {
+    return new ov_range (*this);
+  }
 
   // A range is really just a special kind of real matrix object.  In
   // the places where we need to call empty_clone, it makes more sense
   // to create an empty matrix (0x0) instead of an empty range (1x0).
-  octave_base_value * empty_clone (void) const { return new octave_matrix (); }
+
+  octave_base_value * empty_clone (void) const
+  {
+    return new typename octave_value_range_traits<T>::matrix_type ();
+  }
 
-  type_conv_info numeric_conversion_function (void) const;
+  OCTINTERP_API type_conv_info numeric_conversion_function (void) const;
 
-  octave_base_value * try_narrowing_conversion (void);
+  OCTINTERP_API octave_base_value * try_narrowing_conversion (void);
+
+  builtin_type_t builtin_type (void) const { return class_to_btyp<T>::btyp; }
 
   // We don't need to override all three forms of subsref.  The using
   // declaration will avoid warnings about partially-overloaded virtual
@@ -108,193 +116,339 @@
                              const std::list<octave_value_list>& idx, int)
   { return subsref (type, idx); }
 
-  octave_value do_index_op (const octave_value_list& idx,
-                            bool resize_ok = false);
+  OCTINTERP_API octave_value
+  do_index_op (const octave_value_list& idx, bool resize_ok = false);
 
-  idx_vector index_vector (bool require_integers = false) const;
+  OCTINTERP_API octave::idx_vector index_vector (bool require_integers = false) const;
 
   dim_vector dims (void) const
   {
-    octave_idx_type n = range.numel ();
+    octave_idx_type n = numel ();
     return dim_vector (n > 0, n);
   }
 
-  octave_idx_type nnz (void) const { return range.nnz (); }
+  octave_idx_type numel (void) const { return m_range.numel (); }
+
+  octave_idx_type nnz (void) const
+  {
+    // FIXME: this is a potential waste of memory.
 
-  octave_value resize (const dim_vector& dv, bool fill = false) const;
+    octave_value tmp (raw_array_value ());
+    return tmp.nnz ();
+  }
 
-  std::size_t byte_size (void) const { return 3 * sizeof (double); }
+  OCTINTERP_API octave_value
+  resize (const dim_vector& dv, bool fill = false) const;
+
+  std::size_t byte_size (void) const { return 3 * sizeof (T); }
 
   octave_value reshape (const dim_vector& new_dims) const
-  { return NDArray (array_value ().reshape (new_dims)); }
+  {
+    return raw_array_value ().reshape (new_dims);
+  }
 
   octave_value permute (const Array<int>& vec, bool inv = false) const
-  { return NDArray (array_value ().permute (vec, inv)); }
+  {
+    return raw_array_value ().permute (vec, inv);
+  }
 
-  octave_value squeeze (void) const { return range; }
+  octave_value squeeze (void) const { return m_range; }
 
-  octave_value full_value (void) const { return range.matrix_value (); }
+  octave_value full_value (void) const { return raw_array_value (); }
 
   bool is_defined (void) const { return true; }
 
+  bool is_storable (void) const { return m_range.is_storable (); }
+
   bool is_constant (void) const { return true; }
 
   bool is_range (void) const { return true; }
 
-  octave_value all (int dim = 0) const;
+  bool is_double_type (void) const { return builtin_type () == btyp_double; }
+
+  bool is_single_type (void) const { return builtin_type () == btyp_float; }
+
+  bool isfloat (void) const { return btyp_isfloat (builtin_type ()); }
+
+  bool is_int8_type (void) const { return builtin_type () == btyp_int8; }
+
+  bool is_int16_type (void) const { return builtin_type () == btyp_int16; }
+
+  bool is_int32_type (void) const { return builtin_type () == btyp_int32; }
+
+  bool is_int64_type (void) const { return builtin_type () == btyp_int64; }
+
+  bool is_uint8_type (void) const { return builtin_type () == btyp_uint8; }
+
+  bool is_uint16_type (void) const { return builtin_type () == btyp_uint16; }
 
-  octave_value any (int dim = 0) const;
+  bool is_uint32_type (void) const { return builtin_type () == btyp_uint32; }
+
+  bool is_uint64_type (void) const { return builtin_type () == btyp_uint64; }
+
+  bool isinteger (void) const
+  {
+    return btyp_isinteger (builtin_type ());
+  }
+
+  bool isreal (void) const { return isfloat (); }
+
+  bool isnumeric (void) const
+  {
+    return btyp_isnumeric (builtin_type ());
+  }
+
+  bool is_true (void) const { return nnz () == numel (); }
 
-  octave_value diag (octave_idx_type k = 0) const;
+  octave_value all (int dim = 0) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+    typename ov_mx_type::object_type m (raw_array_value ());
+
+    return m.all (dim);
+  }
+
+  octave_value any (int dim = 0) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+    typename ov_mx_type::object_type m (raw_array_value ());
 
-  octave_value diag (octave_idx_type m, octave_idx_type n) const;
+    return m.any (dim);
+  }
+
+  octave_value diag (octave_idx_type k = 0) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    return m_range.diag (k);
+  }
+
+  octave_value diag (octave_idx_type nr, octave_idx_type nc) const
+  {
+    // FIXME: this is a potential waste of memory.
+
+    typedef typename octave_value_range_traits<T>::matrix_type ov_mx_type;
+    typename ov_mx_type::object_type m (raw_array_value ());
+
+    return m.diag (nr, nc);
+  }
 
   octave_value sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const
-  { return range.sort (dim, mode); }
+  {
+    Array<T> tmp = raw_array_value ();
+    return tmp.sort (dim, mode);
+  }
 
   octave_value sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
                      sortmode mode = ASCENDING) const
-  { return range.sort (sidx, dim, mode); }
+  {
+    Array<T> tmp = raw_array_value ();
+    return tmp.sort (sidx, dim, mode);
+  }
 
   sortmode issorted (sortmode mode = UNSORTED) const
-  { return range.issorted (mode); }
+  {
+    return m_range.issorted (mode);
+  }
 
   Array<octave_idx_type> sort_rows_idx (sortmode) const
-  { return Array<octave_idx_type> (dim_vector (1, 0)); }
+  {
+    return Array<octave_idx_type> (dim_vector (1, 0));
+  }
 
   sortmode is_sorted_rows (sortmode mode = UNSORTED) const
-  { return (mode == UNSORTED) ? ASCENDING : mode; }
-
-  builtin_type_t builtin_type (void) const { return btyp_double; }
-
-  bool isreal (void) const { return true; }
-
-  bool is_double_type (void) const { return true; }
+  {
+    return (mode == UNSORTED) ? ASCENDING : mode;
+  }
 
-  bool isfloat (void) const { return true; }
-
-  bool isnumeric (void) const { return true; }
+  Array<T> raw_array_value (void) const { return m_range.array_value (); }
 
-  bool is_true (void) const;
+  OCTINTERP_API double double_value (bool = false) const;
 
-  double double_value (bool = false) const;
-
-  float float_value (bool = false) const;
+  OCTINTERP_API float float_value (bool = false) const;
 
   double scalar_value (bool frc_str_conv = false) const
-  { return double_value (frc_str_conv); }
+  {
+    return double_value (frc_str_conv);
+  }
 
   float float_scalar_value (bool frc_str_conv = false) const
-  { return float_value (frc_str_conv); }
+  {
+    return float_value (frc_str_conv);
+  }
 
   Matrix matrix_value (bool = false) const
-  { return range.matrix_value (); }
+  {
+    return raw_array_value ();
+  }
 
   FloatMatrix float_matrix_value (bool = false) const
-  { return range.matrix_value (); }
+  {
+    return raw_array_value ();
+  }
 
   NDArray array_value (bool = false) const
-  { return range.matrix_value (); }
+  {
+    return raw_array_value ();
+  }
 
   FloatNDArray float_array_value (bool = false) const
-  { return FloatMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
-  charNDArray char_array_value (bool = false) const;
+  OCTINTERP_API charNDArray char_array_value (bool = false) const;
 
   // FIXME: it would be better to have Range::intXNDArray_value
   // functions to avoid the intermediate conversion to a matrix
   // object.
 
-  int8NDArray
-  int8_array_value (void) const { return int8NDArray (array_value ()); }
+  int8NDArray int8_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  int16NDArray
-  int16_array_value (void) const { return int16NDArray (array_value ()); }
+  int16NDArray int16_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  int32NDArray
-  int32_array_value (void) const { return int32NDArray (array_value ()); }
+  int32NDArray int32_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  int64NDArray
-  int64_array_value (void) const { return int64NDArray (array_value ()); }
+  int64NDArray int64_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  uint8NDArray
-  uint8_array_value (void) const { return uint8NDArray (array_value ()); }
+  uint8NDArray uint8_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  uint16NDArray
-  uint16_array_value (void) const { return uint16NDArray (array_value ()); }
+  uint16NDArray uint16_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  uint32NDArray
-  uint32_array_value (void) const { return uint32NDArray (array_value ()); }
+  uint32NDArray uint32_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
-  uint64NDArray
-  uint64_array_value (void) const { return uint64NDArray (array_value ()); }
+  uint64NDArray uint64_array_value (void) const
+  {
+    return raw_array_value ();
+  }
 
   SparseMatrix sparse_matrix_value (bool = false) const
-  { return SparseMatrix (range.matrix_value ()); }
+  {
+    return SparseMatrix (matrix_value ());
+  }
 
   SparseComplexMatrix sparse_complex_matrix_value (bool = false) const
-  { return SparseComplexMatrix (sparse_matrix_value ()); }
-
-  Complex complex_value (bool = false) const;
+  {
+    return SparseComplexMatrix (complex_matrix_value ());
+  }
 
-  FloatComplex float_complex_value (bool = false) const;
+  OCTINTERP_API Complex complex_value (bool = false) const;
 
-  boolNDArray bool_array_value (bool warn = false) const;
+  OCTINTERP_API FloatComplex float_complex_value (bool = false) const;
+
+  OCTINTERP_API boolNDArray bool_array_value (bool warn = false) const;
 
   ComplexMatrix complex_matrix_value (bool = false) const
-  { return ComplexMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
   FloatComplexMatrix float_complex_matrix_value (bool = false) const
-  { return FloatComplexMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
   ComplexNDArray complex_array_value (bool = false) const
-  { return ComplexMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
   FloatComplexNDArray float_complex_array_value (bool = false) const
-  { return FloatComplexMatrix (range.matrix_value ()); }
+  {
+    return raw_array_value ();
+  }
 
-  Range range_value (void) const { return range; }
+  OCTINTERP_API octave::range<float> float_range_value (void) const;
+
+  OCTINTERP_API octave::range<double> range_value (void) const;
 
-  octave_value convert_to_str_internal (bool pad, bool force, char type) const;
+  OCTINTERP_API octave::range<octave_int8> int8_range_value (void) const;
+
+  OCTINTERP_API octave::range<octave_int16> int16_range_value (void) const;
 
-  octave_value as_double (void) const;
-  octave_value as_single (void) const;
+  OCTINTERP_API octave::range<octave_int32> int32_range_value (void) const;
+
+  OCTINTERP_API octave::range<octave_int64> int64_range_value (void) const;
 
-  octave_value as_int8 (void) const;
-  octave_value as_int16 (void) const;
-  octave_value as_int32 (void) const;
-  octave_value as_int64 (void) const;
+  OCTINTERP_API octave::range<octave_uint8> uint8_range_value (void) const;
+
+  OCTINTERP_API octave::range<octave_uint16> uint16_range_value (void) const;
+
+  OCTINTERP_API octave::range<octave_uint32> uint32_range_value (void) const;
+
+  OCTINTERP_API octave::range<octave_uint64> uint64_range_value (void) const;
 
-  octave_value as_uint8 (void) const;
-  octave_value as_uint16 (void) const;
-  octave_value as_uint32 (void) const;
-  octave_value as_uint64 (void) const;
+  OCTINTERP_API octave_value
+  convert_to_str_internal (bool pad, bool force, char type) const;
 
-  void print (std::ostream& os, bool pr_as_read_syntax = false);
+  OCTINTERP_API octave_value as_double (void) const;
+  OCTINTERP_API octave_value as_single (void) const;
+
+  OCTINTERP_API octave_value as_int8 (void) const;
+  OCTINTERP_API octave_value as_int16 (void) const;
+  OCTINTERP_API octave_value as_int32 (void) const;
+  OCTINTERP_API octave_value as_int64 (void) const;
 
-  void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
+  OCTINTERP_API octave_value as_uint8 (void) const;
+  OCTINTERP_API octave_value as_uint16 (void) const;
+  OCTINTERP_API octave_value as_uint32 (void) const;
+  OCTINTERP_API octave_value as_uint64 (void) const;
 
-  bool print_name_tag (std::ostream& os, const std::string& name) const;
+  OCTINTERP_API void print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  void short_disp (std::ostream& os) const;
+  OCTINTERP_API void
+  print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  float_display_format get_edit_display_format (void) const;
+  OCTINTERP_API bool
+  print_name_tag (std::ostream& os, const std::string& name) const;
 
-  std::string edit_display (const float_display_format& fmt,
-                            octave_idx_type i, octave_idx_type j) const;
+  OCTINTERP_API void short_disp (std::ostream& os) const;
+
+  OCTINTERP_API float_display_format get_edit_display_format (void) const;
 
-  bool save_ascii (std::ostream& os);
+  OCTINTERP_API std::string
+  edit_display (const float_display_format& fmt,
+                octave_idx_type i, octave_idx_type j) const;
 
-  bool load_ascii (std::istream& is);
+  OCTINTERP_API bool save_ascii (std::ostream& os);
 
-  bool save_binary (std::ostream& os, bool save_as_floats);
+  OCTINTERP_API bool load_ascii (std::istream& is);
 
-  bool load_binary (std::istream& is, bool swap,
-                    octave::mach_info::float_format fmt);
+  OCTINTERP_API bool save_binary (std::ostream& os, bool save_as_floats);
 
-  bool save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
+  OCTINTERP_API bool
+  load_binary (std::istream& is, bool swap,
+               octave::mach_info::float_format fmt);
 
-  bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
+  OCTINTERP_API bool
+  save_hdf5 (octave_hdf5_id loc_id, const char *name, bool flag);
+
+  OCTINTERP_API bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
   int write (octave::stream& os, int block_size,
              oct_data_conv::data_type output_type, int skip,
@@ -306,39 +460,134 @@
     return os.write (matrix_value (), block_size, output_type, skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  OCTINTERP_API mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const
   {
-    octave_matrix m (matrix_value ());
-    return m.map (umap);
+    octave_value tmp (raw_array_value ());
+    return tmp.map (umap);
   }
 
-  octave_value fast_elem_extract (octave_idx_type n) const;
+  OCTINTERP_API octave_value fast_elem_extract (octave_idx_type n) const;
 
-private:
+protected:
 
-  Range range;
+  octave::range<T> m_range;
 
-  idx_vector set_idx_cache (const idx_vector& idx) const
+  octave::idx_vector set_idx_cache (const octave::idx_vector& idx) const
   {
-    delete idx_cache;
-    idx_cache = (idx ? new idx_vector (idx) : nullptr);
+    delete m_idx_cache;
+    m_idx_cache = (idx ? new octave::idx_vector (idx) : nullptr);
     return idx;
   }
 
   void clear_cached_info (void) const
   {
-    delete idx_cache; idx_cache = nullptr;
+    delete m_idx_cache; m_idx_cache = nullptr;
   }
 
-  mutable idx_vector *idx_cache;
+  mutable octave::idx_vector *m_idx_cache;
 
-  // No assignment.
-
-  octave_range& operator = (const octave_range&);
+  static octave_hdf5_id hdf5_save_type;
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, float)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, double)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int8)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int16)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int32)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_int64)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint8)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint16)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint32)
+DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS (ov_range, octave_uint64)
+
+// Specializations.
+
+template <>
+OCTINTERP_API octave::range<float>
+ov_range<float>::float_range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<double>
+ov_range<double>::range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<octave_int8>
+ov_range<octave_int8>::int8_range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<octave_int16>
+ov_range<octave_int16>::int16_range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<octave_int32>
+ov_range<octave_int32>::int32_range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<octave_int64>
+ov_range<octave_int64>::int64_range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<octave_uint8>
+ov_range<octave_uint8>::uint8_range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<octave_uint16>
+ov_range<octave_uint16>::uint16_range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<octave_uint32>
+ov_range<octave_uint32>::uint32_range_value (void) const;
+
+template <>
+OCTINTERP_API octave::range<octave_uint64>
+ov_range<octave_uint64>::uint64_range_value (void) const;
+
+// The following specializations are here to preserve previous Range
+// performance until solutions can be generalized for other types.
+
+template <>
+OCTINTERP_API octave::idx_vector
+ov_range<double>::index_vector (bool require_integers) const;
+
+template <>
+OCTINTERP_API octave_idx_type
+ov_range<double>::nnz (void) const;
+
+// The following specialization is also historical baggage.  For double
+// ranges, we can produce special double-valued diagnoal matrix objects
+// but Octave currently provides only double and Complex diagonal matrix
+// objects.
+
+template <>
+OCTINTERP_API octave_value
+ov_range<double>::diag (octave_idx_type k) const;
+
+template <>
+OCTINTERP_API octave_value
+ov_range<double>::diag (octave_idx_type nr, octave_idx_type nc) const;
+
+template <>
+OCTINTERP_API void
+ov_range<double>::print_raw (std::ostream& os, bool pr_as_read_syntax) const;
+
+
+typedef ov_range<float> octave_float_range;
+typedef ov_range<double> octave_double_range;
+
+typedef ov_range<octave_int8> octave_int8_range;
+typedef ov_range<octave_int16> octave_int16_range;
+typedef ov_range<octave_int32> octave_int32_range;
+typedef ov_range<octave_int64> octave_int64_range;
+
+typedef ov_range<octave_uint8> octave_uint8_range;
+typedef ov_range<octave_uint16> octave_uint16_range;
+typedef ov_range<octave_uint32> octave_uint32_range;
+typedef ov_range<octave_uint64> octave_uint64_range;
+
+typedef octave_double_range octave_range;
+
 #endif
--- a/libinterp/octave-value/ov-re-diag.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-re-diag.cc	Sun May 16 09:44:35 2021 +0200
@@ -98,9 +98,9 @@
       int k = 0;        // index we're accessing when index_vector throws
       try
         {
-          idx_vector idx0 = idx(0).index_vector ();
+          octave::idx_vector idx0 = idx(0).index_vector ();
           k = 1;
-          idx_vector idx1 = idx(1).index_vector ();
+          octave::idx_vector idx1 = idx(1).index_vector ();
 
           bool left = idx0.is_permutation (matrix.rows ());
           bool right = idx1.is_permutation (matrix.cols ());
@@ -122,10 +122,10 @@
                 }
             }
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
           // Rethrow to allow more info to be reported later.
-          e.set_pos_if_unset (2, k+1);
+          ie.set_pos_if_unset (2, k+1);
           throw;
         }
     }
--- a/libinterp/octave-value/ov-re-mat.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-re-mat.cc	Sun May 16 09:44:35 2021 +0200
@@ -341,8 +341,8 @@
   if (idx_cache)
     {
       return new octave_matrix (matrix.reshape (new_dims),
-                                idx_vector (idx_cache->as_array ().reshape (new_dims),
-                                            idx_cache->extent (0)));
+                                octave::idx_vector (idx_cache->as_array ().reshape (new_dims),
+                                                    idx_cache->extent (0)));
     }
   else
     return octave_base_matrix<NDArray>::reshape (new_dims);
@@ -354,8 +354,8 @@
   if (idx_cache)
     {
       return new octave_matrix (matrix.squeeze (),
-                                idx_vector (idx_cache->as_array ().squeeze (),
-                                            idx_cache->extent (0)));
+                                octave::idx_vector (idx_cache->as_array ().squeeze (),
+                                                    idx_cache->extent (0)));
     }
   else
     return octave_base_matrix<NDArray>::squeeze ();
@@ -670,7 +670,7 @@
         return false;
       Matrix m (nr, nc);
       double *re = m.fortran_vec ();
-      octave_idx_type len = nr * nc;
+      octave_idx_type len = static_cast<octave_idx_type> (nr) * nc;
       read_doubles (is, re, static_cast<save_type> (tmp), len, swap, fmt);
 
       if (! is)
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-re-mat.h	Sun May 16 09:44:35 2021 +0200
@@ -87,10 +87,10 @@
   {
     // Auto-create cache to speed up subsequent indexing.
     if (zero_based && cache_index)
-      set_idx_cache (idx_vector (idx));
+      set_idx_cache (octave::idx_vector (idx));
   }
 
-  octave_matrix (const NDArray& nda, const idx_vector& cache)
+  octave_matrix (const NDArray& nda, const octave::idx_vector& cache)
     : octave_base_matrix<NDArray> (nda)
   {
     set_idx_cache (cache);
@@ -105,8 +105,8 @@
 
   octave_base_value * try_narrowing_conversion (void);
 
-  idx_vector index_vector (bool /* require_integers */ = false) const
-  { return idx_cache ? *idx_cache : set_idx_cache (idx_vector (matrix)); }
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
+  { return idx_cache ? *idx_cache : set_idx_cache (octave::idx_vector (matrix)); }
 
   builtin_type_t builtin_type (void) const { return btyp_double; }
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-re-sparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -52,16 +52,16 @@
 #include "ov-bool-sparse.h"
 
 
-template class OCTINTERP_API octave_base_sparse<SparseMatrix>;
+template class octave_base_sparse<SparseMatrix>;
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_sparse_matrix, "sparse matrix",
                                      "double");
 
-idx_vector
+octave::idx_vector
 octave_sparse_matrix::index_vector (bool /* require_integers */) const
 {
   if (matrix.numel () == matrix.nnz ())
-    return idx_vector (array_value ());
+    return octave::idx_vector (array_value ());
   else
     {
       std::string nm = '<' + type_name () + '>';
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-re-sparse.h	Sun May 16 09:44:35 2021 +0200
@@ -93,7 +93,7 @@
 
   octave_base_value * try_narrowing_conversion (void);
 
-  idx_vector index_vector (bool require_integers = false) const;
+  octave::idx_vector index_vector (bool require_integers = false) const;
 
   builtin_type_t builtin_type (void) const { return btyp_double; }
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-scalar.cc	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<float>;
+extern template class octave_base_scalar<float>;
 
 template class octave_base_scalar<double>;
 
@@ -98,7 +98,7 @@
 
   octave_value tmp (new octave_matrix (matrix_value ()));
 
-  return tmp.do_index_op (idx, resize_ok);
+  return tmp.index_op (idx, resize_ok);
 }
 
 octave_value
@@ -219,7 +219,7 @@
 {
   double d = double_value ();
 
-  octave_write_double (os, d);
+  octave::write_value<double> (os, d);
 
   os << "\n";
 
@@ -229,7 +229,7 @@
 bool
 octave_scalar::load_ascii (std::istream& is)
 {
-  scalar = octave_read_value<double> (is);
+  scalar = octave::read_value<double> (is);
 
   if (! is)
     error ("load: failed to load scalar constant");
@@ -274,7 +274,7 @@
 
 #if defined (HAVE_HDF5)
 
-  hsize_t dimens[3];
+  hsize_t dimens[3] = {0};
   hid_t space_hid, data_hid;
   space_hid = data_hid = -1;
 
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-scalar.h	Sun May 16 09:44:35 2021 +0200
@@ -78,7 +78,8 @@
 
   type_conv_info numeric_demotion_function (void) const;
 
-  idx_vector index_vector (bool /* require_integers */ = false) const { return idx_vector (scalar); }
+  octave::idx_vector index_vector (bool /* require_integers */ = false) const
+  { return octave::idx_vector (scalar); }
 
   octave_value any (int = 0) const
   { return (scalar != 0 && ! lo_ieee_isnan (scalar)); }
@@ -269,7 +270,7 @@
                      skip, flt_fmt);
   }
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   octave_value map (unary_mapper_t umap) const;
 
--- a/libinterp/octave-value/ov-str-mat.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-str-mat.cc	Sun May 16 09:44:35 2021 +0200
@@ -110,7 +110,7 @@
 
         case 1:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
 
             retval = octave_value (charNDArray (matrix.index (i, resize_ok)),
                                    type);
@@ -119,9 +119,9 @@
 
         case 2:
           {
-            idx_vector i = idx (0).index_vector ();
+            octave::idx_vector i = idx (0).index_vector ();
             k = 1;
-            idx_vector j = idx (1).index_vector ();
+            octave::idx_vector j = idx (1).index_vector ();
 
             retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)),
                                    type);
@@ -130,7 +130,7 @@
 
         default:
           {
-            Array<idx_vector> idx_vec (dim_vector (len, 1));
+            Array<octave::idx_vector> idx_vec (dim_vector (len, 1));
 
             for (k = 0; k < len; k++)
               idx_vec(k) = idx(k).index_vector ();
@@ -140,10 +140,10 @@
           break;
         }
     }
-  catch (octave::index_exception& e)
+  catch (octave::index_exception& ie)
     {
       // Rethrow to allow more info to be reported later.
-      e.set_pos_if_unset (len, k+1);
+      ie.set_pos_if_unset (len, k+1);
       throw;
     }
 
@@ -234,10 +234,23 @@
 
   charMatrix chm (matrix);
 
+  if (chm.rows () > 1)
+    warning_with_id ("Octave:charmat-truncated",
+                     "multi-row character matrix converted to a string, only the first row is used");
+
   // FIXME: Is this correct?
   return chm.row_as_string (0);
 }
 
+/*
+%!test <*49536>
+%! warning ("on", "Octave:charmat-truncated", "local");
+%! s = char ("this", "is", "a", "char", "matrix");
+%! fail ("sprintf (s)", ...
+%!       "warning",     ...
+%!       "multi-row character matrix converted to a string");
+*/
+
 Array<std::string>
 octave_char_matrix_str::cellstr_value (void) const
 {
@@ -268,7 +281,8 @@
 {
   if (matrix.ndims () == 2 && numel () > 0)
     {
-      std::string tmp = string_value ();
+      charMatrix chm (matrix);
+      std::string tmp = chm.row_as_string (0);
 
       // FIXME: should this be configurable?
       std::size_t max_len = 100;
--- a/libinterp/octave-value/ov-struct.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-struct.cc	Sun May 16 09:44:35 2021 +0200
@@ -598,9 +598,7 @@
 void
 octave_struct::print_raw (std::ostream& os, bool) const
 {
-  octave::unwind_protect frame;
-
-  frame.protect_var (Vstruct_levels_to_print);
+  octave::unwind_protect_var<int> restore_var (Vstruct_levels_to_print);
 
   if (Vstruct_levels_to_print >= 0)
     {
@@ -1034,7 +1032,7 @@
 }
 
 mxArray *
-octave_struct::as_mxArray (void) const
+octave_struct::as_mxArray (bool interleaved) const
 {
   int nf = nfields ();
   string_vector kv = map_keys ();
@@ -1044,7 +1042,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 ());
 
@@ -1060,7 +1058,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;
@@ -1318,9 +1316,7 @@
 void
 octave_scalar_struct::print_raw (std::ostream& os, bool) const
 {
-  octave::unwind_protect frame;
-
-  frame.protect_var (Vstruct_levels_to_print);
+  octave::unwind_protect_var<int> restore_var (Vstruct_levels_to_print);
 
   if (Vstruct_levels_to_print >= 0)
     {
@@ -1659,7 +1655,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 ();
@@ -1669,7 +1665,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 ());
 
@@ -1685,7 +1681,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;
@@ -2010,6 +2006,46 @@
 %!assert (isfield (struct ("a", 1, "b", 2), {"a", "c"}), [true, false])
 */
 
+OCTAVE_NORETURN
+static void
+invalid_cell2struct_fields_error (void)
+{
+  error ("cell2struct: FIELDS must be a cell array of strings or a scalar string");
+}
+
+static Array<std::string>
+get_cell2struct_fields (const octave_value& arg)
+{
+  if (arg.is_string ())
+    {
+      if (arg.rows () != 1)
+        invalid_cell2struct_fields_error ();
+
+      return Array<std::string> (dim_vector (1, 1), arg.string_value ());
+    }
+
+  if (arg.iscell ())
+    {
+      const Cell c = arg.cell_value ();
+
+      Array<std::string> retval (c.dims ());
+
+      for (octave_idx_type i = 0; i < c.numel (); i++)
+        {
+          const octave_value val = c(i);
+
+          if (! val.is_string () || val.rows () != 1)
+            invalid_cell2struct_fields_error ();
+
+          retval(i) = c(i).string_value ();
+        }
+
+      return retval;
+    }
+
+  invalid_cell2struct_fields_error ();
+}
+
 DEFUN (cell2struct, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} cell2struct (@var{cell}, @var{fields})
@@ -2043,11 +2079,10 @@
   if (nargin < 2 || nargin > 3)
     print_usage ();
 
-  if (! args(0).iscell ())
-    error ("cell2struct: argument CELL must be of type cell");
-
-  if (! (args(1).iscellstr () || args(1).is_char_matrix ()))
-    error ("cell2struct: FIELDS must be a cell array of strings or a character matrix");
+  const Cell vals
+    = args(0).xcell_value ("cell2struct: argument CELL must be of type cell");
+
+  const Array<std::string> fields = get_cell2struct_fields (args(1));
 
   int dim = 0;
 
@@ -2062,9 +2097,6 @@
   if (dim < 0)
     error ("cell2struct: DIM must be a valid dimension");
 
-  const Cell vals = args(0).cell_value ();
-  const Array<std::string> fields = args(1).cellstr_value ();
-
   octave_idx_type ext = (vals.ndims () > dim ? vals.dims ()(dim) : 1);
 
   if (ext != fields.numel ())
@@ -2089,7 +2121,7 @@
     }
 
   octave_map map (rdv);
-  Array<idx_vector> ia (dim_vector (nd, 1), idx_vector::colon);
+  Array<octave::idx_vector> ia (dim_vector (nd, 1), octave::idx_vector::colon);
 
   for (octave_idx_type i = 0; i < ext; i++)
     {
@@ -2114,6 +2146,12 @@
 %!assert (cell2struct ({1; 2}, {"a"; "b"}), struct ("a", 1, "b", 2))
 
 %!assert (cell2struct ({}, {"f"}, 3), struct ("f", {}))
+
+%!assert (cell2struct ({1; 2; 3; 4}, {'a', 'b'; 'c', 'd'}),
+%!        struct ('a', 1, 'c', 2, 'b', 3, 'd', 4));
+%!assert (cell2struct ({1, 2, 3, 4}, {'a', 'b'; 'c', 'd'}, 2),
+%!        struct ('a', 1, 'c', 2, 'b', 3, 'd', 4));
+%!error cell2struct ({1, 2, 3, 4}, {'a', 'b'; 'c', 'd'})
 */
 
 DEFUN (rmfield, args, ,
--- a/libinterp/octave-value/ov-struct.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-struct.h	Sun May 16 09:44:35 2021 +0200
@@ -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
   fast_elem_extract (octave_idx_type n) const;
@@ -278,7 +278,7 @@
 
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  mxArray * as_mxArray (void) const;
+  mxArray * as_mxArray (bool interleaved) const;
 
   bool fast_elem_insert_self (void *where, builtin_type_t btyp) const;
 
--- a/libinterp/octave-value/ov-typeinfo.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-typeinfo.cc	Sun May 16 09:44:35 2021 +0200
@@ -942,7 +942,12 @@
 %!assert (typeinfo ([i, 2]), "complex matrix")
 %!assert (typeinfo (diag ([i, 2])), "complex diagonal matrix")
 
-%!assert (typeinfo (1:2), "range")
+%!test
+%! if (disable_range ())
+%!   assert (typeinfo (1:2), "matrix")
+%! else
+%!   assert (typeinfo (1:2), "range")
+%! endif
 
 %!assert (typeinfo (false), "bool")
 %!assert (typeinfo ([true, false]), "bool matrix")
--- a/libinterp/octave-value/ov-typeinfo.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-typeinfo.h	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,9 @@
 
 namespace octave
 {
-  class type_info
+  class
+  OCTINTERP_API
+  type_info
   {
   public:
 
@@ -56,7 +58,7 @@
       (const octave_base_value&, const octave_base_value&);
 
     typedef octave_value (*cat_op_fcn)
-      (octave_base_value&, const octave_base_value&,
+      (const octave_base_value&, const octave_base_value&,
      const Array<octave_idx_type>& ra_idx);
 
     typedef octave_value (*assign_op_fcn)
@@ -285,47 +287,49 @@
 
   typedef octave::type_info::assignany_op_fcn assignany_op_fcn;
 
-  extern int register_type (const std::string& t_name,
+  extern OCTINTERP_API int register_type (const std::string& t_name,
                             const std::string& c_name,
                             const octave_value& val);
 
-  extern octave_value lookup_type (const std::string& nm);
+  extern OCTINTERP_API octave_value lookup_type (const std::string& nm);
 
-  extern unary_class_op_fcn lookup_unary_class_op (octave_value::unary_op op);
+  extern OCTINTERP_API unary_class_op_fcn
+  lookup_unary_class_op (octave_value::unary_op op);
 
-  extern unary_op_fcn lookup_unary_op (octave_value::unary_op op, int t);
+  extern OCTINTERP_API unary_op_fcn
+  lookup_unary_op (octave_value::unary_op op, int t);
 
-  extern non_const_unary_op_fcn
+  extern OCTINTERP_API non_const_unary_op_fcn
   lookup_non_const_unary_op (octave_value::unary_op op, int t);
 
-  extern binary_class_op_fcn
+  extern OCTINTERP_API binary_class_op_fcn
   lookup_binary_class_op (octave_value::binary_op op);
 
-  extern binary_op_fcn
+  extern OCTINTERP_API binary_op_fcn
   lookup_binary_op (octave_value::binary_op op, int t1, int t2);
 
-  extern binary_class_op_fcn
+  extern OCTINTERP_API binary_class_op_fcn
   lookup_binary_class_op (octave_value::compound_binary_op op);
 
-  extern binary_op_fcn
+  extern OCTINTERP_API binary_op_fcn
   lookup_binary_op (octave_value::compound_binary_op op, int t1, int t2);
 
-  extern cat_op_fcn lookup_cat_op (int t1, int t2);
+  extern OCTINTERP_API cat_op_fcn lookup_cat_op (int t1, int t2);
 
-  extern assign_op_fcn
+  extern OCTINTERP_API assign_op_fcn
   lookup_assign_op (octave_value::assign_op op, int t_lhs, int t_rhs);
 
-  extern assignany_op_fcn
+  extern OCTINTERP_API assignany_op_fcn
   lookup_assignany_op (octave_value::assign_op op, int t_lhs);
 
-  extern int lookup_pref_assign_conv (int t_lhs, int t_rhs);
+  extern OCTINTERP_API int lookup_pref_assign_conv (int t_lhs, int t_rhs);
 
-  extern octave_base_value::type_conv_fcn
+  extern OCTINTERP_API octave_base_value::type_conv_fcn
   lookup_widening_op (int t, int t_result);
 
-  extern string_vector installed_type_names (void);
+  extern OCTINTERP_API string_vector installed_type_names (void);
 
-  extern octave_scalar_map installed_type_info (void);
+  extern OCTINTERP_API octave_scalar_map installed_type_info (void);
 }
 
 #endif
--- a/libinterp/octave-value/ov-uint16.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-uint16.cc	Sun May 16 09:44:35 2021 +0200
@@ -63,7 +63,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_matrix<uint16NDArray>;
 
--- a/libinterp/octave-value/ov-uint32.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-uint32.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_matrix<uint32NDArray>;
 
--- a/libinterp/octave-value/ov-uint64.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-uint64.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_matrix<uint64NDArray>;
 
--- a/libinterp/octave-value/ov-uint8.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-uint8.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTINTERP_API octave_base_scalar<double>;
+extern template class octave_base_scalar<double>;
 
 template class octave_base_matrix<uint8NDArray>;
 
--- a/libinterp/octave-value/ov-usr-fcn.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Sun May 16 09:44:35 2021 +0200
@@ -216,16 +216,16 @@
   (const octave::symbol_scope& scope, octave::tree_parameter_list *pl,
    octave::tree_parameter_list *rl, octave::tree_statement_list *cl)
   : octave_user_code ("", "", scope, cl, ""),
-    param_list (pl), ret_list (rl),
-    lead_comm (), trail_comm (),
-    location_line (0), location_column (0),
-    parent_name (), system_fcn_file (false),
-    num_named_args (param_list ? param_list->length () : 0),
-    subfunction (false), inline_function (false),
-    anonymous_function (false), nested_function (false),
-    class_constructor (none), class_method (none)
+    m_param_list (pl), m_ret_list (rl),
+    m_lead_comm (), m_trail_comm (),
+    m_location_line (0), m_location_column (0),
+    m_parent_name (), m_system_fcn_file (false),
+    m_num_named_args (m_param_list ? m_param_list->length () : 0),
+    m_subfunction (false), m_inline_function (false),
+    m_anonymous_function (false), m_nested_function (false),
+    m_class_constructor (none), m_class_method (none)
 #if defined (HAVE_LLVM)
-    , jit_info (0)
+    , m_jit_info (0)
 #endif
 {
   if (cmd_list)
@@ -234,20 +234,20 @@
 
 octave_user_function::~octave_user_function (void)
 {
-  delete param_list;
-  delete ret_list;
-  delete lead_comm;
-  delete trail_comm;
+  delete m_param_list;
+  delete m_ret_list;
+  delete m_lead_comm;
+  delete m_trail_comm;
 
 #if defined (HAVE_LLVM)
-  delete jit_info;
+  delete m_jit_info;
 #endif
 }
 
 octave_user_function *
 octave_user_function::define_ret_list (octave::tree_parameter_list *t)
 {
-  ret_list = t;
+  m_ret_list = t;
 
   return this;
 }
@@ -328,7 +328,7 @@
 
   if (is_anonymous_function ())
     result << "anonymous@" << fcn_file_name ()
-           << ':' << location_line << ':' << location_column;
+           << ':' << m_location_line << ':' << m_location_column;
   else if (is_subfunction ())
     result << parent_fcn_name () << '>' << name ();
   else if (is_class_method ())
@@ -337,7 +337,7 @@
     result << '@' << name ();
   else if (is_inline_function ())
     result << "inline@" << fcn_file_name ()
-           << ':' << location_line << ':' << location_column;
+           << ':' << m_location_line << ':' << m_location_column;
   else
     result << name ();
 
@@ -368,10 +368,10 @@
                                           : canonical_fcn_file_dir;
 
       if (fcn_file_dir == ff_name.substr (0, fcn_file_dir.length ()))
-        system_fcn_file = true;
+        m_system_fcn_file = true;
     }
   else
-    system_fcn_file = false;
+    m_system_fcn_file = false;
 }
 
 void
@@ -383,13 +383,13 @@
 bool
 octave_user_function::takes_varargs (void) const
 {
-  return (param_list && param_list->takes_varargs ());
+  return (m_param_list && m_param_list->takes_varargs ());
 }
 
 bool
 octave_user_function::takes_var_return (void) const
 {
-  return (ret_list && ret_list->takes_varargs ());
+  return (m_ret_list && m_ret_list->takes_varargs ());
 }
 
 void
@@ -472,10 +472,10 @@
 {
   octave_value_list retval;
 
-  octave_idx_type n = args.length () - num_named_args;
+  octave_idx_type n = args.length () - m_num_named_args;
 
   if (n > 0)
-    retval = args.slice (num_named_args, n);
+    retval = args.slice (m_num_named_args, n);
 
   return retval;
 }
@@ -524,12 +524,12 @@
 {
   bool retval = false;
   if (Voptimize_subsasgn_calls
-      && param_list && ret_list
-      && param_list->length () > 0 && ! param_list->varargs_only ()
-      && ret_list->length () == 1 && ! ret_list->takes_varargs ())
+      && m_param_list && m_ret_list
+      && m_param_list->length () > 0 && ! m_param_list->varargs_only ()
+      && m_ret_list->length () == 1 && ! m_ret_list->takes_varargs ())
     {
-      octave::tree_identifier *par1 = param_list->front ()->ident ();
-      octave::tree_identifier *ret1 = ret_list->front ()->ident ();
+      octave::tree_identifier *par1 = m_param_list->front ()->ident ();
+      octave::tree_identifier *ret1 = m_ret_list->front ()->ident ();
       retval = par1->name () == ret1->name ();
     }
 
@@ -541,7 +541,7 @@
 {
   std::string retval;
 
-  switch (class_constructor)
+  switch (m_class_constructor)
     {
     case none:
       retval = "none";
@@ -568,7 +568,7 @@
 {
   std::string retval;
 
-  switch (class_method)
+  switch (m_class_method)
     {
     case none:
       retval = "none";
@@ -595,19 +595,19 @@
 {
   std::map<std::string, octave_value> m
     = {{ "user_code", octave_user_code::dump () },
-       { "line", location_line },
-       { "col", location_column },
-       { "end_line", end_location_line },
-       { "end_col", end_location_column },
-       { "parent_name", parent_name },
-       { "system_fcn_file", system_fcn_file },
-       { "num_named_args", num_named_args },
-       { "subfunction", subfunction },
-       { "inline_function", inline_function },
-       { "anonymous_function", anonymous_function },
-       { "nested_function", nested_function },
+       { "line", m_location_line },
+       { "col", m_location_column },
+       { "end_line", m_end_location_line },
+       { "end_col", m_end_location_column },
+       { "parent_name", m_parent_name },
+       { "system_fcn_file", m_system_fcn_file },
+       { "num_named_args", m_num_named_args },
+       { "subfunction", m_subfunction },
+       { "inline_function", m_inline_function },
+       { "anonymous_function", m_anonymous_function },
+       { "nested_function", m_nested_function },
        { "ctor_type", ctor_type_str () },
-       { "class_method", class_method }};
+       { "class_method", m_class_method }};
 
   return octave_value (m);
 }
@@ -727,9 +727,9 @@
                  type.c_str ());
         }
 
-      octave::tree_parameter_list *param_list = fcn->parameter_list ();
+      octave::tree_parameter_list *m_param_list = fcn->parameter_list ();
 
-      retval = (param_list ? param_list->length () : 0);
+      retval = (m_param_list ? m_param_list->length () : 0);
       if (fcn->takes_varargs ())
         retval = -1 - retval;
     }
@@ -849,9 +849,9 @@
                  type.c_str ());
         }
 
-      octave::tree_parameter_list *ret_list = fcn->return_list ();
+      octave::tree_parameter_list *m_ret_list = fcn->return_list ();
 
-      retval = (ret_list ? ret_list->length () : 0);
+      retval = (m_ret_list ? m_ret_list->length () : 0);
 
       if (fcn->takes_var_return ())
         retval = -1 - retval;
--- a/libinterp/octave-value/ov-usr-fcn.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov-usr-fcn.h	Sun May 16 09:44:35 2021 +0200
@@ -238,35 +238,35 @@
 
   void stash_fcn_location (int line, int col)
   {
-    location_line = line;
-    location_column = col;
+    m_location_line = line;
+    m_location_column = col;
   }
 
-  int beginning_line (void) const { return location_line; }
-  int beginning_column (void) const { return location_column; }
+  int beginning_line (void) const { return m_location_line; }
+  int beginning_column (void) const { return m_location_column; }
 
   void stash_fcn_end_location (int line, int col)
   {
-    end_location_line = line;
-    end_location_column = col;
+    m_end_location_line = line;
+    m_end_location_column = col;
   }
 
-  int ending_line (void) const { return end_location_line; }
-  int ending_column (void) const { return end_location_column; }
+  int ending_line (void) const { return m_end_location_line; }
+  int ending_column (void) const { return m_end_location_column; }
 
   void maybe_relocate_end (void);
 
-  void stash_parent_fcn_name (const std::string& p) { parent_name = p; }
+  void stash_parent_fcn_name (const std::string& p) { m_parent_name = p; }
 
   void stash_parent_fcn_scope (const octave::symbol_scope& ps);
 
-  void stash_leading_comment (octave::comment_list *lc) { lead_comm = lc; }
+  void stash_leading_comment (octave::comment_list *lc) { m_lead_comm = lc; }
 
-  void stash_trailing_comment (octave::comment_list *tc) { trail_comm = tc; }
+  void stash_trailing_comment (octave::comment_list *tc) { m_trail_comm = tc; }
 
   std::string profiler_name (void) const;
 
-  std::string parent_fcn_name (void) const { return parent_name; }
+  std::string parent_fcn_name (void) const { return m_parent_name; }
 
   octave::symbol_scope parent_fcn_scope (void) const
   {
@@ -280,7 +280,7 @@
 
   void mark_as_system_fcn_file (void);
 
-  bool is_system_fcn_file (void) const { return system_fcn_file; }
+  bool is_system_fcn_file (void) const { return m_system_fcn_file; }
 
   bool is_user_function (void) const { return true; }
 
@@ -310,22 +310,22 @@
 
   void stash_function_name (const std::string& s) { my_name = s; }
 
-  void mark_as_subfunction (void) { subfunction = true; }
+  void mark_as_subfunction (void) { m_subfunction = true; }
 
-  bool is_subfunction (void) const { return subfunction; }
+  bool is_subfunction (void) const { return m_subfunction; }
 
-  void mark_as_inline_function (void) { inline_function = true; }
+  void mark_as_inline_function (void) { m_inline_function = true; }
 
-  bool is_inline_function (void) const { return inline_function; }
+  bool is_inline_function (void) const { return m_inline_function; }
 
-  void mark_as_anonymous_function (void) { anonymous_function = true; }
+  void mark_as_anonymous_function (void) { m_anonymous_function = true; }
 
-  bool is_anonymous_function (void) const { return anonymous_function; }
+  bool is_anonymous_function (void) const { return m_anonymous_function; }
 
   bool is_anonymous_function_of_class
   (const std::string& cname = "") const
   {
-    return anonymous_function
+    return m_anonymous_function
            ? (cname.empty ()
               ? (! dispatch_class ().empty ())
               : cname == dispatch_class ())
@@ -340,41 +340,41 @@
     return is_inline_function () || is_anonymous_function ();
   }
 
-  void mark_as_nested_function (void) { nested_function = true; }
+  void mark_as_nested_function (void) { m_nested_function = true; }
 
-  bool is_nested_function (void) const { return nested_function; }
+  bool is_nested_function (void) const { return m_nested_function; }
 
   bool is_parent_function (void) const { return m_scope.is_parent (); }
 
-  void mark_as_legacy_constructor (void) { class_constructor = legacy; }
+  void mark_as_legacy_constructor (void) { m_class_constructor = legacy; }
 
   bool is_legacy_constructor (const std::string& cname = "") const
   {
-    return (class_constructor == legacy
+    return (m_class_constructor == legacy
             ? (cname.empty () ? true : cname == dispatch_class ()) : false);
   }
 
-  void mark_as_classdef_constructor (void) { class_constructor = classdef; }
+  void mark_as_classdef_constructor (void) { m_class_constructor = classdef; }
 
   bool is_classdef_constructor (const std::string& cname = "") const
   {
-    return (class_constructor == classdef
+    return (m_class_constructor == classdef
             ? (cname.empty () ? true : cname == dispatch_class ()) : false);
   }
 
-  void mark_as_legacy_method (void) { class_method = legacy; }
+  void mark_as_legacy_method (void) { m_class_method = legacy; }
 
   bool is_legacy_method (const std::string& cname = "") const
   {
-    return (class_method == legacy
+    return (m_class_method == legacy
             ? (cname.empty () ? true : cname == dispatch_class ()) : false);
   }
 
-  void mark_as_classdef_method (void) { class_method = classdef; }
+  void mark_as_classdef_method (void) { m_class_method = classdef; }
 
   bool is_classdef_method (const std::string& cname = "") const
   {
-    return (class_method == classdef
+    return (m_class_method == classdef
             ? (cname.empty () ? true : cname == dispatch_class ()) : false);
   }
 
@@ -391,13 +391,13 @@
   execute (octave::tree_evaluator& tw, int nargout = 0,
            const octave_value_list& args = octave_value_list ());
 
-  octave::tree_parameter_list * parameter_list (void) { return param_list; }
+  octave::tree_parameter_list * parameter_list (void) { return m_param_list; }
 
-  octave::tree_parameter_list * return_list (void) { return ret_list; }
+  octave::tree_parameter_list * return_list (void) { return m_ret_list; }
 
-  octave::comment_list * leading_comment (void) { return lead_comm; }
+  octave::comment_list * leading_comment (void) { return m_lead_comm; }
 
-  octave::comment_list * trailing_comment (void) { return trail_comm; }
+  octave::comment_list * trailing_comment (void) { return m_trail_comm; }
 
   // If is_special_expr is true, retrieve the sigular expression that forms the
   // body.  May be null (even if is_special_expr is true).
@@ -408,9 +408,9 @@
   void accept (octave::tree_walker& tw);
 
 #if defined (HAVE_LLVM)
-  octave::jit_function_info * get_info (void) { return jit_info; }
+  octave::jit_function_info * get_info (void) { return m_jit_info; }
 
-  void stash_info (octave::jit_function_info *info) { jit_info = info; }
+  void stash_info (octave::jit_function_info *info) { m_jit_info = info; }
 #endif
 
   octave_value dump (void) const;
@@ -428,58 +428,58 @@
   std::string method_type_str (void) const;
 
   // List of arguments for this function.  These are local variables.
-  octave::tree_parameter_list *param_list;
+  octave::tree_parameter_list *m_param_list;
 
   // List of parameters we return.  These are also local variables in
   // this function.
-  octave::tree_parameter_list *ret_list;
+  octave::tree_parameter_list *m_ret_list;
 
   // The comments preceding the FUNCTION token.
-  octave::comment_list *lead_comm;
+  octave::comment_list *m_lead_comm;
 
   // The comments preceding the ENDFUNCTION token.
-  octave::comment_list *trail_comm;
+  octave::comment_list *m_trail_comm;
 
   // Location where this function was defined.
-  int location_line;
-  int location_column;
-  int end_location_line;
-  int end_location_column;
+  int m_location_line;
+  int m_location_column;
+  int m_end_location_line;
+  int m_end_location_column;
 
   // The name of the parent function, if any.
-  std::string parent_name;
+  std::string m_parent_name;
 
   // 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.
-  bool system_fcn_file;
+  bool m_system_fcn_file;
 
   // The number of arguments that have names.
-  int num_named_args;
+  int m_num_named_args;
 
-  // TRUE means this is a subfunction of a primary function.
-  bool subfunction;
+  // TRUE means this is a m_subfunction of a primary function.
+  bool m_subfunction;
 
   // TRUE means this is an inline function.
-  bool inline_function;
+  bool m_inline_function;
 
   // TRUE means this is an anonymous function.
-  bool anonymous_function;
+  bool m_anonymous_function;
 
   // TRUE means this is a nested function.
-  bool nested_function;
+  bool m_nested_function;
 
   // TRUE means this function contains a nested function.
-  bool parent_function;
+  bool m_parent_function;
 
   // Enum describing whether this function is the constructor for class object.
-  class_method_type class_constructor;
+  class_method_type m_class_constructor;
 
   // Enum describing whether this function is a method for a class.
-  class_method_type class_method;
+  class_method_type m_class_method;
 
 #if defined (HAVE_LLVM)
-  octave::jit_function_info *jit_info;
+  octave::jit_function_info *m_jit_info;
 #endif
 
   void maybe_relocate_end_internal (void);
--- a/libinterp/octave-value/ov.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov.cc	Sun May 16 09:44:35 2021 +0200
@@ -76,6 +76,7 @@
 #include "ov-usr-fcn.h"
 #include "ov-fcn-handle.h"
 #include "ov-typeinfo.h"
+#include "ov-magic-int.h"
 #include "ov-null-mat.h"
 #include "ov-lazy-idx.h"
 #include "ov-java.h"
@@ -1003,22 +1004,22 @@
   maybe_mutate ();
 }
 
-octave_value::octave_value (const idx_vector& idx, bool lazy)
+octave_value::octave_value (const octave::idx_vector& idx, bool lazy)
   : rep ()
 {
   double scalar;
-  Range range;
+  octave::range<double> range;
   NDArray array;
   boolNDArray mask;
-  idx_vector::idx_class_type idx_class;
+  octave::idx_vector::idx_class_type idx_class;
 
   if (lazy)
     {
       // Only make lazy indices out of ranges and index vectors.
       switch (idx.idx_class ())
         {
-        case idx_vector::class_range:
-        case idx_vector::class_vector:
+        case octave::idx_vector::class_range:
+        case octave::idx_vector::class_vector:
           rep = new octave_lazy_index (idx);
           maybe_mutate ();
           return;
@@ -1032,23 +1033,23 @@
 
   switch (idx_class)
     {
-    case idx_vector::class_colon:
+    case octave::idx_vector::class_colon:
       rep = new octave_magic_colon ();
       break;
 
-    case idx_vector::class_range:
+    case octave::idx_vector::class_range:
       rep = new octave_range (range, idx);
       break;
 
-    case idx_vector::class_scalar:
+    case octave::idx_vector::class_scalar:
       rep = new octave_scalar (scalar);
       break;
 
-    case idx_vector::class_vector:
+    case octave::idx_vector::class_vector:
       rep = new octave_matrix (array, idx);
       break;
 
-    case idx_vector::class_mask:
+    case octave::idx_vector::class_mask:
       rep = new octave_bool_matrix (mask, idx);
       break;
 
@@ -1068,15 +1069,126 @@
 }
 
 octave_value::octave_value (double base, double limit, double inc)
-  : rep (new octave_range (base, limit, inc))
+  : rep (new ov_range<double> (octave::range<double> (base, inc, limit)))
 {
   maybe_mutate ();
 }
 
 octave_value::octave_value (const Range& r, bool force_range)
+  : rep (nullptr)
+{
+  if (! force_range && ! r.ok ())
+    error ("invalid range");
+
+  if (force_range || ! Vdisable_range)
+    rep = dynamic_cast<octave_base_value *> (new ov_range<double> (octave::range<double> (r.base (), r.increment (), r.limit ())));
+  else
+    rep = dynamic_cast<octave_base_value *> (new octave_matrix (r.matrix_value ()));
+
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<char>& r, char type,
+                            bool /*force_range*/)
+#if 0
   : rep (force_range || ! Vdisable_range
-         ? dynamic_cast<octave_base_value *> (new octave_range (r))
-         : dynamic_cast<octave_base_value *> (new octave_matrix (r.matrix_value ())))
+         ? dynamic_cast<octave_base_value *> (new octave_char_range (r, type))
+         : dynamic_cast<octave_base_value *> (type == '"'
+                                              ? new octave_char_matrix_dq_str (r.array_value ())
+                                              : new octave_char_matrix_sq_str (r.array_value ())))
+#else
+  : rep (type == '"'
+         ? new octave_char_matrix_dq_str (r.array_value ())
+         : new octave_char_matrix_sq_str (r.array_value ()))
+#endif
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<float>& r, bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<float> (r))
+         : dynamic_cast<octave_base_value *> (new octave_float_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<double>& r, bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<double> (r))
+         : dynamic_cast<octave_base_value *> (new octave_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_int8>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_int8> (r))
+         : dynamic_cast<octave_base_value *> (new octave_int8_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_int16>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_int16> (r))
+         : dynamic_cast<octave_base_value *> (new octave_int16_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_int32>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_int32> (r))
+         : dynamic_cast<octave_base_value *> (new octave_int32_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_int64>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_int64> (r))
+         : dynamic_cast<octave_base_value *> (new octave_int64_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_uint8>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint8> (r))
+         : dynamic_cast<octave_base_value *> (new octave_uint8_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_uint16>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint16> (r))
+         : dynamic_cast<octave_base_value *> (new octave_uint16_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_uint32>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint32> (r))
+         : dynamic_cast<octave_base_value *> (new octave_uint32_matrix (r.array_value ())))
+{
+  maybe_mutate ();
+}
+
+octave_value::octave_value (const octave::range<octave_uint64>& r,
+                            bool force_range)
+  : rep (force_range || ! Vdisable_range
+         ? dynamic_cast<octave_base_value *> (new ov_range<octave_uint64> (r))
+         : dynamic_cast<octave_base_value *> (new octave_uint64_matrix (r.array_value ())))
 {
   maybe_mutate ();
 }
@@ -1241,7 +1353,7 @@
 %!assert (class (single (uint64 (1))), "single")
 %!assert (class (single (true)), "single")
 %!assert (class (single ("A")), "single")
-%!error (single (sparse (1)))
+%!error single (sparse (1))
 %!test
 %! x = diag ([1 3 2]);
 %! y = single (x);
@@ -1530,7 +1642,7 @@
 
       binary_op binop = op_eq_to_binary_op (op);
 
-      t_rhs = do_binary_op (binop, t, rhs);
+      t_rhs = octave::binary_op (binop, t, rhs);
     }
 
   *this = subsasgn (type, idx, t_rhs);
@@ -1562,7 +1674,7 @@
 
       if (f)
         {
-          f (*rep, octave_value_list (), *rhs.rep);
+          f (*rep, octave_value_list (), rhs.get_rep ());
           // Usually unnecessary, but may be needed (complex arrays).
           maybe_mutate ();
         }
@@ -1571,7 +1683,7 @@
 
           binary_op binop = op_eq_to_binary_op (op);
 
-          octave_value t = do_binary_op (binop, *this, rhs);
+          octave_value t = octave::binary_op (binop, *this, rhs);
 
           operator = (t);
         }
@@ -1633,7 +1745,7 @@
 
   if (rows () == test.rows () && columns () == test.columns ())
     {
-      octave_value tmp = do_binary_op (octave_value::op_eq, *this, test);
+      octave_value tmp = octave::binary_op (octave_value::op_eq, *this, test);
 
       // Empty array also means a match.
       if (tmp.is_defined ())
@@ -2007,17 +2119,17 @@
       {                                                 \
         retval = FCN ();                                \
       }                                                 \
-    catch (octave::execution_exception& e)               \
+    catch (octave::execution_exception& ee)             \
       {                                                 \
         if (fmt)                                        \
           {                                             \
             va_list args;                               \
             va_start (args, fmt);                       \
-            verror (e, fmt, args);                      \
+            verror (ee, fmt, args);                     \
             va_end (args);                              \
           }                                             \
                                                         \
-        throw e;                                        \
+        throw ee;                                       \
       }                                                 \
                                                         \
     return retval;                                      \
@@ -2108,7 +2220,16 @@
 XVALUE_EXTRACTOR (Cell, xcell_value, cell_value)
 XVALUE_EXTRACTOR (Array<std::string>, xcellstr_value, cellstr_value)
 
-XVALUE_EXTRACTOR (Range, xrange_value, range_value)
+XVALUE_EXTRACTOR (octave::range<float>, xfloat_range_value, float_range_value)
+XVALUE_EXTRACTOR (octave::range<double>, xrange_value, range_value)
+XVALUE_EXTRACTOR (octave::range<octave_int8>, xint8_range_value, int8_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_int16>, xint16_range_value, int16_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_int32>, xint32_range_value, int32_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_int64>, xint64_range_value, int64_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_uint8>, xuint8_range_value, uint8_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_uint16>, xuint16_range_value, uint16_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_uint32>, xuint32_range_value, uint32_range_value)
+XVALUE_EXTRACTOR (octave::range<octave_uint64>, xuint64_range_value, uint64_range_value)
 
 XVALUE_EXTRACTOR (octave_map, xmap_value, map_value)
 XVALUE_EXTRACTOR (octave_scalar_map, xscalar_map_value, scalar_map_value)
@@ -2150,6 +2271,10 @@
   octave_value retval = *this;
   if (isnull ())
     retval = octave_value (rep->empty_clone ());
+  else if (is_magic_int ())
+    retval = octave_value (rep->double_value ());
+  else if (is_range () && ! rep->is_storable ())
+    error ("range with infinite number of elements cannot be stored");
   else
     retval.maybe_economize ();
 
@@ -2166,6 +2291,15 @@
         delete rep;
       rep = rc;
     }
+  else if (is_magic_int ())
+    {
+      octave_base_value *rc = new octave_scalar (rep->double_value ());
+      if (--rep->count == 0)
+        delete rep;
+      rep = rc;
+    }
+  else if (is_range () && ! rep->is_storable ())
+    error ("range with infinite number of elements cannot be stored");
   else
     maybe_economize ();
 }
@@ -2184,457 +2318,6 @@
   return rep->write (os, block_size, output_type, skip, flt_fmt);
 }
 
-OCTAVE_NORETURN static void
-err_binary_op (const std::string& on, const std::string& tn1,
-               const std::string& tn2)
-{
-  error ("binary operator '%s' not implemented for '%s' by '%s' operations",
-         on.c_str (), tn1.c_str (), tn2.c_str ());
-}
-
-OCTAVE_NORETURN static void
-err_binary_op_conv (const std::string& on)
-{
-  error ("type conversion failed for binary operator '%s'", on.c_str ());
-}
-
-octave_value
-do_binary_op (octave::type_info& ti, octave_value::binary_op op,
-              const octave_value& v1, const octave_value& v2)
-{
-  octave_value retval;
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  if (t1 == octave_class::static_type_id ()
-      || t2 == octave_class::static_type_id ()
-      || t1 == octave_classdef::static_type_id ()
-      || t2 == octave_classdef::static_type_id ())
-    {
-      octave::type_info::binary_class_op_fcn f
-        = ti.lookup_binary_class_op (op);
-
-      if (! f)
-        err_binary_op (octave_value::binary_op_as_string (op),
-                       v1.class_name (), v2.class_name ());
-
-      retval = f (v1, v2);
-    }
-  else
-    {
-      // FIXME: we need to handle overloading operators for built-in
-      // classes (double, char, int8, etc.)
-
-      octave::type_info::binary_op_fcn f
-        = ti.lookup_binary_op (op, t1, t2);
-
-      if (f)
-        retval = f (*v1.rep, *v2.rep);
-      else
-        {
-          octave_value tv1;
-          octave_base_value::type_conv_info cf1
-            = v1.numeric_conversion_function ();
-
-          octave_value tv2;
-          octave_base_value::type_conv_info cf2
-            = v2.numeric_conversion_function ();
-
-          // Try biased (one-sided) conversions first.
-          if (cf2.type_id () >= 0
-              && ti.lookup_binary_op (op, t1, cf2.type_id ()))
-            cf1 = nullptr;
-          else if (cf1.type_id () >= 0
-                   && ti.lookup_binary_op (op, cf1.type_id (), t2))
-            cf2 = nullptr;
-
-          if (cf1)
-            {
-              octave_base_value *tmp = cf1 (*v1.rep);
-
-              if (! tmp)
-                err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-              tv1 = octave_value (tmp);
-              t1 = tv1.type_id ();
-            }
-          else
-            tv1 = v1;
-
-          if (cf2)
-            {
-              octave_base_value *tmp = cf2 (*v2.rep);
-
-              if (! tmp)
-                err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-              tv2 = octave_value (tmp);
-              t2 = tv2.type_id ();
-            }
-          else
-            tv2 = v2;
-
-          if (cf1 || cf2)
-            {
-              retval = do_binary_op (op, tv1, tv2);
-            }
-          else
-            {
-              //demote double -> single and try again
-              cf1 = tv1.numeric_demotion_function ();
-
-              cf2 = tv2.numeric_demotion_function ();
-
-              // Try biased (one-sided) conversions first.
-              if (cf2.type_id () >= 0
-                  && ti.lookup_binary_op (op, t1, cf2.type_id ()))
-                cf1 = nullptr;
-              else if (cf1.type_id () >= 0
-                       && ti.lookup_binary_op (op, cf1.type_id (), t2))
-                cf2 = nullptr;
-
-              if (cf1)
-                {
-                  octave_base_value *tmp = cf1 (*tv1.rep);
-
-                  if (! tmp)
-                    err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-                  tv1 = octave_value (tmp);
-                  t1 = tv1.type_id ();
-                }
-
-              if (cf2)
-                {
-                  octave_base_value *tmp = cf2 (*tv2.rep);
-
-                  if (! tmp)
-                    err_binary_op_conv (octave_value::binary_op_as_string (op));
-
-                  tv2 = octave_value (tmp);
-                  t2 = tv2.type_id ();
-                }
-
-              if (! cf1 && ! cf2)
-                err_binary_op (octave_value::binary_op_as_string (op),
-                               v1.type_name (), v2.type_name ());
-
-              f = ti.lookup_binary_op (op, t1, t2);
-
-              if (! f)
-                err_binary_op (octave_value::binary_op_as_string (op),
-                               v1.type_name (), v2.type_name ());
-
-              retval = f (*tv1.rep, *tv2.rep);
-            }
-        }
-    }
-
-  return retval;
-}
-
-octave_value
-do_binary_op (octave_value::binary_op op,
-              const octave_value& v1, const octave_value& v2)
-{
-  octave::type_info& ti = octave::__get_type_info__ ("do_binary_op");
-
-  return do_binary_op (ti, op, v1, v2);
-}
-
-static octave_value
-decompose_binary_op (octave::type_info& ti,
-                     octave_value::compound_binary_op op,
-                     const octave_value& v1, const octave_value& v2)
-{
-  switch (op)
-    {
-    case octave_value::op_trans_mul:
-      return do_binary_op (octave_value::op_mul,
-                           do_unary_op (octave_value::op_transpose, v1), v2);
-
-    case octave_value::op_mul_trans:
-      return do_binary_op (ti, octave_value::op_mul,
-                           v1, do_unary_op (octave_value::op_transpose, v2));
-
-    case octave_value::op_herm_mul:
-      return do_binary_op (ti, octave_value::op_mul,
-                           do_unary_op (octave_value::op_hermitian, v1), v2);
-
-    case octave_value::op_mul_herm:
-      return do_binary_op (ti, octave_value::op_mul,
-                           v1, do_unary_op (octave_value::op_hermitian, v2));
-
-    case octave_value::op_trans_ldiv:
-      return do_binary_op (ti, octave_value::op_ldiv,
-                           do_unary_op (octave_value::op_transpose, v1), v2);
-
-    case octave_value::op_herm_ldiv:
-      return do_binary_op (ti, octave_value::op_ldiv,
-                           do_unary_op (octave_value::op_hermitian, v1), v2);
-
-    case octave_value::op_el_not_and:
-      return do_binary_op (ti, octave_value::op_el_and,
-                           do_unary_op (octave_value::op_not, v1), v2);
-
-    case octave_value::op_el_not_or:
-      return do_binary_op (ti, octave_value::op_el_or,
-                           do_unary_op (octave_value::op_not, v1), v2);
-
-    case octave_value::op_el_and_not:
-      return do_binary_op (ti, octave_value::op_el_and,
-                           v1, do_unary_op (octave_value::op_not, v2));
-
-    case octave_value::op_el_or_not:
-      return do_binary_op (ti, octave_value::op_el_or,
-                           v1, do_unary_op (octave_value::op_not, v2));
-
-    default:
-      error ("invalid compound operator");
-    }
-}
-
-octave_value
-do_binary_op (octave::type_info& ti, octave_value::compound_binary_op op,
-              const octave_value& v1, const octave_value& v2)
-{
-  octave_value retval;
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  if (t1 == octave_class::static_type_id ()
-      || t2 == octave_class::static_type_id ()
-      || t1 == octave_classdef::static_type_id ()
-      || t2 == octave_classdef::static_type_id ())
-    {
-      octave::type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
-
-      if (f)
-        retval = f (v1, v2);
-      else
-        retval = decompose_binary_op (ti, op, v1, v2);
-    }
-  else
-    {
-      octave::type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2);
-
-      if (f)
-        retval = f (*v1.rep, *v2.rep);
-      else
-        retval = decompose_binary_op (ti, op, v1, v2);
-    }
-
-  return retval;
-}
-
-octave_value
-do_binary_op (octave_value::compound_binary_op op,
-              const octave_value& v1, const octave_value& v2)
-{
-  octave::type_info& ti = octave::__get_type_info__ ("do_binary_op");
-
-  return do_binary_op (ti, op, v1, v2);
-}
-
-OCTAVE_NORETURN static void
-err_cat_op (const std::string& tn1, const std::string& tn2)
-{
-  error ("concatenation operator not implemented for '%s' by '%s' operations",
-         tn1.c_str (), tn2.c_str ());
-}
-
-OCTAVE_NORETURN static void
-err_cat_op_conv (void)
-{
-  error ("type conversion failed for concatenation operator");
-}
-
-octave_value
-do_cat_op (octave::type_info& ti, const octave_value& v1,
-           const octave_value& v2, const Array<octave_idx_type>& ra_idx)
-{
-  octave_value retval;
-
-  // Can't rapid return for concatenation with an empty object here as
-  // something like cat(1,[],single([]) must return the correct type.
-
-  int t1 = v1.type_id ();
-  int t2 = v2.type_id ();
-
-  octave::type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2);
-
-  if (f)
-    retval = f (*v1.rep, *v2.rep, ra_idx);
-  else
-    {
-      octave_value tv1;
-      octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function ();
-
-      octave_value tv2;
-      octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function ();
-
-      // Try biased (one-sided) conversions first.
-      if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ()))
-        cf1 = nullptr;
-      else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2))
-        cf2 = nullptr;
-
-      if (cf1)
-        {
-          octave_base_value *tmp = cf1 (*v1.rep);
-
-          if (! tmp)
-            err_cat_op_conv ();
-
-          tv1 = octave_value (tmp);
-          t1 = tv1.type_id ();
-        }
-      else
-        tv1 = v1;
-
-      if (cf2)
-        {
-          octave_base_value *tmp = cf2 (*v2.rep);
-
-          if (! tmp)
-            err_cat_op_conv ();
-
-          tv2 = octave_value (tmp);
-          t2 = tv2.type_id ();
-        }
-      else
-        tv2 = v2;
-
-      if (! cf1 && ! cf2)
-        err_cat_op (v1.type_name (), v2.type_name ());
-
-      retval = do_cat_op (ti, tv1, tv2, ra_idx);
-    }
-
-  return retval;
-}
-
-octave_value
-do_cat_op (const octave_value& v1, const octave_value& v2,
-           const Array<octave_idx_type>& ra_idx)
-{
-  octave::type_info& ti = octave::__get_type_info__ ("do_cat_op");
-
-  return do_cat_op (ti, v1, v2, ra_idx);
-}
-
-octave_value
-do_colon_op (const octave_value& base, const octave_value& increment,
-             const octave_value& limit, bool is_for_cmd_expr)
-{
-  octave_value retval;
-
-  if (base.isobject () || increment.isobject () || limit.isobject ())
-    {
-      std::string dispatch_type;
-
-      if (base.isobject ())
-        dispatch_type = base.class_name ();
-      else if (increment.is_defined () && increment.isobject ())
-        dispatch_type = increment.class_name ();
-      else
-        dispatch_type = limit.class_name ();
-
-      octave::symbol_table& symtab = octave::__get_symbol_table__ ("do_colon_op");
-
-      octave_value meth = symtab.find_method ("colon", dispatch_type);
-
-      if (! meth.is_defined ())
-        error ("colon method not defined for %s class", dispatch_type.c_str ());
-
-      octave_value_list args;
-
-      if (increment.is_defined ())
-        {
-          args(2) = limit;
-          args(1) = increment;
-        }
-      else
-        args(1) = limit;
-
-      args(0) = base;
-
-      octave_value_list tmp = octave::feval (meth.function_value (), args, 1);
-
-      if (tmp.length () > 0)
-        retval = tmp(0);
-    }
-  else
-    {
-      bool result_is_str = (base.is_string () && limit.is_string ());
-      bool dq_str = (base.is_dq_string () || limit.is_dq_string ());
-
-      if (base.numel () > 1 || limit.numel () > 1
-          || (increment.is_defined () && increment.numel () > 1))
-        warning_with_id ("Octave:colon-nonscalar-argument",
-                         "colon arguments should be scalars");
-
-      if (base.iscomplex () || limit.iscomplex ()
-          || (increment.is_defined () && increment.iscomplex ()))
-        warning_with_id ("Octave:colon-complex-argument",
-                         "imaginary part of complex colon arguments is ignored");
-
-      Matrix m_base, m_limit, m_increment;
-
-      try
-        {
-          m_base = base.matrix_value (true);
-        }
-      catch (octave::execution_exception& e)
-        {
-          error (e, "invalid base value in colon expression");
-        }
-
-      try
-        {
-          m_limit = limit.matrix_value (true);
-        }
-      catch (octave::execution_exception& e)
-        {
-          error (e, "invalid limit value in colon expression");
-        }
-
-      try
-        {
-          m_increment = (increment.is_defined ()
-                         ? increment.matrix_value (true)
-                         : Matrix (1, 1, 1.0));
-        }
-      catch (octave::execution_exception& e)
-        {
-          error (e, "invalid increment value in colon expression");
-        }
-
-      bool base_empty = m_base.isempty ();
-      bool limit_empty = m_limit.isempty ();
-      bool increment_empty = m_increment.isempty ();
-
-      if (base_empty || limit_empty || increment_empty)
-        retval = Range ();
-      else
-        {
-          Range r (m_base(0), m_limit(0), m_increment(0));
-
-          // For compatibility with Matlab, don't allow the range used in
-          // a FOR loop expression to be converted to a Matrix.
-
-          retval = octave_value (r, is_for_cmd_expr);
-
-          if (result_is_str)
-            retval = (retval.convert_to_str (false, true, dq_str ? '"' : '\''));
-        }
-    }
-
-  return retval;
-}
-
 void
 octave_value::print_info (std::ostream& os, const std::string& prefix) const
 {
@@ -2645,75 +2328,72 @@
   rep->print_info (os, prefix + ' ');
 }
 
-OCTAVE_NORETURN static void
-err_unary_op (const std::string& on, const std::string& tn)
-{
-  error ("unary operator '%s' not implemented for '%s' operands",
-         on.c_str (), tn.c_str ());
-}
-
-OCTAVE_NORETURN static void
-err_unary_op_conv (const std::string& on)
+void *
+octave_value::mex_get_data (mxClassID class_id, mxComplexity complexity) const
 {
-  error ("type conversion failed for unary operator '%s'", on.c_str ());
-}
-
-octave_value
-do_unary_op (octave::type_info& ti, octave_value::unary_op op,
-             const octave_value& v)
-{
-  octave_value retval;
-
-  int t = v.type_id ();
-
-  if (t == octave_class::static_type_id ()
-      || t == octave_classdef::static_type_id ())
-    {
-      octave::type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op);
-
-      if (! f)
-        err_unary_op (octave_value::unary_op_as_string (op), v.class_name ());
-
-      retval = f (v);
-    }
-  else
+  // If class_id is set to mxUNKNOWN_CLASS, return data for any type.
+  // Otherwise, require that REP matches the requested type and
+  // complexity.
+
+  if (class_id != mxUNKNOWN_CLASS)
     {
-      // FIXME: we need to handle overloading operators for built-in
-      // classes (double, char, int8, etc.)
-
-      octave::type_info::unary_op_fcn f = ti.lookup_unary_op (op, t);
-
-      if (f)
-        retval = f (*v.rep);
-      else
+      bool type_ok = false;
+
+      switch (class_id)
         {
-          octave_value tv;
-          octave_base_value::type_conv_fcn cf
-            = v.numeric_conversion_function ();
-
-          if (! cf)
-            err_unary_op (octave_value::unary_op_as_string (op),
-                          v.type_name ());
-
-          octave_base_value *tmp = cf (*v.rep);
-
-          if (! tmp)
-            err_unary_op_conv (octave_value::unary_op_as_string (op));
-
-          tv = octave_value (tmp);
-          retval = do_unary_op (op, tv);
+        case mxDOUBLE_CLASS:
+          type_ok = is_double_type ();
+          break;
+
+        case mxSINGLE_CLASS:
+          type_ok = is_single_type ();
+          break;
+
+        case mxINT8_CLASS:
+          type_ok = is_int8_type ();
+          break;
+
+        case mxINT16_CLASS:
+          type_ok = is_int16_type ();
+          break;
+
+        case mxINT32_CLASS:
+          type_ok = is_int32_type ();
+          break;
+
+        case mxINT64_CLASS:
+          type_ok = is_int64_type ();
+          break;
+
+        case mxUINT8_CLASS:
+          type_ok = is_uint8_type ();
+          break;
+
+        case mxUINT16_CLASS:
+          type_ok = is_uint16_type ();
+          break;
+
+        case mxUINT32_CLASS:
+          type_ok = is_uint32_type ();
+          break;
+
+        case mxUINT64_CLASS:
+          type_ok = is_uint64_type ();
+          break;
+
+        default:
+          // We only expect to see numeric types explicitly requested.
+          error ("mex_get_data: unexpected type requested");
         }
+
+      if (! type_ok)
+        error ("mex_get_data: type mismatch");
+
+      if (complexity == mxCOMPLEX && ! iscomplex ())
+        error ("mex_get_data: objectis not complex as requested");
     }
 
-  return retval;
-}
-
-octave_value
-do_unary_op (octave_value::unary_op op, const octave_value& v)
-{
-  octave::type_info& ti = octave::__get_type_info__ ("do_unary_op");
-
-  return do_unary_op (ti, op, v);
+  return rep->mex_get_data ();
 }
 
 OCTAVE_NORETURN static void
@@ -2724,8 +2404,15 @@
          op.c_str (), tn.c_str ());
 }
 
+OCTAVE_NORETURN static void
+err_unary_op (const std::string& on, const std::string& tn)
+{
+  error ("unary operator '%s' not implemented for '%s' operands",
+         on.c_str (), tn.c_str ());
+}
+
 octave_value&
-octave_value::do_non_const_unary_op (unary_op op)
+octave_value::non_const_unary_op (unary_op op)
 {
   if (op == op_incr || op == op_decr)
     {
@@ -2743,8 +2430,7 @@
       // Genuine.
       int t = type_id ();
 
-      octave::type_info& ti
-        = octave::__get_type_info__ ("do_non_const_unary_op");
+      octave::type_info& ti = octave::__get_type_info__ ("non_const_unary_op");
 
       octave::type_info::non_const_unary_op_fcn f
         = ti.lookup_non_const_unary_op (op, t);
@@ -2808,7 +2494,7 @@
       if (rep->count == 1)
         {
           octave::type_info& ti
-            = octave::__get_type_info__ ("do_non_const_unary_op");
+            = octave::__get_type_info__ ("non_const_unary_op");
 
           f = ti.lookup_non_const_unary_op (op, t);
         }
@@ -2816,18 +2502,18 @@
       if (f)
         f (*rep);
       else
-        *this = do_unary_op (op, *this);
+        *this = octave::unary_op (op, *this);
     }
 
   return *this;
 }
 
 octave_value&
-octave_value::do_non_const_unary_op (unary_op op, const std::string& type,
-                                     const std::list<octave_value_list>& idx)
+octave_value::non_const_unary_op (unary_op op, const std::string& type,
+                                  const std::list<octave_value_list>& idx)
 {
   if (idx.empty ())
-    do_non_const_unary_op (op);
+    non_const_unary_op (op);
   else
     {
       // FIXME: only do the following stuff if we can't find a
@@ -2937,6 +2623,636 @@
     return octave_value (rhs.empty_clone ());
 }
 
+namespace octave
+{
+  OCTAVE_NORETURN static void
+  err_binary_op (const std::string& on, const std::string& tn1,
+                 const std::string& tn2)
+  {
+    error ("binary operator '%s' not implemented for '%s' by '%s' operations",
+           on.c_str (), tn1.c_str (), tn2.c_str ());
+  }
+
+  OCTAVE_NORETURN static void
+  err_binary_op_conv (const std::string& on)
+  {
+    error ("type conversion failed for binary operator '%s'", on.c_str ());
+  }
+
+  octave_value
+  binary_op (type_info& ti, octave_value::binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    octave_value retval;
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    if (t1 == octave_class::static_type_id ()
+        || t2 == octave_class::static_type_id ()
+        || t1 == octave_classdef::static_type_id ()
+        || t2 == octave_classdef::static_type_id ())
+      {
+        type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
+
+        if (! f)
+          err_binary_op (octave_value::binary_op_as_string (op),
+                         v1.class_name (), v2.class_name ());
+
+        retval = f (v1, v2);
+      }
+    else
+      {
+        // FIXME: we need to handle overloading operators for built-in
+        // classes (double, char, int8, etc.)
+
+        type_info::binary_op_fcn f
+          = ti.lookup_binary_op (op, t1, t2);
+
+        if (f)
+          retval = f (v1.get_rep (), v2.get_rep ());
+        else
+          {
+            octave_value tv1;
+            octave_base_value::type_conv_info cf1
+              = v1.numeric_conversion_function ();
+
+            octave_value tv2;
+            octave_base_value::type_conv_info cf2
+              = v2.numeric_conversion_function ();
+
+            // Try biased (one-sided) conversions first.
+            if (cf2.type_id () >= 0
+                && ti.lookup_binary_op (op, t1, cf2.type_id ()))
+              cf1 = nullptr;
+            else if (cf1.type_id () >= 0
+                     && ti.lookup_binary_op (op, cf1.type_id (), t2))
+              cf2 = nullptr;
+
+            if (cf1)
+              {
+                octave_base_value *tmp = cf1 (v1.get_rep ());
+
+                if (! tmp)
+                  err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                tv1 = octave_value (tmp);
+                t1 = tv1.type_id ();
+              }
+            else
+              tv1 = v1;
+
+            if (cf2)
+              {
+                octave_base_value *tmp = cf2 (v2.get_rep ());
+
+                if (! tmp)
+                  err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                tv2 = octave_value (tmp);
+                t2 = tv2.type_id ();
+              }
+            else
+              tv2 = v2;
+
+            if (cf1 || cf2)
+              {
+                retval = binary_op (op, tv1, tv2);
+              }
+            else
+              {
+                //demote double -> single and try again
+                cf1 = tv1.numeric_demotion_function ();
+
+                cf2 = tv2.numeric_demotion_function ();
+
+                // Try biased (one-sided) conversions first.
+                if (cf2.type_id () >= 0
+                    && ti.lookup_binary_op (op, t1, cf2.type_id ()))
+                  cf1 = nullptr;
+                else if (cf1.type_id () >= 0
+                         && ti.lookup_binary_op (op, cf1.type_id (), t2))
+                  cf2 = nullptr;
+
+                if (cf1)
+                  {
+                    octave_base_value *tmp = cf1 (tv1.get_rep ());
+
+                    if (! tmp)
+                      err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                    tv1 = octave_value (tmp);
+                    t1 = tv1.type_id ();
+                  }
+
+                if (cf2)
+                  {
+                    octave_base_value *tmp = cf2 (tv2.get_rep ());
+
+                    if (! tmp)
+                      err_binary_op_conv (octave_value::binary_op_as_string (op));
+
+                    tv2 = octave_value (tmp);
+                    t2 = tv2.type_id ();
+                  }
+
+                if (! cf1 && ! cf2)
+                  err_binary_op (octave_value::binary_op_as_string (op),
+                                 v1.type_name (), v2.type_name ());
+
+                f = ti.lookup_binary_op (op, t1, t2);
+
+                if (! f)
+                  err_binary_op (octave_value::binary_op_as_string (op),
+                                 v1.type_name (), v2.type_name ());
+
+                retval = f (tv1.get_rep (), tv2.get_rep ());
+              }
+          }
+      }
+
+    return retval;
+  }
+
+  octave_value
+  binary_op (octave_value::binary_op op, const octave_value& v1,
+             const octave_value& v2)
+  {
+    type_info& ti = __get_type_info__ ("binary_op");
+
+    return binary_op (ti, op, v1, v2);
+  }
+
+  static octave_value
+  decompose_binary_op (type_info& ti, octave_value::compound_binary_op op,
+                       const octave_value& v1, const octave_value& v2)
+  {
+    switch (op)
+      {
+      case octave_value::op_trans_mul:
+        return binary_op (octave_value::op_mul,
+                          unary_op (octave_value::op_transpose, v1), v2);
+
+      case octave_value::op_mul_trans:
+        return binary_op (ti, octave_value::op_mul,
+                          v1, unary_op (octave_value::op_transpose, v2));
+
+      case octave_value::op_herm_mul:
+        return binary_op (ti, octave_value::op_mul,
+                          unary_op (octave_value::op_hermitian, v1), v2);
+
+      case octave_value::op_mul_herm:
+        return binary_op (ti, octave_value::op_mul,
+                          v1, unary_op (octave_value::op_hermitian, v2));
+
+      case octave_value::op_trans_ldiv:
+        return binary_op (ti, octave_value::op_ldiv,
+                          unary_op (octave_value::op_transpose, v1), v2);
+
+      case octave_value::op_herm_ldiv:
+        return binary_op (ti, octave_value::op_ldiv,
+                          unary_op (octave_value::op_hermitian, v1), v2);
+
+      case octave_value::op_el_not_and:
+        return binary_op (ti, octave_value::op_el_and,
+                          unary_op (octave_value::op_not, v1), v2);
+
+      case octave_value::op_el_not_or:
+        return binary_op (ti, octave_value::op_el_or,
+                          unary_op (octave_value::op_not, v1), v2);
+
+      case octave_value::op_el_and_not:
+        return binary_op (ti, octave_value::op_el_and,
+                          v1, unary_op (octave_value::op_not, v2));
+
+      case octave_value::op_el_or_not:
+        return binary_op (ti, octave_value::op_el_or,
+                          v1, unary_op (octave_value::op_not, v2));
+
+      default:
+        error ("invalid compound operator");
+      }
+  }
+
+  octave_value
+  binary_op (type_info& ti, octave_value::compound_binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    octave_value retval;
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    if (t1 == octave_class::static_type_id ()
+        || t2 == octave_class::static_type_id ()
+        || t1 == octave_classdef::static_type_id ()
+        || t2 == octave_classdef::static_type_id ())
+      {
+        type_info::binary_class_op_fcn f = ti.lookup_binary_class_op (op);
+
+        if (f)
+          retval = f (v1, v2);
+        else
+          retval = decompose_binary_op (ti, op, v1, v2);
+      }
+    else
+      {
+        type_info::binary_op_fcn f = ti.lookup_binary_op (op, t1, t2);
+
+        if (f)
+          retval = f (v1.get_rep (), v2.get_rep ());
+        else
+          retval = decompose_binary_op (ti, op, v1, v2);
+      }
+
+    return retval;
+  }
+
+  octave_value
+  binary_op (octave_value::compound_binary_op op,
+             const octave_value& v1, const octave_value& v2)
+  {
+    type_info& ti = __get_type_info__ ("binary_op");
+
+    return binary_op (ti, op, v1, v2);
+  }
+
+  OCTAVE_NORETURN static void
+  err_cat_op (const std::string& tn1, const std::string& tn2)
+  {
+    error ("concatenation operator not implemented for '%s' by '%s' operations",
+           tn1.c_str (), tn2.c_str ());
+  }
+
+  OCTAVE_NORETURN static void
+  err_cat_op_conv (void)
+  {
+    error ("type conversion failed for concatenation operator");
+  }
+
+  octave_value
+  cat_op (type_info& ti, const octave_value& v1,
+          const octave_value& v2, const Array<octave_idx_type>& ra_idx)
+  {
+    octave_value retval;
+
+    // Can't rapid return for concatenation with an empty object here as
+    // something like cat(1,[],single([]) must return the correct type.
+
+    int t1 = v1.type_id ();
+    int t2 = v2.type_id ();
+
+    type_info::cat_op_fcn f = ti.lookup_cat_op (t1, t2);
+
+    if (f)
+      retval = f (v1.get_rep (), v2.get_rep (), ra_idx);
+    else
+      {
+        octave_value tv1;
+        octave_base_value::type_conv_info cf1 = v1.numeric_conversion_function ();
+
+        octave_value tv2;
+        octave_base_value::type_conv_info cf2 = v2.numeric_conversion_function ();
+
+        // Try biased (one-sided) conversions first.
+        if (cf2.type_id () >= 0 && ti.lookup_cat_op (t1, cf2.type_id ()))
+          cf1 = nullptr;
+        else if (cf1.type_id () >= 0 && ti.lookup_cat_op (cf1.type_id (), t2))
+          cf2 = nullptr;
+
+        if (cf1)
+          {
+            octave_base_value *tmp = cf1 (v1.get_rep ());
+
+            if (! tmp)
+              err_cat_op_conv ();
+
+            tv1 = octave_value (tmp);
+            t1 = tv1.type_id ();
+          }
+        else
+          tv1 = v1;
+
+        if (cf2)
+          {
+            octave_base_value *tmp = cf2 (v2.get_rep ());
+
+            if (! tmp)
+              err_cat_op_conv ();
+
+            tv2 = octave_value (tmp);
+            t2 = tv2.type_id ();
+          }
+        else
+          tv2 = v2;
+
+        if (! cf1 && ! cf2)
+          err_cat_op (v1.type_name (), v2.type_name ());
+
+        retval = cat_op (ti, tv1, tv2, ra_idx);
+      }
+
+    return retval;
+  }
+
+  octave_value
+  cat_op (const octave_value& v1, const octave_value& v2,
+          const Array<octave_idx_type>& ra_idx)
+  {
+    type_info& ti = __get_type_info__ ("cat_op");
+
+    return cat_op (ti, v1, v2, ra_idx);
+  }
+
+  // Unless the colon operator is used with a class or classdef object,
+  // then all arguments must be the same type or mixed with double
+  // values.
+
+  static builtin_type_t
+  get_colon_op_type (builtin_type_t op1_type, builtin_type_t op2_type)
+  {
+    if (op1_type == op2_type)
+      return op1_type;
+
+    if (op1_type == btyp_double)
+      return op2_type;
+
+    if (op2_type == btyp_double)
+      return op1_type;
+
+    return btyp_unknown;
+  }
+
+  static builtin_type_t
+  get_colon_op_type (const octave_value& base, const octave_value& increment,
+                     const octave_value& limit)
+  {
+    builtin_type_t typ
+      = get_colon_op_type (base.builtin_type (), increment.builtin_type ());
+
+    if (typ == btyp_unknown)
+      return typ;
+
+    return get_colon_op_type (typ, limit.builtin_type ());
+  }
+
+  // Templated version used for various integer types (int8, uint16, ...)
+  template <typename T>
+  octave_value
+  make_range (const octave_value& base, const octave_value& increment,
+              const octave_value& limit, bool for_cmd_expr)
+  {
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      return octave_value (range<T> (), for_cmd_expr);
+
+    double dval;
+
+    T base_val = octave_value_extract<T> (base);
+    dval = base.double_value ();
+    if (base_val != dval)
+      error ("colon operator lower bound invalid (not an integer or out of range for given integer type)");
+
+    T increment_val = octave_value_extract<T> (increment);
+    dval = increment.double_value ();
+    if (increment_val != dval)
+      error ("colon operator increment invalid (not an integer or out of range for given integer type)");
+
+    T limit_val = octave_value_extract<T> (limit);
+    dval = limit.double_value ();
+    if (limit_val != dval)
+      error ("colon operator upper bound invalid (not an integer or out of range for given integer type)");
+
+    range<T> r (base_val, increment_val, limit_val);
+
+    return octave_value (r, for_cmd_expr);
+  }
+
+  template <>
+  octave_value
+  make_range<double> (const octave_value& base, const octave_value& increment,
+                      const octave_value& limit, bool for_cmd_expr)
+  {
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      return octave_value (range<double> (), for_cmd_expr);
+
+    double base_val = base.double_value ();
+    double increment_val = increment.double_value ();
+    double limit_val = limit.double_value ();
+
+    range<double> r (base_val, increment_val, limit_val);
+
+    return octave_value (r, for_cmd_expr);
+  }
+
+  template <>
+  octave_value
+  make_range<float> (const octave_value& base, const octave_value& increment,
+                     const octave_value& limit, bool for_cmd_expr)
+  {
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      return octave_value (range<float> (), for_cmd_expr);
+
+    float base_val = base.float_value ();
+    float increment_val = increment.float_value ();
+    float limit_val = limit.float_value ();
+
+    range<float> r (base_val, increment_val, limit_val);
+
+    return octave_value (r, for_cmd_expr);
+  }
+
+  template <>
+  octave_value
+  make_range<char> (const octave_value& base, const octave_value& increment,
+                    const octave_value& limit, bool for_cmd_expr)
+  {
+    octave_value retval;
+
+    bool dq_str = (base.is_dq_string () || increment.is_dq_string ()
+                   || limit.is_dq_string ());
+
+    char type = dq_str ? '"' : '\'';
+
+    if (base.isempty () || increment.isempty () || limit.isempty ())
+      retval = octave_value ("", type);
+    else
+      {
+        Matrix mtx_base = base.matrix_value (true);
+        Matrix mtx_increment = increment.matrix_value (true);
+        Matrix mtx_limit = limit.matrix_value (true);
+
+        range<double> tmp (mtx_base(0), mtx_increment(0), mtx_limit(0));
+
+        retval = octave_value (tmp, for_cmd_expr);
+      }
+
+    return retval.convert_to_str (false, true, type);
+  }
+
+  octave_value
+  colon_op (const octave_value& base, const octave_value& increment_arg,
+            const octave_value& limit, bool is_for_cmd_expr)
+  {
+    if (base.isobject () || increment_arg.isobject () || limit.isobject ())
+      {
+        octave_value_list tmp1;
+
+        if (increment_arg.is_defined ())
+          {
+            tmp1(2) = limit;
+            tmp1(1) = increment_arg;
+            tmp1(0) = base;
+          }
+        else
+          {
+            tmp1(1) = limit;
+            tmp1(0) = base;
+          }
+
+        interpreter& interp = __get_interpreter__ ("colon_op");
+
+        symbol_table& symtab = interp.get_symbol_table ();
+
+        octave_value fcn = symtab.find_function ("colon", tmp1);
+
+        if (fcn.is_defined ())
+          {
+            octave_value_list tmp2 = interp.feval (fcn, tmp1, 1);
+
+            return tmp2(0);
+          }
+      }
+
+    octave_value increment
+      = increment_arg.is_defined () ? increment_arg : octave_value (1.0);
+
+    if (base.numel () > 1 || limit.numel () > 1 || increment.numel () > 1)
+      warning_with_id ("Octave:colon-nonscalar-argument",
+                       "colon arguments should be scalars");
+
+    if (base.iscomplex () || limit.iscomplex () || increment.iscomplex ())
+      warning_with_id ("Octave:colon-complex-argument",
+                       "imaginary part of complex colon arguments is ignored");
+
+    // FIXME: is there a better way to do this job, maybe using type traits?
+
+    builtin_type_t type_id = get_colon_op_type (base, increment, limit);
+
+    // For compatibility with Matlab, don't allow the range used in
+    // a FOR loop expression to be converted to a Matrix.
+
+    switch (type_id)
+      {
+      case btyp_double:
+      case btyp_complex:
+        return make_range<double> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_float:
+      case btyp_float_complex:
+        return make_range<float> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int8:
+        return make_range<octave_int8> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int16:
+        return make_range<octave_int16> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int32:
+        return make_range<octave_int32> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_int64:
+        return make_range<octave_int64> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_uint8:
+        return make_range<octave_uint8> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_uint16:
+        return make_range<octave_uint16> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_uint32:
+        return make_range<octave_uint32> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_uint64:
+        return make_range<octave_uint64> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_char:
+        return make_range<char> (base, increment, limit, is_for_cmd_expr);
+
+      case btyp_unknown:
+        error ("incompatible types found in range expression");
+
+      default:
+        error ("invalid types found in range expression");
+      }
+
+    return octave_value ();
+  }
+
+  OCTAVE_NORETURN static void
+  err_unary_op_conv (const std::string& on)
+  {
+    error ("type conversion failed for unary operator '%s'", on.c_str ());
+  }
+
+  octave_value
+  unary_op (type_info& ti, octave_value::unary_op op,
+            const octave_value& v)
+  {
+    octave_value retval;
+
+    int t = v.type_id ();
+
+    if (t == octave_class::static_type_id ()
+        || t == octave_classdef::static_type_id ())
+      {
+        type_info::unary_class_op_fcn f = ti.lookup_unary_class_op (op);
+
+        if (! f)
+          err_unary_op (octave_value::unary_op_as_string (op), v.class_name ());
+
+        retval = f (v);
+      }
+    else
+      {
+        // FIXME: we need to handle overloading operators for built-in
+        // classes (double, char, int8, etc.)
+
+        type_info::unary_op_fcn f = ti.lookup_unary_op (op, t);
+
+        if (f)
+          retval = f (v.get_rep ());
+        else
+          {
+            octave_value tv;
+            octave_base_value::type_conv_fcn cf
+              = v.numeric_conversion_function ();
+
+            if (! cf)
+              err_unary_op (octave_value::unary_op_as_string (op),
+                            v.type_name ());
+
+            octave_base_value *tmp = cf (v.get_rep ());
+
+            if (! tmp)
+              err_unary_op_conv (octave_value::unary_op_as_string (op));
+
+            tv = octave_value (tmp);
+            retval = unary_op (op, tv);
+          }
+      }
+
+    return retval;
+  }
+
+  octave_value
+  unary_op (octave_value::unary_op op, const octave_value& v)
+  {
+    type_info& ti = __get_type_info__ ("unary_op");
+
+    return unary_op (ti, op, v);
+  }
+}
+
 void
 install_types (octave::type_info& ti)
 {
@@ -2948,7 +3264,16 @@
   octave_diag_matrix::register_type (ti);
   octave_complex_matrix::register_type (ti);
   octave_complex_diag_matrix::register_type (ti);
-  octave_range::register_type (ti);
+  ov_range<float>::register_type (ti);
+  ov_range<double>::register_type (ti);
+  ov_range<octave_int8>::register_type (ti);
+  ov_range<octave_int16>::register_type (ti);
+  ov_range<octave_int32>::register_type (ti);
+  ov_range<octave_int64>::register_type (ti);
+  ov_range<octave_uint8>::register_type (ti);
+  ov_range<octave_uint16>::register_type (ti);
+  ov_range<octave_uint32>::register_type (ti);
+  ov_range<octave_uint64>::register_type (ti);
   octave_bool::register_type (ti);
   octave_bool_matrix::register_type (ti);
   octave_char_matrix_str::register_type (ti);
@@ -2988,6 +3313,8 @@
   octave_float_complex_matrix::register_type (ti);
   octave_float_complex_diag_matrix::register_type (ti);
   octave_perm_matrix::register_type (ti);
+  octave_magic_int::register_type (ti);
+  octave_magic_uint::register_type (ti);
   octave_null_matrix::register_type (ti);
   octave_null_str::register_type (ti);
   octave_null_sq_str::register_type (ti);
--- a/libinterp/octave-value/ov.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave-value/ov.h	Sun May 16 09:44:35 2021 +0200
@@ -61,20 +61,11 @@
 class octave_fcn_handle;
 class octave_value_list;
 
+#include "mxtypes.h"
+
 #include "oct-stream.h"
 #include "ov-base.h"
 
-// Forward declarations of friend functions that have default arguments.
-
-OCTINTERP_API octave_value do_colon_op (const octave_value& base,
-                                        const octave_value& limit,
-                                        bool is_for_cmd_expr = false);
-
-OCTINTERP_API octave_value do_colon_op (const octave_value& base,
-                                        const octave_value& increment,
-                                        const octave_value& limit,
-                                        bool is_for_cmd_expr = false);
-
 class
 OCTINTERP_API
 octave_value
@@ -155,22 +146,23 @@
     unknown_assign_op
   };
 
-  static binary_op assign_op_to_binary_op (assign_op);
+  static OCTINTERP_API binary_op assign_op_to_binary_op (assign_op);
 
-  static assign_op binary_op_to_assign_op (binary_op);
+  static OCTINTERP_API assign_op binary_op_to_assign_op (binary_op);
 
-  static std::string unary_op_as_string (unary_op);
-  static std::string unary_op_fcn_name (unary_op);
+  static OCTINTERP_API std::string unary_op_as_string (unary_op);
+  static OCTINTERP_API std::string unary_op_fcn_name (unary_op);
 
-  static std::string binary_op_as_string (binary_op);
-  static std::string binary_op_fcn_name (binary_op);
+  static OCTINTERP_API std::string binary_op_as_string (binary_op);
+  static OCTINTERP_API std::string binary_op_fcn_name (binary_op);
 
-  static std::string binary_op_fcn_name (compound_binary_op);
+  static OCTINTERP_API std::string binary_op_fcn_name (compound_binary_op);
 
-  static std::string assign_op_as_string (assign_op);
+  static OCTINTERP_API std::string assign_op_as_string (assign_op);
 
-  static octave_value empty_conv (const std::string& type,
-                                  const octave_value& rhs = octave_value ());
+  static OCTINTERP_API octave_value
+  empty_conv (const std::string& type,
+              const octave_value& rhs = octave_value ());
 
   enum magic_colon { magic_colon_t };
 
@@ -180,12 +172,12 @@
     rep->count++;
   }
 
-  octave_value (short int i);
-  octave_value (unsigned short int i);
-  octave_value (int i);
-  octave_value (unsigned int i);
-  octave_value (long int i);
-  octave_value (unsigned long int i);
+  OCTINTERP_API octave_value (short int i);
+  OCTINTERP_API octave_value (unsigned short int i);
+  OCTINTERP_API octave_value (int i);
+  OCTINTERP_API octave_value (unsigned int i);
+  OCTINTERP_API octave_value (long int i);
+  OCTINTERP_API octave_value (unsigned long int i);
 
   // FIXME: These are kluges.  They turn into doubles internally, which will
   // break for very large values.  We just use them to store things like
@@ -193,114 +185,148 @@
   // than can be represented exactly in a double.
 
 #if defined (OCTAVE_HAVE_LONG_LONG_INT)
-  octave_value (long long int i);
+  OCTINTERP_API octave_value (long long int i);
 #endif
 #if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
-  octave_value (unsigned long long int i);
+  OCTINTERP_API octave_value (unsigned long long int i);
 #endif
 
-  octave_value (octave::sys::time t);
-  octave_value (double d);
-  octave_value (float d);
-  octave_value (const Array<octave_value>& a, bool is_cs_list = false);
-  octave_value (const Cell& c, bool is_cs_list = false);
-  octave_value (const Matrix& m, const MatrixType& t = MatrixType ());
-  octave_value (const FloatMatrix& m, const MatrixType& t = MatrixType ());
-  octave_value (const NDArray& nda);
-  octave_value (const FloatNDArray& nda);
-  octave_value (const Array<double>& m);
-  octave_value (const Array<float>& m);
-  octave_value (const DiagMatrix& d);
-  octave_value (const DiagArray2<double>& d);
-  octave_value (const DiagArray2<float>& d);
-  octave_value (const DiagArray2<Complex>& d);
-  octave_value (const DiagArray2<FloatComplex>& d);
-  octave_value (const FloatDiagMatrix& d);
-  octave_value (const RowVector& v);
-  octave_value (const FloatRowVector& v);
-  octave_value (const ColumnVector& v);
-  octave_value (const FloatColumnVector& v);
-  octave_value (const Complex& C);
-  octave_value (const FloatComplex& C);
-  octave_value (const ComplexMatrix& m, const MatrixType& t = MatrixType ());
-  octave_value (const FloatComplexMatrix& m,
-                const MatrixType& t = MatrixType ());
-  octave_value (const ComplexNDArray& cnda);
-  octave_value (const FloatComplexNDArray& cnda);
-  octave_value (const Array<Complex>& m);
-  octave_value (const Array<FloatComplex>& m);
-  octave_value (const ComplexDiagMatrix& d);
-  octave_value (const FloatComplexDiagMatrix& d);
-  octave_value (const ComplexRowVector& v);
-  octave_value (const FloatComplexRowVector& v);
-  octave_value (const ComplexColumnVector& v);
-  octave_value (const FloatComplexColumnVector& v);
-  octave_value (const PermMatrix& p);
-  octave_value (bool b);
-  octave_value (const boolMatrix& bm, const MatrixType& t = MatrixType ());
-  octave_value (const boolNDArray& bnda);
-  octave_value (const Array<bool>& bnda);
-  octave_value (char c, char type = '\'');
-  octave_value (const char *s, char type = '\'');
-  octave_value (const std::string& s, char type = '\'');
-  octave_value (const string_vector& s, char type = '\'');
-  octave_value (const charMatrix& chm,  char type = '\'');
-  octave_value (const charNDArray& chnda, char type = '\'');
-  octave_value (const Array<char>& chnda, char type = '\'');
+  OCTINTERP_API octave_value (octave::sys::time t);
+  OCTINTERP_API octave_value (double d);
+  OCTINTERP_API octave_value (float d);
+  OCTINTERP_API octave_value (const Array<octave_value>& a,
+                              bool is_cs_list = false);
+  OCTINTERP_API octave_value (const Cell& c, bool is_cs_list = false);
+  OCTINTERP_API octave_value (const Matrix& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const FloatMatrix& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const NDArray& nda);
+  OCTINTERP_API octave_value (const FloatNDArray& nda);
+  OCTINTERP_API octave_value (const Array<double>& m);
+  OCTINTERP_API octave_value (const Array<float>& m);
+  OCTINTERP_API octave_value (const DiagMatrix& d);
+  OCTINTERP_API octave_value (const DiagArray2<double>& d);
+  OCTINTERP_API octave_value (const DiagArray2<float>& d);
+  OCTINTERP_API octave_value (const DiagArray2<Complex>& d);
+  OCTINTERP_API octave_value (const DiagArray2<FloatComplex>& d);
+  OCTINTERP_API octave_value (const FloatDiagMatrix& d);
+  OCTINTERP_API octave_value (const RowVector& v);
+  OCTINTERP_API octave_value (const FloatRowVector& v);
+  OCTINTERP_API octave_value (const ColumnVector& v);
+  OCTINTERP_API octave_value (const FloatColumnVector& v);
+  OCTINTERP_API octave_value (const Complex& C);
+  OCTINTERP_API octave_value (const FloatComplex& C);
+  OCTINTERP_API octave_value (const ComplexMatrix& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const FloatComplexMatrix& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const ComplexNDArray& cnda);
+  OCTINTERP_API octave_value (const FloatComplexNDArray& cnda);
+  OCTINTERP_API octave_value (const Array<Complex>& m);
+  OCTINTERP_API octave_value (const Array<FloatComplex>& m);
+  OCTINTERP_API octave_value (const ComplexDiagMatrix& d);
+  OCTINTERP_API octave_value (const FloatComplexDiagMatrix& d);
+  OCTINTERP_API octave_value (const ComplexRowVector& v);
+  OCTINTERP_API octave_value (const FloatComplexRowVector& v);
+  OCTINTERP_API octave_value (const ComplexColumnVector& v);
+  OCTINTERP_API octave_value (const FloatComplexColumnVector& v);
+  OCTINTERP_API octave_value (const PermMatrix& p);
+  OCTINTERP_API octave_value (bool b);
+  OCTINTERP_API octave_value (const boolMatrix& bm,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const boolNDArray& bnda);
+  OCTINTERP_API octave_value (const Array<bool>& bnda);
+  OCTINTERP_API octave_value (char c, char type = '\'');
+  OCTINTERP_API octave_value (const char *s, char type = '\'');
+  OCTINTERP_API octave_value (const std::string& s, char type = '\'');
+  OCTINTERP_API octave_value (const string_vector& s, char type = '\'');
+  OCTINTERP_API octave_value (const charMatrix& chm,  char type = '\'');
+  OCTINTERP_API octave_value (const charNDArray& chnda, char type = '\'');
+  OCTINTERP_API octave_value (const Array<char>& chnda, char type = '\'');
 
-  octave_value (const SparseMatrix& m, const MatrixType& t = MatrixType ());
-  octave_value (const Sparse<double>& m, const MatrixType& t = MatrixType ());
-  octave_value (const SparseComplexMatrix& m,
-                const MatrixType& t = MatrixType ());
-  octave_value (const Sparse<Complex>& m, const MatrixType& t = MatrixType ());
-  octave_value (const SparseBoolMatrix& bm,
-                const MatrixType& t = MatrixType ());
-  octave_value (const Sparse<bool>& m, const MatrixType& t = MatrixType ());
-  octave_value (const octave_int8& i);
-  octave_value (const octave_int16& i);
-  octave_value (const octave_int32& i);
-  octave_value (const octave_int64& i);
-  octave_value (const octave_uint8& i);
-  octave_value (const octave_uint16& i);
-  octave_value (const octave_uint32& i);
-  octave_value (const octave_uint64& i);
-  octave_value (const int8NDArray& inda);
-  octave_value (const Array<octave_int8>& inda);
-  octave_value (const int16NDArray& inda);
-  octave_value (const Array<octave_int16>& inda);
-  octave_value (const int32NDArray& inda);
-  octave_value (const Array<octave_int32>& inda);
-  octave_value (const int64NDArray& inda);
-  octave_value (const Array<octave_int64>& inda);
-  octave_value (const uint8NDArray& inda);
-  octave_value (const Array<octave_uint8>& inda);
-  octave_value (const uint16NDArray& inda);
-  octave_value (const Array<octave_uint16>& inda);
-  octave_value (const uint32NDArray& inda);
-  octave_value (const Array<octave_uint32>& inda);
-  octave_value (const uint64NDArray& inda);
-  octave_value (const Array<octave_uint64>& inda);
-  octave_value (const Array<octave_idx_type>& inda,
-                bool zero_based = false, bool cache_index = false);
-  octave_value (const Array<std::string>& cellstr);
-  octave_value (const idx_vector& idx, bool lazy = true);
-  octave_value (double base, double limit, double inc);
-  octave_value (const Range& r, bool force_range = false);
-  octave_value (const octave_map& m);
-  octave_value (const octave_scalar_map& m);
-  octave_value (const std::map<std::string, octave_value>&);
-  octave_value (const octave_map& m, const std::string& id,
-                const std::list<std::string>& plist);
-  octave_value (const octave_scalar_map& m, const std::string& id,
-                const std::list<std::string>& plist);
+  OCTINTERP_API octave_value (const SparseMatrix& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const Sparse<double>& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const SparseComplexMatrix& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const Sparse<Complex>& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const SparseBoolMatrix& bm,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const Sparse<bool>& m,
+                              const MatrixType& t = MatrixType ());
+  OCTINTERP_API octave_value (const octave_int8& i);
+  OCTINTERP_API octave_value (const octave_int16& i);
+  OCTINTERP_API octave_value (const octave_int32& i);
+  OCTINTERP_API octave_value (const octave_int64& i);
+  OCTINTERP_API octave_value (const octave_uint8& i);
+  OCTINTERP_API octave_value (const octave_uint16& i);
+  OCTINTERP_API octave_value (const octave_uint32& i);
+  OCTINTERP_API octave_value (const octave_uint64& i);
+  OCTINTERP_API octave_value (const int8NDArray& inda);
+  OCTINTERP_API octave_value (const Array<octave_int8>& inda);
+  OCTINTERP_API octave_value (const int16NDArray& inda);
+  OCTINTERP_API octave_value (const Array<octave_int16>& inda);
+  OCTINTERP_API octave_value (const int32NDArray& inda);
+  OCTINTERP_API octave_value (const Array<octave_int32>& inda);
+  OCTINTERP_API octave_value (const int64NDArray& inda);
+  OCTINTERP_API octave_value (const Array<octave_int64>& inda);
+  OCTINTERP_API octave_value (const uint8NDArray& inda);
+  OCTINTERP_API octave_value (const Array<octave_uint8>& inda);
+  OCTINTERP_API octave_value (const uint16NDArray& inda);
+  OCTINTERP_API octave_value (const Array<octave_uint16>& inda);
+  OCTINTERP_API octave_value (const uint32NDArray& inda);
+  OCTINTERP_API octave_value (const Array<octave_uint32>& inda);
+  OCTINTERP_API octave_value (const uint64NDArray& inda);
+  OCTINTERP_API octave_value (const Array<octave_uint64>& inda);
+  OCTINTERP_API octave_value (const Array<octave_idx_type>& inda,
+                              bool zero_based = false,
+                              bool cache_index = false);
+  OCTINTERP_API octave_value (const Array<std::string>& cellstr);
+  OCTINTERP_API octave_value (const octave::idx_vector& idx, bool lazy = true);
+  OCTAVE_DEPRECATED (7, "use 'octave_value (range<double>&)' instead")
+  OCTINTERP_API octave_value (double base, double limit, double inc);
+  OCTAVE_DEPRECATED (7, "use 'octave_value (range<double>&)' instead")
+  OCTINTERP_API octave_value (const Range& r, bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<char>& r, char type,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<float>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<double>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<octave_int8>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<octave_int16>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<octave_int32>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<octave_int64>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<octave_uint8>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<octave_uint16>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<octave_uint32>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave::range<octave_uint64>& r,
+                              bool force_range = false);
+  OCTINTERP_API octave_value (const octave_map& m);
+  OCTINTERP_API octave_value (const octave_scalar_map& m);
+  OCTINTERP_API octave_value (const std::map<std::string, octave_value>&);
+  OCTINTERP_API octave_value (const octave_map& m, const std::string& id,
+                              const std::list<std::string>& plist);
+  OCTINTERP_API octave_value (const octave_scalar_map& m, const std::string& id,
+                              const std::list<std::string>& plist);
 
   // This one is explicit because it can cause some trouble to
   // accidentally create a cs-list when one was not intended.
-  explicit octave_value (const octave_value_list& m);
+  explicit OCTINTERP_API octave_value (const octave_value_list& m);
 
-  octave_value (octave_value::magic_colon);
+  OCTINTERP_API octave_value (octave_value::magic_colon);
 
-  octave_value (octave_base_value *new_rep, bool borrow = false);
+  OCTINTERP_API octave_value (octave_base_value *new_rep, bool borrow = false);
 
   // Copy constructor.
 
@@ -318,7 +344,7 @@
 
   // This should only be called for derived types.
 
-  octave_base_value * clone (void) const;
+  OCTINTERP_API octave_base_value * clone (void) const;
 
   octave_base_value * empty_clone (void) const
   { return rep->empty_clone (); }
@@ -412,7 +438,7 @@
   octave_base_value::type_conv_info numeric_demotion_function (void) const
   { return rep->numeric_demotion_function (); }
 
-  void maybe_mutate (void);
+  OCTINTERP_API void maybe_mutate (void);
 
   octave_value squeeze (void) const
   { return rep->squeeze (); }
@@ -451,8 +477,8 @@
   // FIXME: Do we really need all these different versions of subsref
   // and related functions?
 
-  octave_value single_subsref (const std::string& type,
-                               const octave_value_list& idx);
+  OCTINTERP_API octave_value
+  single_subsref (const std::string& type, const octave_value_list& idx);
 
   octave_value subsref (const std::string& type,
                         const std::list<octave_value_list>& idx)
@@ -463,42 +489,50 @@
                         bool auto_add)
   { return rep->subsref (type, idx, auto_add); }
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx,
-                             int nargout);
+  OCTINTERP_API octave_value_list
+  subsref (const std::string& type, const std::list<octave_value_list>& idx,
+           int nargout);
 
-  octave_value next_subsref (const std::string& type, const
-                             std::list<octave_value_list>& idx,
-                             std::size_t skip = 1);
+  OCTINTERP_API octave_value
+  next_subsref (const std::string& type,
+                const std::list<octave_value_list>& idx, std::size_t skip = 1);
 
-  octave_value_list next_subsref (int nargout,
-                                  const std::string& type, const
-                                  std::list<octave_value_list>& idx,
-                                  std::size_t skip = 1);
+  OCTINTERP_API octave_value_list
+  next_subsref (int nargout, const std::string& type,
+                const std::list<octave_value_list>& idx, std::size_t skip = 1);
 
-  octave_value next_subsref (bool auto_add, const std::string& type, const
-                             std::list<octave_value_list>& idx,
-                             std::size_t skip = 1);
+  OCTINTERP_API octave_value
+  next_subsref (bool auto_add, const std::string& type,
+                const std::list<octave_value_list>& idx, std::size_t skip = 1);
 
+  octave_value index_op (const octave_value_list& idx, bool resize_ok = false)
+  {
+    return rep->do_index_op (idx, resize_ok);
+  }
+
+  OCTAVE_DEPRECATED (7, "use 'octave_value::index_op' instead")
   octave_value do_index_op (const octave_value_list& idx,
                             bool resize_ok = false)
-  { return rep->do_index_op (idx, resize_ok); }
+  {
+    return index_op (idx, resize_ok);
+  }
 
-  octave_value subsasgn (const std::string& type,
-                         const std::list<octave_value_list>& idx,
-                         const octave_value& rhs);
+  OCTINTERP_API octave_value
+  subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
+            const octave_value& rhs);
 
-  octave_value undef_subsasgn (const std::string& type,
-                               const std::list<octave_value_list>& idx,
-                               const octave_value& rhs);
+  OCTINTERP_API octave_value
+  undef_subsasgn (const std::string& type,
+                  const std::list<octave_value_list>& idx,
+                  const octave_value& rhs);
 
-  octave_value& assign (assign_op op, const std::string& type,
-                        const std::list<octave_value_list>& idx,
-                        const octave_value& rhs);
+  OCTINTERP_API octave_value&
+  assign (assign_op op, const std::string& type,
+          const std::list<octave_value_list>& idx, const octave_value& rhs);
 
-  octave_value& assign (assign_op, const octave_value& rhs);
+  OCTINTERP_API octave_value& assign (assign_op, const octave_value& rhs);
 
-  idx_vector index_vector (bool require_integers = false) const
+  octave::idx_vector index_vector (bool require_integers = false) const
   {
     return rep->index_vector (require_integers);
   }
@@ -507,13 +541,13 @@
 
   dim_vector dims (void) const { return rep->dims (); }
 
-  std::string get_dims_str (void) const;
+  OCTINTERP_API std::string get_dims_str (void) const;
 
   octave_idx_type rows (void) const { return rep->rows (); }
 
   octave_idx_type columns (void) const { return rep->columns (); }
 
-  octave_idx_type length (void) const;
+  OCTINTERP_API octave_idx_type length (void) const;
 
   int ndims (void) const { return rep->ndims (); }
 
@@ -637,6 +671,9 @@
   bool is_magic_colon (void) const
   { return rep->is_magic_colon (); }
 
+  bool is_magic_int (void) const
+  { return rep->is_magic_int (); }
+
   bool isnull (void) const
   { return rep->isnull (); }
 
@@ -943,12 +980,39 @@
   Array<std::string> cellstr_value (void) const
   { return rep->cellstr_value (); }
 
-  Range range_value (void) const
+  octave::range<float> float_range_value (void) const
+  { return rep->float_range_value (); }
+
+  octave::range<double> range_value (void) const
   { return rep->range_value (); }
 
-  octave_map map_value (void) const;
+  octave::range<octave_int8> int8_range_value (void) const
+  { return rep->int8_range_value (); }
+
+  octave::range<octave_int16> int16_range_value (void) const
+  { return rep->int16_range_value (); }
+
+  octave::range<octave_int32> int32_range_value (void) const
+  { return rep->int32_range_value (); }
+
+  octave::range<octave_int64> int64_range_value (void) const
+  { return rep->int64_range_value (); }
 
-  octave_scalar_map scalar_map_value (void) const;
+  octave::range<octave_uint8> uint8_range_value (void) const
+  { return rep->uint8_range_value (); }
+
+  octave::range<octave_uint16> uint16_range_value (void) const
+  { return rep->uint16_range_value (); }
+
+  octave::range<octave_uint32> uint32_range_value (void) const
+  { return rep->uint32_range_value (); }
+
+  octave::range<octave_uint64> uint64_range_value (void) const
+  { return rep->uint64_range_value (); }
+
+  OCTINTERP_API octave_map map_value (void) const;
+
+  OCTINTERP_API octave_scalar_map scalar_map_value (void) const;
 
   string_vector map_keys (void) const
   { return rep->map_keys (); }
@@ -969,67 +1033,80 @@
   bool is_instance_of (const std::string& cls_name) const
   { return rep->is_instance_of (cls_name); }
 
-  octave_classdef * classdef_object_value (bool silent = false) const;
+  OCTINTERP_API octave_classdef *
+  classdef_object_value (bool silent = false) const;
 
-  octave_function * function_value (bool silent = false) const;
+  OCTINTERP_API octave_function *
+  function_value (bool silent = false) const;
 
-  octave_user_function * user_function_value (bool silent = false) const;
+  OCTINTERP_API octave_user_function *
+  user_function_value (bool silent = false) const;
 
-  octave_user_script * user_script_value (bool silent = false) const;
+  OCTINTERP_API octave_user_script *
+  user_script_value (bool silent = false) const;
 
-  octave_user_code * user_code_value (bool silent = false) const;
+  OCTINTERP_API octave_user_code * user_code_value (bool silent = false) const;
 
-  octave_fcn_handle * fcn_handle_value (bool silent = false) const;
+  OCTINTERP_API octave_fcn_handle *
+  fcn_handle_value (bool silent = false) const;
 
-  octave_value_list list_value (void) const;
+  OCTINTERP_API octave_value_list list_value (void) const;
 
-  ColumnVector column_vector_value (bool frc_str_conv = false,
-                                    bool frc_vec_conv = false) const;
+  OCTINTERP_API ColumnVector
+  column_vector_value (bool frc_str_conv = false,
+                       bool frc_vec_conv = false) const;
 
-  ComplexColumnVector
+  OCTINTERP_API ComplexColumnVector
   complex_column_vector_value (bool frc_str_conv = false,
                                bool frc_vec_conv = false) const;
 
-  RowVector row_vector_value (bool frc_str_conv = false,
-                              bool frc_vec_conv = false) const;
+  OCTINTERP_API RowVector
+  row_vector_value (bool frc_str_conv = false,
+                    bool frc_vec_conv = false) const;
 
-  ComplexRowVector
+  OCTINTERP_API ComplexRowVector
   complex_row_vector_value (bool frc_str_conv = false,
                             bool frc_vec_conv = false) const;
 
-  FloatColumnVector float_column_vector_value (bool frc_str_conv = false,
-                                               bool frc_vec_conv = false) const;
+  OCTINTERP_API FloatColumnVector
+  float_column_vector_value (bool frc_str_conv = false,
+                             bool frc_vec_conv = false) const;
 
-  FloatComplexColumnVector
+  OCTINTERP_API FloatComplexColumnVector
   float_complex_column_vector_value (bool frc_str_conv = false,
                                      bool frc_vec_conv = false) const;
 
-  FloatRowVector float_row_vector_value (bool frc_str_conv = false,
-                                         bool frc_vec_conv = false) const;
+  OCTINTERP_API FloatRowVector
+  float_row_vector_value (bool frc_str_conv = false,
+                          bool frc_vec_conv = false) const;
 
-  FloatComplexRowVector
+  OCTINTERP_API FloatComplexRowVector
   float_complex_row_vector_value (bool frc_str_conv = false,
                                   bool frc_vec_conv = false) const;
 
-  Array<int> int_vector_value (bool req_int = false,
-                               bool frc_str_conv = false,
-                               bool frc_vec_conv = false) const;
+  OCTINTERP_API Array<int>
+  int_vector_value (bool req_int = false,
+                    bool frc_str_conv = false,
+                    bool frc_vec_conv = false) const;
 
-  Array<octave_idx_type>
+  OCTINTERP_API Array<octave_idx_type>
   octave_idx_type_vector_value (bool req_int = false,
                                 bool frc_str_conv = false,
                                 bool frc_vec_conv = false) const;
 
-  Array<double> vector_value (bool frc_str_conv = false,
-                              bool frc_vec_conv = false) const;
+  OCTINTERP_API Array<double>
+  vector_value (bool frc_str_conv = false,
+                bool frc_vec_conv = false) const;
 
-  Array<Complex> complex_vector_value (bool frc_str_conv = false,
-                                       bool frc_vec_conv = false) const;
+  OCTINTERP_API Array<Complex>
+  complex_vector_value (bool frc_str_conv = false,
+                        bool frc_vec_conv = false) const;
 
-  Array<float> float_vector_value (bool frc_str_conv = false,
-                                   bool frc_vec_conv = false) const;
+  OCTINTERP_API Array<float>
+  float_vector_value (bool frc_str_conv = false,
+                      bool frc_vec_conv = false) const;
 
-  Array<FloatComplex>
+  OCTINTERP_API Array<FloatComplex>
   float_complex_vector_value (bool frc_str_conv = false,
                               bool frc_vec_conv = false) const;
 
@@ -1041,165 +1118,216 @@
   // specific types and display error messages that are more meaningful than
   // the generic "error: wrong type argument 'cell'" message.
 
-  short int xshort_value (const char *fmt, ...) const;
+  OCTINTERP_API short int xshort_value (const char *fmt, ...) const;
+
+  OCTINTERP_API unsigned short int xushort_value (const char *fmt, ...) const;
 
-  unsigned short int xushort_value (const char *fmt, ...) const;
+  OCTINTERP_API int xint_value (const char *fmt, ...) const;
 
-  int xint_value (const char *fmt, ...) const;
+  OCTINTERP_API unsigned int xuint_value (const char *fmt, ...) const;
+
+  OCTINTERP_API int xnint_value (const char *fmt, ...) const;
 
-  unsigned int xuint_value (const char *fmt, ...) const;
+  OCTINTERP_API long int xlong_value (const char *fmt, ...) const;
 
-  int xnint_value (const char *fmt, ...) const;
+  OCTINTERP_API unsigned long int xulong_value (const char *fmt, ...) const;
 
-  long int xlong_value (const char *fmt, ...) const;
+  OCTINTERP_API int64_t xint64_value (const char *fmt, ...) const;
 
-  unsigned long int xulong_value (const char *fmt, ...) const;
+  OCTINTERP_API uint64_t xuint64_value (const char *fmt, ...) const;
+
+  OCTINTERP_API octave_idx_type xidx_type_value (const char *fmt, ...) const;
 
-  int64_t xint64_value (const char *fmt, ...) const;
+  OCTINTERP_API double xdouble_value (const char *fmt, ...) const;
 
-  uint64_t xuint64_value (const char *fmt, ...) const;
+  OCTINTERP_API float xfloat_value (const char *fmt, ...) const;
 
-  octave_idx_type xidx_type_value (const char *fmt, ...) const;
+  OCTINTERP_API double xscalar_value (const char *fmt, ...) const;
 
-  double xdouble_value (const char *fmt, ...) const;
+  OCTINTERP_API float xfloat_scalar_value (const char *fmt, ...) const;
+
+  OCTINTERP_API Matrix xmatrix_value (const char *fmt, ...) const;
 
-  float xfloat_value (const char *fmt, ...) const;
+  OCTINTERP_API FloatMatrix xfloat_matrix_value (const char *fmt, ...) const;
 
-  double xscalar_value (const char *fmt, ...) const;
+  OCTINTERP_API NDArray xarray_value (const char *fmt, ...) const;
 
-  float xfloat_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API FloatNDArray xfloat_array_value (const char *fmt, ...) const;
 
-  Matrix xmatrix_value (const char *fmt, ...) const;
+  OCTINTERP_API Complex xcomplex_value (const char *fmt, ...) const;
+
+  OCTINTERP_API FloatComplex xfloat_complex_value (const char *fmt, ...) const;
 
-  FloatMatrix xfloat_matrix_value (const char *fmt, ...) const;
-
-  NDArray xarray_value (const char *fmt, ...) const;
+  OCTINTERP_API ComplexMatrix
+  xcomplex_matrix_value (const char *fmt, ...) const;
 
-  FloatNDArray xfloat_array_value (const char *fmt, ...) const;
+  OCTINTERP_API FloatComplexMatrix
+  xfloat_complex_matrix_value (const char *fmt, ...) const;
 
-  Complex xcomplex_value (const char *fmt, ...) const;
+  OCTINTERP_API ComplexNDArray
+  xcomplex_array_value (const char *fmt, ...) const;
 
-  FloatComplex xfloat_complex_value (const char *fmt, ...) const;
+  OCTINTERP_API FloatComplexNDArray
+  xfloat_complex_array_value (const char *fmt, ...) const;
 
-  ComplexMatrix xcomplex_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API bool xbool_value (const char *fmt, ...) const;
 
-  FloatComplexMatrix xfloat_complex_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API boolMatrix xbool_matrix_value (const char *fmt, ...) const;
 
-  ComplexNDArray xcomplex_array_value (const char *fmt, ...) const;
+  OCTINTERP_API boolNDArray xbool_array_value (const char *fmt, ...) const;
+
+  OCTINTERP_API charMatrix xchar_matrix_value (const char *fmt, ...) const;
 
-  FloatComplexNDArray xfloat_complex_array_value (const char *fmt, ...) const;
+  OCTINTERP_API charNDArray xchar_array_value (const char *fmt, ...) const;
 
-  bool xbool_value (const char *fmt, ...) const;
+  OCTINTERP_API SparseMatrix xsparse_matrix_value (const char *fmt, ...) const;
 
-  boolMatrix xbool_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API SparseComplexMatrix
+  xsparse_complex_matrix_value (const char *fmt, ...) const;
 
-  boolNDArray xbool_array_value (const char *fmt, ...) const;
+  OCTINTERP_API SparseBoolMatrix
+  xsparse_bool_matrix_value (const char *fmt, ...) const;
 
-  charMatrix xchar_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API DiagMatrix xdiag_matrix_value (const char *fmt, ...) const;
 
-  charNDArray xchar_array_value (const char *fmt, ...) const;
+  OCTINTERP_API FloatDiagMatrix
+  xfloat_diag_matrix_value (const char *fmt, ...) const;
 
-  SparseMatrix xsparse_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API ComplexDiagMatrix
+  xcomplex_diag_matrix_value (const char *fmt, ...) const;
 
-  SparseComplexMatrix xsparse_complex_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API FloatComplexDiagMatrix
+  xfloat_complex_diag_matrix_value (const char *fmt, ...) const;
 
-  SparseBoolMatrix xsparse_bool_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API PermMatrix xperm_matrix_value (const char *fmt, ...) const;
+
+  OCTINTERP_API octave_int8 xint8_scalar_value (const char *fmt, ...) const;
 
-  DiagMatrix xdiag_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_int16 xint16_scalar_value (const char *fmt, ...) const;
 
-  FloatDiagMatrix xfloat_diag_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_int32 xint32_scalar_value (const char *fmt, ...) const;
+
+  OCTINTERP_API octave_int64 xint64_scalar_value (const char *fmt, ...) const;
 
-  ComplexDiagMatrix xcomplex_diag_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_uint8 xuint8_scalar_value (const char *fmt, ...) const;
 
-  FloatComplexDiagMatrix xfloat_complex_diag_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_uint16 xuint16_scalar_value (const char *fmt, ...) const;
 
-  PermMatrix xperm_matrix_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_uint32 xuint32_scalar_value (const char *fmt, ...) const;
 
-  octave_int8 xint8_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_uint64 xuint64_scalar_value (const char *fmt, ...) const;
+
+  OCTINTERP_API int8NDArray xint8_array_value (const char *fmt, ...) const;
 
-  octave_int16 xint16_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API int16NDArray xint16_array_value (const char *fmt, ...) const;
 
-  octave_int32 xint32_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API int32NDArray xint32_array_value (const char *fmt, ...) const;
 
-  octave_int64 xint64_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API int64NDArray xint64_array_value (const char *fmt, ...) const;
 
-  octave_uint8 xuint8_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API uint8NDArray xuint8_array_value (const char *fmt, ...) const;
+
+  OCTINTERP_API uint16NDArray xuint16_array_value (const char *fmt, ...) const;
 
-  octave_uint16 xuint16_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API uint32NDArray xuint32_array_value (const char *fmt, ...) const;
 
-  octave_uint32 xuint32_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API uint64NDArray xuint64_array_value (const char *fmt, ...) const;
 
-  octave_uint64 xuint64_scalar_value (const char *fmt, ...) const;
+  OCTINTERP_API std::string xstring_value (const char *fmt, ...) const;
 
-  int8NDArray xint8_array_value (const char *fmt, ...) const;
+  OCTINTERP_API string_vector xstring_vector_value (const char *fmt, ...) const;
+
+  OCTINTERP_API Cell xcell_value (const char *fmt, ...) const;
 
-  int16NDArray xint16_array_value (const char *fmt, ...) const;
-
-  int32NDArray xint32_array_value (const char *fmt, ...) const;
+  OCTINTERP_API Array<std::string> xcellstr_value (const char *fmt, ...) const;
 
-  int64NDArray xint64_array_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<float>
+  xfloat_range_value (const char *fmt, ...) const;
 
-  uint8NDArray xuint8_array_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<double>
+  xrange_value (const char *fmt, ...) const;
 
-  uint16NDArray xuint16_array_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<octave_int8>
+  xint8_range_value (const char *fmt, ...) const;
 
-  uint32NDArray xuint32_array_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<octave_int16>
+  xint16_range_value (const char *fmt, ...) const;
 
-  uint64NDArray xuint64_array_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<octave_int32>
+  xint32_range_value (const char *fmt, ...) const;
 
-  std::string xstring_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<octave_int64>
+  xint64_range_value (const char *fmt, ...) const;
 
-  string_vector xstring_vector_value (const char *fmt, ...) const;
-
-  Cell xcell_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<octave_uint8>
+  xuint8_range_value (const char *fmt, ...) const;
 
-  Array<std::string> xcellstr_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<octave_uint16>
+  xuint16_range_value (const char *fmt, ...) const;
 
-  Range xrange_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<octave_uint32>
+  xuint32_range_value (const char *fmt, ...) const;
 
-  octave_map xmap_value (const char *fmt, ...) const;
+  OCTINTERP_API octave::range<octave_uint64>
+  xuint64_range_value (const char *fmt, ...) const;
 
-  octave_scalar_map xscalar_map_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_map xmap_value (const char *fmt, ...) const;
 
-  ColumnVector xcolumn_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_scalar_map
+  xscalar_map_value (const char *fmt, ...) const;
 
-  ComplexColumnVector
+  OCTINTERP_API ColumnVector xcolumn_vector_value (const char *fmt, ...) const;
+
+  OCTINTERP_API ComplexColumnVector
   xcomplex_column_vector_value (const char *fmt, ...) const;
 
-  RowVector xrow_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API RowVector xrow_vector_value (const char *fmt, ...) const;
 
-  ComplexRowVector xcomplex_row_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API ComplexRowVector
+  xcomplex_row_vector_value (const char *fmt, ...) const;
 
-  FloatColumnVector xfloat_column_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API FloatColumnVector
+  xfloat_column_vector_value (const char *fmt, ...) const;
 
-  FloatComplexColumnVector
+  OCTINTERP_API FloatComplexColumnVector
   xfloat_complex_column_vector_value (const char *fmt, ...) const;
 
-  FloatRowVector xfloat_row_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API FloatRowVector
+  xfloat_row_vector_value (const char *fmt, ...) const;
 
-  FloatComplexRowVector
+  OCTINTERP_API FloatComplexRowVector
   xfloat_complex_row_vector_value (const char *fmt, ...) const;
 
-  Array<int> xint_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API Array<int> xint_vector_value (const char *fmt, ...) const;
 
-  Array<octave_idx_type>
+  OCTINTERP_API Array<octave_idx_type>
   xoctave_idx_type_vector_value (const char *fmt, ...) const;
 
-  Array<double> xvector_value (const char *fmt, ...) const;
+  OCTINTERP_API Array<double> xvector_value (const char *fmt, ...) const;
 
-  Array<Complex> xcomplex_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API Array<Complex>
+  xcomplex_vector_value (const char *fmt, ...) const;
 
-  Array<float> xfloat_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API Array<float> xfloat_vector_value (const char *fmt, ...) const;
 
-  Array<FloatComplex> xfloat_complex_vector_value (const char *fmt, ...) const;
+  OCTINTERP_API Array<FloatComplex>
+  xfloat_complex_vector_value (const char *fmt, ...) const;
+
+  OCTINTERP_API octave_function * xfunction_value (const char *fmt, ...) const;
 
-  octave_function * xfunction_value (const char *fmt, ...) const;
-  octave_user_function * xuser_function_value (const char *fmt, ...) const;
-  octave_user_script * xuser_script_value (const char *fmt, ...) const;
-  octave_user_code * xuser_code_value (const char *fmt, ...) const;
-  octave_fcn_handle * xfcn_handle_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_user_function *
+  xuser_function_value (const char *fmt, ...) const;
+
+  OCTINTERP_API octave_user_script *
+  xuser_script_value (const char *fmt, ...) const;
 
-  octave_value_list xlist_value (const char *fmt, ...) const;
+  OCTINTERP_API octave_user_code *
+  xuser_code_value (const char *fmt, ...) const;
+
+  OCTINTERP_API octave_fcn_handle *
+  xfcn_handle_value (const char *fmt, ...) const;
+
+  OCTINTERP_API octave_value_list xlist_value (const char *fmt, ...) const;
 
   // Possibly economize a lazy-indexed value.
 
@@ -1210,12 +1338,12 @@
   // storing it to a "permanent" location, like a named variable, a cell or a
   // struct component, or a return value of a function.
 
-  octave_value storable_value (void) const;
+  OCTINTERP_API octave_value storable_value (void) const;
 
   // Ditto, but in place, i.e., equivalent to *this = this->storable_value (),
   // but possibly more efficient.
 
-  void make_storable_value (void);
+  OCTINTERP_API void make_storable_value (void);
 
   // FIXME: These should probably be private.
   // Conversions.  If a user of this class wants a certain kind of constant,
@@ -1249,7 +1377,7 @@
 
   void short_disp (std::ostream& os) const { rep->short_disp (os); }
 
-  float_display_format get_edit_display_format (void) const;
+  OCTINTERP_API float_display_format get_edit_display_format (void) const;
 
   std::string edit_display (const float_display_format& fmt,
                             octave_idx_type i, octave_idx_type j) const
@@ -1263,46 +1391,35 @@
 
   std::string class_name (void) const { return rep->class_name (); }
 
-  // Unary and binary operations.
-
-  friend OCTINTERP_API octave_value
-  do_unary_op (octave::type_info& ti, unary_op op, const octave_value& a);
-
-  octave_value& do_non_const_unary_op (unary_op op);
-
-  octave_value& do_non_const_unary_op (unary_op op, const std::string& type,
-                                       const std::list<octave_value_list>& idx);
-
-  friend OCTINTERP_API octave_value
-  do_binary_op (octave::type_info& ti, binary_op op,
-                const octave_value& a, const octave_value& b);
+  // Unary operations that are member functions.  There are also some
+  // non-member functions for unary and binary operations declared
+  // below, outside of the octave_value class declaration.
 
-  friend OCTINTERP_API octave_value
-  do_binary_op (octave::type_info& ti, compound_binary_op op,
-                const octave_value& a, const octave_value& b);
+  OCTINTERP_API octave_value& non_const_unary_op (unary_op op);
 
-  friend OCTINTERP_API octave_value
-  do_cat_op (octave::type_info& ti, const octave_value& a,
-             const octave_value& b, const Array<octave_idx_type>& ra_idx);
-
-  friend OCTINTERP_API octave_value do_colon_op (const octave_value& base,
-                                                 const octave_value& limit,
-                                                 bool is_for_cmd_expr)
+  OCTAVE_DEPRECATED (7, "use 'octave_value::non_const_unary_op' instead")
+  octave_value& do_non_const_unary_op (unary_op op)
   {
-    return do_colon_op (base, octave_value (), limit, is_for_cmd_expr);
+    return non_const_unary_op (op);
   }
 
-  friend OCTINTERP_API octave_value do_colon_op (const octave_value& base,
-                                                 const octave_value& increment,
-                                                 const octave_value& limit,
-                                                 bool is_for_cmd_expr);
+  OCTINTERP_API octave_value&
+  non_const_unary_op (unary_op op, const std::string& type,
+                      const std::list<octave_value_list>& idx);
+
+  OCTAVE_DEPRECATED (7, "use 'octave_value::non_const_unary_op' instead")
+  octave_value& do_non_const_unary_op (unary_op op, const std::string& type,
+                                       const std::list<octave_value_list>& idx)
+  {
+    return non_const_unary_op (op, type, idx);
+  }
 
   const octave_base_value& get_rep (void) const { return *rep; }
 
   bool is_copy_of (const octave_value& val) const { return rep == val.rep; }
 
-  void print_info (std::ostream& os,
-                   const std::string& prefix = "") const;
+  OCTINTERP_API void
+  print_info (std::ostream& os, const std::string& prefix = "") const;
 
   bool save_ascii (std::ostream& os) { return rep->save_ascii (os); }
 
@@ -1322,21 +1439,25 @@
   bool load_hdf5 (octave_hdf5_id loc_id, const char *name)
   { return rep->load_hdf5 (loc_id, name); }
 
-  int write (octave::stream& os, int block_size,
-             oct_data_conv::data_type output_type, int skip,
-             octave::mach_info::float_format flt_fmt) const;
+  OCTINTERP_API int
+  write (octave::stream& os, int block_size,
+         oct_data_conv::data_type output_type, int skip,
+         octave::mach_info::float_format flt_fmt) const;
 
   octave_base_value * internal_rep (void) const { return rep; }
 
   // 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 (); }
+  OCTINTERP_API 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); }
@@ -1477,57 +1598,155 @@
 
 private:
 
-  static octave_base_value *nil_rep (void);
+  static OCTINTERP_API octave_base_value *nil_rep (void);
 
-  assign_op unary_op_to_assign_op (unary_op op);
+  OCTINTERP_API assign_op unary_op_to_assign_op (unary_op op);
 
-  binary_op op_eq_to_binary_op (assign_op op);
+  OCTINTERP_API binary_op op_eq_to_binary_op (assign_op op);
 
   // This declaration protects against constructing octave_value from
   // const octave_base_value* which actually silently calls octave_value (bool).
-  octave_value (const octave_base_value *);
+  OCTINTERP_API octave_value (const octave_base_value *);
 
 };
 
-// Publish externally used friend functions.  Which compiler requires
-// these extra declarations?
+// Non-member unary and binary operations on octave_value objects.
+
+namespace octave
+{
+  extern OCTINTERP_API octave_value
+  unary_op (type_info& ti, octave_value::unary_op op,
+            const octave_value& a);
+
+  extern OCTINTERP_API octave_value
+  unary_op (octave_value::unary_op op, const octave_value& a);
+
+  extern OCTINTERP_API octave_value
+  binary_op (type_info& ti, octave_value::binary_op op,
+             const octave_value& a, const octave_value& b);
+
+  extern OCTINTERP_API octave_value
+  binary_op (type_info& ti, octave_value::compound_binary_op op,
+             const octave_value& a, const octave_value& b);
 
-extern OCTINTERP_API octave_value
-do_unary_op (octave::type_info& ti, octave_value::unary_op op,
-             const octave_value& a);
+  extern OCTINTERP_API octave_value
+  binary_op (octave_value::binary_op op, const octave_value& a,
+             const octave_value& b);
+
+  extern OCTINTERP_API octave_value
+  binary_op (octave_value::compound_binary_op op, const octave_value& a,
+             const octave_value& b);
 
-extern OCTINTERP_API octave_value
-do_unary_op (octave_value::unary_op op, const octave_value& a);
+  extern OCTINTERP_API octave_value
+  cat_op (type_info& ti, const octave_value& a,
+          const octave_value& b, const Array<octave_idx_type>& ra_idx);
+
+  extern OCTINTERP_API octave_value
+  cat_op (const octave_value& a, const octave_value& b,
+          const Array<octave_idx_type>& ra_idx);
+
+  extern OCTINTERP_API octave_value
+  colon_op (const octave_value& base, const octave_value& increment,
+            const octave_value& limit, bool is_for_cmd_expr = false);
 
-extern OCTINTERP_API octave_value
-do_binary_op (octave::type_info& ti, octave_value::binary_op op,
-              const octave_value& a, const octave_value& b);
+  inline octave_value
+  colon_op (const octave_value& base, const octave_value& limit,
+            bool is_for_cmd_expr = false)
+  {
+    // Note, we need to pass an undefined octave_value object instead of
+    // octave_value (1.0) so that we can properly detect the
+    // two-argument case and correctly pass just two arguments to any
+    // user-defined function that is provided if either base or limit is
+    // an object.
+
+    return colon_op (base, octave_value (), limit, is_for_cmd_expr);
+  }
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::unary_op' instead")
+inline octave_value
+do_unary_op (octave::type_info& ti, octave_value::unary_op op,
+             const octave_value& a)
+{
+  return octave::unary_op (ti, op, a);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::unary_op' instead")
+inline octave_value
+do_unary_op (octave_value::unary_op op, const octave_value& a)
+{
+  return octave::unary_op (op, a);
+
+}
+OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
+inline octave_value
+do_binary_op (octave::type_info& ti, octave_value::binary_op op,
+              const octave_value& a, const octave_value& b)
+{
+  return octave::binary_op (ti, op, a, b);
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
+inline octave_value
 do_binary_op (octave::type_info& ti, octave_value::compound_binary_op op,
-              const octave_value& a, const octave_value& b);
+              const octave_value& a, const octave_value& b)
+{
+  return octave::binary_op (ti, op, a, b);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
+inline octave_value
 do_binary_op (octave_value::binary_op op, const octave_value& a,
-              const octave_value& b);
+              const octave_value& b)
+{
+  return octave::binary_op (op, a, b);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::binary_op' instead")
+inline octave_value
 do_binary_op (octave_value::compound_binary_op op, const octave_value& a,
-              const octave_value& b);
+              const octave_value& b)
+{
+  return octave::binary_op (op, a, b);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::cat_op' instead")
+inline octave_value
 do_cat_op (octave::type_info& ti, const octave_value& a,
-           const octave_value& b, const Array<octave_idx_type>& ra_idx);
+           const octave_value& b, const Array<octave_idx_type>& ra_idx)
+{
+  return octave::cat_op (ti, a, b, ra_idx);
+}
 
-extern OCTINTERP_API octave_value
+OCTAVE_DEPRECATED (7, "use 'octave::cat_op' instead")
+inline octave_value
 do_cat_op (const octave_value& a, const octave_value& b,
-           const Array<octave_idx_type>& ra_idx);
+           const Array<octave_idx_type>& ra_idx)
+{
+  return octave::cat_op (a, b, ra_idx);
+}
 
-#define OV_UNOP_FN(name)                        \
-  inline octave_value                           \
-  name (const octave_value& a)                  \
-  {                                             \
-    return do_unary_op (octave_value::name, a); \
+OCTAVE_DEPRECATED (7, "use 'octave::colon_op' instead")
+inline octave_value
+do_colon_op (const octave_value& base, const octave_value& increment,
+             const octave_value& limit, bool is_for_cmd_expr = false)
+{
+  return octave::colon_op (base, increment, limit, is_for_cmd_expr);
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::colon_op' instead")
+inline octave_value
+do_colon_op (const octave_value& base, const octave_value& limit,
+             bool is_for_cmd_expr = false)
+{
+  return octave::colon_op (base, limit, is_for_cmd_expr);
+}
+
+#define OV_UNOP_FN(name)                                \
+  inline octave_value                                   \
+  name (const octave_value& a)                          \
+  {                                                     \
+    return octave::unary_op (octave_value::name, a);    \
   }
 
 #define OV_UNOP_OP(name, op)                    \
@@ -1553,11 +1772,11 @@
 //   incr
 //   decr
 
-#define OV_BINOP_FN(name)                               \
-  inline octave_value                                   \
-  name (const octave_value& a1, const octave_value& a2) \
-  {                                                     \
-    return do_binary_op (octave_value::name, a1, a2);   \
+#define OV_BINOP_FN(name)                                       \
+  inline octave_value                                           \
+  name (const octave_value& a1, const octave_value& a2)         \
+  {                                                             \
+    return octave::binary_op (octave_value::name, a1, a2);      \
   }
 
 #define OV_BINOP_OP(name, op)                                   \
@@ -1595,11 +1814,11 @@
 
 OV_BINOP_FN (op_struct_ref)
 
-#define OV_COMP_BINOP_FN(name)                          \
-  inline octave_value                                   \
-  name (const octave_value& a1, const octave_value& a2) \
-  {                                                     \
-    return do_binary_op (octave_value::name, a1, a2);   \
+#define OV_COMP_BINOP_FN(name)                                  \
+  inline octave_value                                           \
+  name (const octave_value& a1, const octave_value& a2)         \
+  {                                                             \
+    return octave::binary_op (octave_value::name, a1, a2);      \
   }
 
 OV_COMP_BINOP_FN (op_trans_mul)
--- a/libinterp/octave.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave.cc	Sun May 16 09:44:35 2021 +0200
@@ -157,6 +157,10 @@
               m_exec_path = octave_optarg_wrapper ();
             break;
 
+          case EXPERIMENTAL_TERMINAL_WIDGET_OPTION:
+            m_experimental_terminal_widget = true;
+            break;
+
           case GUI_OPTION:
             m_gui = true;
             break;
@@ -212,6 +216,10 @@
             m_persist = true;
             break;
 
+          case SERVER_OPTION:
+            m_server = true;
+            break;
+
           case TEXI_MACROS_FILE_OPTION:
             if (octave_optarg_wrapper ())
               m_texi_macros_file = octave_optarg_wrapper ();
@@ -236,6 +244,44 @@
                                       argc-octave_optind_wrapper ());
   }
 
+  octave_value cmdline_options::as_octave_value (void) const
+  {
+    octave_scalar_map m;
+
+    m.assign ("sys_argc", sys_argc ());
+    m.assign ("sys_argv", string_vector (sys_argv ()));
+    m.assign ("debug_jit", debug_jit ());
+    m.assign ("echo_commands", echo_commands ());
+    m.assign ("forced_interactive", forced_interactive ());
+    m.assign ("forced_line_editing", forced_line_editing ());
+    m.assign ("gui", gui ());
+    m.assign ("inhibit_startup_message", inhibit_startup_message ());
+    m.assign ("jit_compiler", jit_compiler ());
+    m.assign ("line_editing", line_editing ());
+    m.assign ("no_window_system", no_window_system ());
+    m.assign ("persist", persist ());
+    m.assign ("read_history_file", read_history_file ());
+    m.assign ("read_init_files", read_init_files ());
+    m.assign ("read_site_files", read_site_files ());
+    m.assign ("server", server ());
+    m.assign ("set_initial_path", set_initial_path ());
+    m.assign ("traditional", traditional ());
+    m.assign ("verbose_flag", verbose_flag ());
+    m.assign ("code_to_eval", code_to_eval ());
+    m.assign ("command_line_path", string_vector (command_line_path ()));
+    m.assign ("docstrings_file", docstrings_file ());
+    m.assign ("doc_cache_file", doc_cache_file ());
+    m.assign ("exec_path", exec_path ());
+    m.assign ("image_path", image_path ());
+    m.assign ("info_file", info_file ());
+    m.assign ("info_program", info_program ());
+    m.assign ("texi_macros_file", texi_macros_file ());
+    m.assign ("all_args", all_args ());
+    m.assign ("remaining_args", remaining_args ());
+
+    return m;
+  }
+
   application *application::instance = nullptr;
 
   application::application (int argc, char **argv)
@@ -250,6 +296,14 @@
     init ();
   }
 
+  // Note: Although the application destructor doesn't explicitly
+  // perform any actions, it can't be declared "default" in the header
+  // file if the octave::interpreter is an incomplete type.  Providing
+  // an explicit definition of the destructor here is much simpler than
+  // including the full declaration of octave::interpreter in the
+  // octave.h header file.
+  application::~application (void) { }
+
   void
   application::set_program_names (const std::string& pname)
   {
@@ -282,13 +336,12 @@
     return instance ? instance->m_options.forced_interactive () : false;
   }
 
-  application::~application (void)
+  // Provided for convenience.  Will be removed once we eliminate the
+  // old terminal widget.
+  bool application::experimental_terminal_widget (void) const
   {
-    // Delete interpreter if it still exists.
-
-    delete m_interpreter;
-
-    instance = nullptr;
+    return (instance
+            ? instance->m_options.experimental_terminal_widget () : false);
   }
 
   bool application::interpreter_initialized (void)
@@ -299,7 +352,7 @@
   interpreter& application::create_interpreter (void)
   {
     if (! m_interpreter)
-      m_interpreter = new interpreter (this);
+      m_interpreter = std::unique_ptr<interpreter> (new interpreter (this));
 
     return *m_interpreter;
   }
@@ -317,9 +370,7 @@
 
   void application::delete_interpreter (void)
   {
-    delete m_interpreter;
-
-    m_interpreter = nullptr;
+    m_interpreter.reset ();
   }
 
   void application::init (void)
@@ -361,9 +412,13 @@
             std::cerr << "error: --gui and --no-line-editing are mutually exclusive options" << std::endl;
             octave_print_terse_usage_and_exit ();
           }
+        if (m_options.server ())
+          {
+            std::cerr << "error: --gui and --server are mutually exclusive options" << std::endl;
+            octave_print_terse_usage_and_exit ();
+          }
       }
 
-
     m_is_octave_program = ((m_have_script_file || m_have_eval_option_code)
                            && ! m_options.persist ()
                            && ! m_options.traditional ());
@@ -434,6 +489,26 @@
 %!error argv (1)
 */
 
+DEFUN (cmdline_options, args, ,
+       doc: /* -*- texinfo -*-
+@deftypefn {} {} argv ()
+Return a structure containing info about the command line arguments
+passed to Octave.
+@end deftypefn */)
+{
+  if (args.length () != 0)
+    print_usage ();
+
+  octave::application *app = octave::application::app ();
+
+  if (! app)
+    error ("invalid application context!");
+
+  octave::cmdline_options opts = app->options ();
+
+  return ovl (opts.as_octave_value ());
+}
+
 DEFUN (program_invocation_name, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {} program_invocation_name ()
--- a/libinterp/octave.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/octave.h	Sun May 16 09:44:35 2021 +0200
@@ -29,10 +29,13 @@
 #include "octave-config.h"
 
 #include <list>
+#include <memory>
 #include <string>
 
 #include "str-vec.h"
 
+class octave_value;
+
 namespace octave
 {
   // Command line arguments.  See also options-usage.h.
@@ -55,6 +58,7 @@
     bool debug_jit (void) const { return m_debug_jit; }
     bool echo_commands (void) const { return m_echo_commands; }
 
+    bool experimental_terminal_widget (void) const { return m_experimental_terminal_widget; }
     bool forced_interactive (void) const { return m_forced_interactive; }
     bool forced_line_editing (void) const { return m_forced_line_editing; }
     bool gui (void) const { return m_gui; }
@@ -67,6 +71,7 @@
     bool read_history_file (void) const { return m_read_history_file; }
     bool read_init_files (void) const { return m_read_init_files; }
     bool read_site_files (void) const { return m_read_site_files; }
+    bool server (void) const { return m_server; }
     bool set_initial_path (void) const { return m_set_initial_path; }
     bool traditional (void) const { return m_traditional; }
     bool verbose_flag (void) const { return m_verbose_flag; }
@@ -85,6 +90,7 @@
     void debug_jit (bool arg) { m_debug_jit = arg; }
     void echo_commands (bool arg) { m_echo_commands = arg; }
 
+    void experimental_terminal_widget (bool arg) { m_experimental_terminal_widget = arg; }
     void forced_line_editing (bool arg) { m_forced_line_editing = arg; }
     void forced_interactive (bool arg) { m_forced_interactive = arg; }
     void gui (bool arg) { m_gui = arg; }
@@ -97,6 +103,7 @@
     void read_history_file (bool arg) { m_read_history_file = arg; }
     void read_init_files (bool arg) { m_read_init_files = arg; }
     void read_site_files (bool arg) { m_read_site_files = arg; }
+    void server (bool arg) { m_server = arg; }
     void set_initial_path (bool arg) { m_set_initial_path = arg; }
     void traditional (bool arg) { m_traditional = arg; }
     void verbose_flag (bool arg) { m_verbose_flag = arg; }
@@ -112,6 +119,8 @@
     void all_args (const string_vector& arg) { m_all_args = arg; }
     void remaining_args (const string_vector& arg) { m_remaining_args = arg; }
 
+    octave_value as_octave_value (void) const;
+
   private:
 
     // TRUE means enable debug tracing for the JIT compiler.
@@ -122,6 +131,10 @@
     // (--echo-commands, -x)
     bool m_echo_commands = false;
 
+    // If TRUE, use new experimental terminal widget in the GUI.
+    // (--experimental-terminal-widget)
+    bool m_experimental_terminal_widget = false;
+
     // If TRUE, start the GUI.
     // (--gui) and (--force-gui) for backwards compatibility
     bool m_gui = false;
@@ -166,6 +179,10 @@
     // (--norc; --no-site-file; -f)
     bool m_read_site_files = true;
 
+    // If TRUE, start the command server.
+    // (--server)
+    bool m_server = false;
+
     // TRUE means we set the initial path to configured defaults.
     // (--no-init-path)
     bool m_set_initial_path = true;
@@ -283,6 +300,10 @@
 
     void forced_interactive (bool arg) { m_options.forced_interactive (arg); }
 
+    // Provided for convenience.  Will be removed once we eliminate the
+    // old terminal widget.
+    bool experimental_terminal_widget (void) const;
+
     static application * app (void) { return instance; }
 
     static std::string program_invocation_name (void)
@@ -344,7 +365,7 @@
     // from eval without persist.
     bool m_is_octave_program = false;
 
-    interpreter *m_interpreter = nullptr;
+    std::unique_ptr<interpreter> m_interpreter;
   };
 
   class OCTINTERP_API cli_application : public application
--- a/libinterp/op-kw-docs	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/op-kw-docs	Sun May 16 09:44:35 2021 +0200
@@ -585,6 +585,13 @@
 Mark the end of a properties block in a classdef definition.
 @seealso{properties}
 @end deftypefn
+endspmd
+@c libinterp/parse-tree/oct-parse.yy
+-*- texinfo -*-
+@deftypefn {} {} endparfor
+Mark the end of an spmd block.  See @code{spmd} for an example.
+@seealso{spmd, parfor}
+@end deftypefn
 endswitch
 @c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
@@ -761,6 +768,31 @@
 Return from a function.
 @seealso{function}
 @end deftypefn
+spmd
+@c libinterp/parse-tree/oct-parse.yy
+-*- texinfo -*-
+@deftypefn  {} {} spmd
+@deftypefnx {} {} spmd (@var{n})
+@deftypefnx {} {} spmd (@var{m}, @var{n})
+Begin a block of statements which may execute in parallel across multiple
+workers.
+
+If Octave has a parallel processing pool enabled, the block of code will be
+executed in parallel across all of the pool's workers.  Otherwise, @code{spmd}
+has no effect and the statements are processed as normal code by the main
+Octave interpreter.
+
+If called with one additional argument @var{n} then use exactly @var{n} workers
+from the pool.  If called with two arguments @var{m}, @var{n} then use a
+minimum of @var{m} workers and a maximum of @var{n} workers from the parallel
+pool.
+
+@strong{Warning:} parallel processing pools are currently unimplemented in
+Octave; @code{spmd} currently does nothing, but is included to avoid breaking
+existing @sc{matlab} code.
+
+@seealso{parfor}
+@end deftypefn
 switch
 @c libinterp/parse-tree/oct-parse.yy
 -*- texinfo -*-
--- a/libinterp/operators/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -86,6 +86,7 @@
   %reldir%/op-m-s.cc \
   %reldir%/op-m-scm.cc \
   %reldir%/op-m-sm.cc \
+  %reldir%/op-mi.cc \
   %reldir%/op-pm-cm.cc \
   %reldir%/op-pm-fcm.cc \
   %reldir%/op-pm-fm.cc \
--- a/libinterp/operators/op-b-sbm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-b-sbm.cc	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 
 DEFCATOP (b_sbm, bool, sparse_bool_matrix)
 {
-  octave_bool& v1 = dynamic_cast<octave_bool&> (a1);
+  const octave_bool& v1 = dynamic_cast<const octave_bool&> (a1);
   const octave_sparse_bool_matrix& v2
     = dynamic_cast<const octave_sparse_bool_matrix&> (a2);
   SparseBoolMatrix tmp (1, 1, v1.bool_value ());
@@ -59,7 +59,7 @@
 
 DEFCATOP (b_sm, bool, sparse_matrix)
 {
-  octave_bool& v1 = dynamic_cast<octave_bool&> (a1);
+  const octave_bool& v1 = dynamic_cast<const octave_bool&> (a1);
   const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseMatrix tmp (1, 1, v1.scalar_value ());
   return octave_value (tmp. concat (v2.sparse_matrix_value (), ra_idx));
@@ -67,7 +67,7 @@
 
 DEFCATOP (s_sbm, scalar, sparse_bool_matrix)
 {
-  octave_scalar& v1 = dynamic_cast<octave_scalar&> (a1);
+  const octave_scalar& v1 = dynamic_cast<const octave_scalar&> (a1);
   const octave_sparse_bool_matrix& v2
     = dynamic_cast<const octave_sparse_bool_matrix&> (a2);
   SparseMatrix tmp (1, 1, v1.scalar_value ());
--- a/libinterp/operators/op-bm-sbm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-bm-sbm.cc	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 
 DEFCATOP (bm_sbm, bool_matrix, sparse_bool_matrix)
 {
-  octave_bool_matrix& v1 = dynamic_cast<octave_bool_matrix&> (a1);
+  const octave_bool_matrix& v1 = dynamic_cast<const octave_bool_matrix&> (a1);
   const octave_sparse_bool_matrix& v2
     = dynamic_cast<const octave_sparse_bool_matrix&> (a2);
   SparseBoolMatrix tmp (v1.bool_matrix_value ());
@@ -61,7 +61,7 @@
 
 DEFCATOP (m_sbm, matrix, sparse_bool_matrix)
 {
-  octave_matrix& v1 = dynamic_cast<octave_matrix&> (a1);
+  const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
   const octave_sparse_bool_matrix& v2
     = dynamic_cast<const octave_sparse_bool_matrix&> (a2);
   SparseMatrix tmp (v1.matrix_value ());
@@ -70,7 +70,7 @@
 
 DEFCATOP (bm_sm, bool_matrix, sparse_matrix)
 {
-  octave_bool_matrix& v1 = dynamic_cast<octave_bool_matrix&> (a1);
+  const octave_bool_matrix& v1 = dynamic_cast<const octave_bool_matrix&> (a1);
   const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseMatrix tmp (v1.matrix_value ());
   return octave_value (tmp. concat (v2.sparse_matrix_value (), ra_idx));
--- a/libinterp/operators/op-chm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-chm.cc	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
 
 DEFCATOP (chm_s, char_matrix, scalar)
 {
-  octave_char_matrix& v1 = dynamic_cast<octave_char_matrix&> (a1);
+  const octave_char_matrix& v1 = dynamic_cast<const octave_char_matrix&> (a1);
   const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
 
   warn_implicit_conversion ("Octave:num-to-str",
@@ -64,7 +64,7 @@
 
 DEFCATOP (chm_m, char_matrix, matrix)
 {
-  octave_char_matrix& v1 = dynamic_cast<octave_char_matrix&> (a1);
+  const octave_char_matrix& v1 = dynamic_cast<const octave_char_matrix&> (a1);
   const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
 
   warn_implicit_conversion ("Octave:num-to-str",
@@ -76,7 +76,7 @@
 
 DEFCATOP (s_chm, scalar, char_matrix)
 {
-  octave_scalar& v1 = dynamic_cast<octave_scalar&> (a1);
+  const octave_scalar& v1 = dynamic_cast<const octave_scalar&> (a1);
   const octave_char_matrix& v2 = dynamic_cast<const octave_char_matrix&> (a2);
 
   warn_implicit_conversion ("Octave:num-to-str",
@@ -88,7 +88,7 @@
 
 DEFCATOP (m_chm, matrix, char_matrix)
 {
-  octave_matrix& v1 = dynamic_cast<octave_matrix&> (a1);
+  const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
   const octave_char_matrix& v2 = dynamic_cast<const octave_char_matrix&> (a2);
 
   warn_implicit_conversion ("Octave:num-to-str",
--- a/libinterp/operators/op-cm-scm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-cm-scm.cc	Sun May 16 09:44:35 2021 +0200
@@ -129,7 +129,8 @@
 
 DEFCATOP (cm_scm, complex_matrix, sparse_complex_matrix)
 {
-  octave_complex_matrix& v1 = dynamic_cast<octave_complex_matrix&> (a1);
+  const octave_complex_matrix& v1
+    = dynamic_cast<const octave_complex_matrix&> (a1);
   const octave_sparse_complex_matrix& v2
     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
   SparseComplexMatrix tmp (v1.complex_matrix_value ());
--- a/libinterp/operators/op-cm-sm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-cm-sm.cc	Sun May 16 09:44:35 2021 +0200
@@ -125,7 +125,8 @@
 
 DEFCATOP (cm_sm, complex_matrix, sparse_matrix)
 {
-  octave_complex_matrix& v1 = dynamic_cast<octave_complex_matrix&> (a1);
+  const octave_complex_matrix& v1
+    = dynamic_cast<const octave_complex_matrix&> (a1);
   const octave_sparse_matrix& v2
     = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseComplexMatrix tmp (v1.complex_matrix_value ());
--- a/libinterp/operators/op-cs-scm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-cs-scm.cc	Sun May 16 09:44:35 2021 +0200
@@ -108,7 +108,7 @@
 
 DEFCATOP (cs_scm, complex, sparse_complex_matrix)
 {
-  octave_complex& v1 = dynamic_cast<octave_complex&> (a1);
+  const octave_complex& v1 = dynamic_cast<const octave_complex&> (a1);
   const octave_sparse_complex_matrix& v2
     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
   SparseComplexMatrix tmp (1, 1, v1.complex_value ());
--- a/libinterp/operators/op-cs-sm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-cs-sm.cc	Sun May 16 09:44:35 2021 +0200
@@ -104,8 +104,9 @@
 
 DEFCATOP (cs_sm, sparse_matrix, complex)
 {
-  octave_complex& v1 = dynamic_cast<octave_complex&> (a1);
-  const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
+  const octave_complex& v1 = dynamic_cast<const octave_complex&> (a1);
+  const octave_sparse_matrix& v2
+    = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseComplexMatrix tmp (1, 1, v1.complex_value ());
   return octave_value (tmp. concat (v2.sparse_matrix_value (), ra_idx));
 }
--- a/libinterp/operators/op-m-scm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-m-scm.cc	Sun May 16 09:44:35 2021 +0200
@@ -122,7 +122,7 @@
 
 DEFCATOP (m_scm, matrix, sparse_complex_matrix)
 {
-  octave_matrix& v1 = dynamic_cast<octave_matrix&> (a1);
+  const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
   const octave_sparse_complex_matrix& v2
     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
   SparseMatrix tmp (v1.matrix_value ());
--- a/libinterp/operators/op-m-sm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-m-sm.cc	Sun May 16 09:44:35 2021 +0200
@@ -117,7 +117,7 @@
 
 DEFCATOP (m_sm, matrix, sparse_matrix)
 {
-  octave_matrix& v1 = dynamic_cast<octave_matrix&> (a1);
+  const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
   const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseMatrix tmp (v1.matrix_value ());
   return octave_value (tmp. concat (v2.sparse_matrix_value (), ra_idx));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/operators/op-mi.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,119 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <iostream>
+
+#include "errwarn.h"
+#include "ops.h"
+#include "ov-magic-int.h"
+#include "ov-typeinfo.h"
+#include "ov.h"
+
+// Magic integer unary ops.  Only + and - are allowed so that
+// expressions like
+//
+//   int64 (-9007199254740994)
+//
+// produce proper int64 constants.
+
+static octave_value
+oct_unop_unsigned_uplus (const octave_base_value& a)
+{
+  const octave_magic_uint& v = dynamic_cast<const octave_magic_uint&> (a);
+  // no-op.
+  // FIXME: but can we do this just by incrementing the reference count?
+  return octave_value (v.clone ());
+}
+
+static octave_value
+oct_unop_unsigned_uminus (const octave_base_value& a)
+{
+  const octave_magic_uint& v = dynamic_cast<const octave_magic_uint&> (a);
+
+  // We are storing a uint64 value, so some fakery is needed here.
+  // Is there a better way?
+
+  octave_uint64 val = v.uint64_scalar_value ();
+
+  uint64_t ival = val.value ();
+
+  static const uint64_t max_val
+    = static_cast<uint64_t> (std::numeric_limits<int64_t>::max ());
+
+  static const uint64_t max_val_p1 = max_val + 1;
+
+  if (ival <= max_val)
+    {
+      int64_t signed_ival = ival;
+      return octave_value (new octave_magic_int (-signed_ival));
+    }
+
+  if (ival == max_val_p1)
+    {
+      // Correctly capture intmin.  For example, negating uint8(128)
+      // should return int8(-128) but converting directly to int8 and
+      // negating will not return the correct result.
+
+      static const int64_t min_signed_ival
+        = std::numeric_limits<int64_t>::min ();
+
+      return octave_value (new octave_magic_int (min_signed_ival));
+    }
+
+  return octave_value (-static_cast<double> (ival));
+}
+
+static octave_value
+oct_unop_signed_uplus (const octave_base_value& a)
+{
+  const octave_magic_int& v = dynamic_cast<const octave_magic_int&> (a);
+  // no-op.
+  // FIXME: but can we do this just by incrementing the reference count?
+  return octave_value (v.clone ());
+}
+
+static octave_value
+oct_unop_signed_uminus (const octave_base_value& a)
+{
+  const octave_magic_int& v = dynamic_cast<const octave_magic_int&> (a);
+
+  octave_int64 val = v.int64_scalar_value ();
+
+  return octave_value (new octave_magic_int (-val));
+}
+
+void
+install_mi_ops (octave::type_info& ti)
+{
+  INSTALL_UNOP_TI (ti, op_uplus, octave_magic_uint, unsigned_uplus);
+  INSTALL_UNOP_TI (ti, op_uminus, octave_magic_uint, unsigned_uminus);
+
+  INSTALL_UNOP_TI (ti, op_uplus, octave_magic_int, signed_uplus);
+  INSTALL_UNOP_TI (ti, op_uminus, octave_magic_int, signed_uminus);
+}
--- a/libinterp/operators/op-range.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-range.cc	Sun May 16 09:44:35 2021 +0200
@@ -31,63 +31,13 @@
 #include "ovl.h"
 #include "ov.h"
 #include "ov-range.h"
-#include "ov-ch-mat.h"
-#include "ov-scalar.h"
 #include "ov-re-mat.h"
-#include "ov-flt-re-mat.h"
-#include "ov-complex.h"
-#include "ov-cx-mat.h"
-#include "ov-bool.h"
-#include "ov-bool-mat.h"
 #include "ov-typeinfo.h"
 #include "ov-null-mat.h"
 #include "ops.h"
-#include "xpow.h"
 
-// range unary ops.
-
-DEFUNOP (not, range)
-{
-  const octave_range& v = dynamic_cast<const octave_range&> (a);
-
-  return octave_value (! v.matrix_value ());
-}
-
+// Allow +RNG_VAL to avoid conversion to array.
 DEFUNOP_OP (uplus, range, /* no-op */)
-DEFUNOP_OP (uminus, range, -)
-
-DEFUNOP (transpose, range)
-{
-  const octave_range& v = dynamic_cast<const octave_range&> (a);
-
-  return octave_value (v.matrix_value ().transpose ());
-}
-
-DEFBINOP_OP (addrs, range, scalar, +)
-DEFBINOP_OP (addsr, scalar, range, +)
-DEFBINOP_OP (subrs, range, scalar, -)
-DEFBINOP_OP (subsr, scalar, range, -)
-DEFBINOP_OP (mulrs, range, scalar, *)
-DEFBINOP_OP (mulsr, scalar, range, *)
-
-DEFBINOP_FN (el_powsr, scalar, range, elem_xpow)
-DEFBINOP_FN (el_powcsr, complex, range, elem_xpow)
-
-DEFNDCATOP_FN (r_r, range, range, array, array, concat)
-DEFNDCATOP_FN (r_s, range, scalar, array, array, concat)
-DEFNDCATOP_FN (r_m, range, matrix, array, array, concat)
-DEFNDCATOP_FN (r_cs, range, complex, array, complex_array, concat)
-DEFNDCATOP_FN (r_cm, range, complex_matrix, array, complex_array, concat)
-DEFNDCATOP_FN (r_b, range, bool, array, array, concat)
-DEFNDCATOP_FN (r_bm, range, bool_matrix, array, array, concat)
-DEFNDCATOP_FN (r_chm, range, char_matrix, array, char_array, concat)
-DEFNDCATOP_FN (s_r, scalar, range, array, array, concat)
-DEFNDCATOP_FN (m_r, matrix, range, array, array, concat)
-DEFNDCATOP_FN (cs_r, complex, range, complex_array, array, concat)
-DEFNDCATOP_FN (cm_r, complex_matrix, range, complex_array, array, concat)
-DEFNDCATOP_FN (b_r, bool, range, array, array, concat)
-DEFNDCATOP_FN (bm_r, bool_matrix, range, array, array, concat)
-DEFNDCATOP_FN (chm_r, char_matrix, range, char_array, array, concat)
 
 CONVDECL (range_to_matrix)
 {
@@ -99,39 +49,7 @@
 void
 install_range_ops (octave::type_info& ti)
 {
-  INSTALL_UNOP_TI (ti, op_not, octave_range, not);
   INSTALL_UNOP_TI (ti, op_uplus, octave_range, uplus);
-  INSTALL_UNOP_TI (ti, op_uminus, octave_range, uminus);
-  INSTALL_UNOP_TI (ti, op_transpose, octave_range, transpose);
-  INSTALL_UNOP_TI (ti, op_hermitian, octave_range, transpose);
-
-  INSTALL_BINOP_TI (ti, op_add, octave_range, octave_scalar, addrs);
-  INSTALL_BINOP_TI (ti, op_add, octave_scalar, octave_range, addsr);
-  INSTALL_BINOP_TI (ti, op_sub, octave_range, octave_scalar, subrs);
-  INSTALL_BINOP_TI (ti, op_sub, octave_scalar, octave_range, subsr);
-  INSTALL_BINOP_TI (ti, op_mul, octave_range, octave_scalar, mulrs);
-  INSTALL_BINOP_TI (ti, op_mul, octave_scalar, octave_range, mulsr);
-
-  INSTALL_BINOP_TI (ti, op_el_mul, octave_range, octave_scalar, mulrs);
-  INSTALL_BINOP_TI (ti, op_el_mul, octave_scalar, octave_range, mulsr);
-  INSTALL_BINOP_TI (ti, op_el_pow, octave_scalar, octave_range, el_powsr);
-  INSTALL_BINOP_TI (ti, op_el_pow, octave_complex, octave_range, el_powcsr);
-
-  INSTALL_CATOP_TI (ti, octave_range, octave_range, r_r);
-  INSTALL_CATOP_TI (ti, octave_range, octave_scalar, r_s);
-  INSTALL_CATOP_TI (ti, octave_range, octave_matrix, r_m);
-  INSTALL_CATOP_TI (ti, octave_range, octave_complex, r_cs);
-  INSTALL_CATOP_TI (ti, octave_range, octave_complex_matrix, r_cm);
-  INSTALL_CATOP_TI (ti, octave_range, octave_bool, r_b);
-  INSTALL_CATOP_TI (ti, octave_range, octave_bool_matrix, r_bm);
-  INSTALL_CATOP_TI (ti, octave_range, octave_char_matrix, r_chm);
-  INSTALL_CATOP_TI (ti, octave_scalar, octave_range, s_r);
-  INSTALL_CATOP_TI (ti, octave_matrix, octave_range, m_r);
-  INSTALL_CATOP_TI (ti, octave_complex, octave_range, cs_r);
-  INSTALL_CATOP_TI (ti, octave_complex_matrix, octave_range, cm_r);
-  INSTALL_CATOP_TI (ti, octave_bool, octave_range, b_r);
-  INSTALL_CATOP_TI (ti, octave_bool_matrix, octave_range, bm_r);
-  INSTALL_CATOP_TI (ti, octave_char_matrix, octave_range, chm_r);
 
   // FIXME: this would be unnecessary if
   // octave_base_value::numeric_assign always tried converting lhs
@@ -141,7 +59,7 @@
   INSTALL_ASSIGNCONV_TI (ti, octave_range, octave_null_str, octave_matrix);
   INSTALL_ASSIGNCONV_TI (ti, octave_range, octave_null_sq_str, octave_matrix);
 
-  // However, this should probably be here just in case we need it.
+  // Hmm, this one also seems to be needed.
 
   INSTALL_WIDENOP_TI (ti, octave_range, octave_matrix, range_to_matrix);
 }
--- a/libinterp/operators/op-s-scm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-s-scm.cc	Sun May 16 09:44:35 2021 +0200
@@ -110,7 +110,7 @@
 
 DEFCATOP (s_scm, scalar, sparse_compelx_matrix)
 {
-  octave_scalar& v1 = dynamic_cast<octave_scalar&> (a1);
+  const octave_scalar& v1 = dynamic_cast<const octave_scalar&> (a1);
   const octave_sparse_complex_matrix& v2
     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
   SparseMatrix tmp (1, 1, v1.scalar_value ());
--- a/libinterp/operators/op-s-sm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-s-sm.cc	Sun May 16 09:44:35 2021 +0200
@@ -101,7 +101,7 @@
 
 DEFCATOP (s_sm, scalar, sparse_matrix)
 {
-  octave_scalar& v1 = dynamic_cast<octave_scalar&> (a1);
+  const octave_scalar& v1 = dynamic_cast<const octave_scalar&> (a1);
   const octave_sparse_matrix& v2 = dynamic_cast<const octave_sparse_matrix&> (a2);
   SparseMatrix tmp (1, 1, v1.scalar_value ());
   return octave_value (tmp.concat (v2.sparse_matrix_value (), ra_idx));
--- a/libinterp/operators/op-sbm-b.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-sbm-b.cc	Sun May 16 09:44:35 2021 +0200
@@ -56,7 +56,7 @@
 
 DEFCATOP (sbm_b, sparse_bool_matrix, bool)
 {
-  octave_sparse_bool_matrix& v1 = dynamic_cast<octave_sparse_bool_matrix&> (a1);
+  const octave_sparse_bool_matrix& v1 = dynamic_cast<const octave_sparse_bool_matrix&> (a1);
   const octave_bool& v2 = dynamic_cast<const octave_bool&> (a2);
 
   SparseBoolMatrix tmp (1, 1, v2.bool_value ());
@@ -65,7 +65,7 @@
 
 DEFCATOP (sm_b, sparse_matrix, bool)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_bool& v2 = dynamic_cast<const octave_bool&> (a2);
 
   SparseMatrix tmp (1, 1, v2.scalar_value ());
@@ -74,7 +74,7 @@
 
 DEFCATOP (sbm_s, sparse_bool_matrix, scalar)
 {
-  octave_sparse_bool_matrix& v1 = dynamic_cast<octave_sparse_bool_matrix&> (a1);
+  const octave_sparse_bool_matrix& v1 = dynamic_cast<const octave_sparse_bool_matrix&> (a1);
   const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
 
   SparseMatrix tmp (1, 1, v2.scalar_value ());
--- a/libinterp/operators/op-sbm-bm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-sbm-bm.cc	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
 
 DEFCATOP (sbm_bm, sparse_bool_matrix, bool_matrix)
 {
-  octave_sparse_bool_matrix& v1 = dynamic_cast<octave_sparse_bool_matrix&> (a1);
+  const octave_sparse_bool_matrix& v1 = dynamic_cast<const octave_sparse_bool_matrix&> (a1);
   const octave_bool_matrix& v2 = dynamic_cast<const octave_bool_matrix&> (a2);
 
   SparseBoolMatrix tmp (v2.bool_matrix_value ());
@@ -70,7 +70,7 @@
 
 DEFCATOP (sbm_m, sparse_bool_matrix, matrix)
 {
-  octave_sparse_bool_matrix& v1 = dynamic_cast<octave_sparse_bool_matrix&> (a1);
+  const octave_sparse_bool_matrix& v1 = dynamic_cast<const octave_sparse_bool_matrix&> (a1);
   const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
 
   SparseMatrix tmp (v2.matrix_value ());
@@ -79,7 +79,7 @@
 
 DEFCATOP (sm_bm, sparse_matrix, bool_matrix)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_bool_matrix& v2 = dynamic_cast<const octave_bool_matrix&> (a2);
 
   SparseMatrix tmp (v2.matrix_value ());
--- a/libinterp/operators/op-scm-cm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-scm-cm.cc	Sun May 16 09:44:35 2021 +0200
@@ -129,8 +129,8 @@
 
 DEFCATOP (scm_cm, sparse_complex_matrix, complex_matrix)
 {
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
+  const octave_sparse_complex_matrix& v1
+    = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
   const octave_complex_matrix& v2
     = dynamic_cast<const octave_complex_matrix&> (a2);
   SparseComplexMatrix tmp (v2.complex_matrix_value ());
--- a/libinterp/operators/op-scm-cs.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-scm-cs.cc	Sun May 16 09:44:35 2021 +0200
@@ -117,8 +117,8 @@
 
 DEFCATOP (scm_cs, sparse_complex_matrix, complex)
 {
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
+  const octave_sparse_complex_matrix& v1
+    = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
   const octave_complex& v2 = dynamic_cast<const octave_complex&> (a2);
   SparseComplexMatrix tmp (1, 1, v2.complex_value ());
   return octave_value
--- a/libinterp/operators/op-scm-m.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-scm-m.cc	Sun May 16 09:44:35 2021 +0200
@@ -123,8 +123,8 @@
 
 DEFCATOP (scm_m, sparse_complex_matrix, matrix)
 {
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
+  const octave_sparse_complex_matrix& v1
+    = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
   const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
   SparseMatrix tmp (v2.matrix_value ());
   return octave_value
--- a/libinterp/operators/op-scm-s.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-scm-s.cc	Sun May 16 09:44:35 2021 +0200
@@ -125,8 +125,8 @@
 
 DEFCATOP (scm_s, sparse_complex_matrix, scalar)
 {
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
+  const octave_sparse_complex_matrix& v1
+    = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
   const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
   SparseComplexMatrix tmp (1, 1, v2.complex_value ());
   return octave_value
--- a/libinterp/operators/op-sm-cm.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-sm-cm.cc	Sun May 16 09:44:35 2021 +0200
@@ -126,7 +126,7 @@
 
 DEFCATOP (sm_cm, sparse_matrix, complex_matrix)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_complex_matrix& v2
     = dynamic_cast<const octave_complex_matrix&> (a2);
   SparseComplexMatrix tmp (v2.complex_matrix_value ());
--- a/libinterp/operators/op-sm-cs.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-sm-cs.cc	Sun May 16 09:44:35 2021 +0200
@@ -114,7 +114,7 @@
 
 DEFCATOP (sm_cs, sparse_matrix, complex)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_complex& v2 = dynamic_cast<const octave_complex&> (a2);
   SparseComplexMatrix tmp (1, 1, v2.complex_value ());
   return octave_value (v1.sparse_matrix_value (). concat (tmp, ra_idx));
--- a/libinterp/operators/op-sm-m.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-sm-m.cc	Sun May 16 09:44:35 2021 +0200
@@ -118,7 +118,7 @@
 
 DEFCATOP (sm_m, sparse_matrix, matrix)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
   SparseMatrix tmp (v2.matrix_value ());
   return octave_value (v1.sparse_matrix_value (). concat (tmp, ra_idx));
--- a/libinterp/operators/op-sm-s.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-sm-s.cc	Sun May 16 09:44:35 2021 +0200
@@ -115,7 +115,7 @@
 
 DEFCATOP (sm_s, sparse_matrix, scalar)
 {
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
+  const octave_sparse_matrix& v1 = dynamic_cast<const octave_sparse_matrix&> (a1);
   const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
   SparseMatrix tmp (1, 1, v2.scalar_value ());
   return octave_value (v1.sparse_matrix_value (). concat (tmp, ra_idx));
--- a/libinterp/operators/op-struct.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/op-struct.cc	Sun May 16 09:44:35 2021 +0200
@@ -60,7 +60,8 @@
 DEFNDCATOP_FN (ss_ss_concat, scalar_struct, scalar_struct, map, map, concat)
 
 static octave_value
-oct_catop_struct_matrix (octave_base_value& a1, const octave_base_value& a2,
+oct_catop_struct_matrix (const octave_base_value& a1,
+                         const octave_base_value& a2,
                          const Array<octave_idx_type>&)
 {
   const octave_struct& v1 = dynamic_cast<const octave_struct&> (a1);
@@ -76,7 +77,8 @@
 }
 
 static octave_value
-oct_catop_matrix_struct (octave_base_value& a1, const octave_base_value& a2,
+oct_catop_matrix_struct (const octave_base_value& a1,
+                         const octave_base_value& a2,
                          const Array<octave_idx_type>&)
 {
   const octave_matrix& v1 = dynamic_cast<const octave_matrix&> (a1);
--- a/libinterp/operators/ops.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/operators/ops.h	Sun May 16 09:44:35 2021 +0200
@@ -322,12 +322,13 @@
 
 #define DEFCATOPX(name, t1, t2)                                         \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value&, const octave_base_value&, \
+  CONCAT2 (oct_catop_, name) (const octave_base_value&,                 \
+                              const octave_base_value&,                 \
                               const Array<octave_idx_type>& ra_idx)
 
 #define DEFCATOP(name, t1, t2)                                          \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)
 
@@ -335,11 +336,11 @@
 
 #define DEFCATOP_FN(name, t1, t2, f)                                    \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)     \
   {                                                                     \
-    CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     return octave_value (v1.CONCAT2 (t1, _value) () . f (v2.CONCAT2 (t2, _value) (), ra_idx)); \
@@ -347,11 +348,11 @@
 
 #define DEFNDCATOP_FN(name, t1, t2, e1, e2, f)                          \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)     \
   {                                                                     \
-    CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     return octave_value (v1.CONCAT2 (e1, _value) () . f (v2.CONCAT2 (e2, _value) (), ra_idx)); \
@@ -359,11 +360,11 @@
 
 #define DEFNDCHARCATOP_FN(name, t1, t2, f)                              \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)     \
   {                                                                     \
-    CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     return octave_value (v1.char_array_value () . f (v2.char_array_value (), ra_idx), \
@@ -376,11 +377,11 @@
 
 #define DEFNDCATOP_FN2(name, t1, t2, tc1, tc2, e1, e2, f)               \
   static octave_value                                                   \
-  CONCAT2 (oct_catop_, name) (octave_base_value& a1,                    \
+  CONCAT2 (oct_catop_, name) (const octave_base_value& a1,              \
                               const octave_base_value& a2,              \
                               const Array<octave_idx_type>& ra_idx)     \
   {                                                                     \
-    CONCAT2 (octave_, t1)& v1 = dynamic_cast<CONCAT2 (octave_, t1)&> (a1); \
+    const CONCAT2 (octave_, t1)& v1 = dynamic_cast<const CONCAT2 (octave_, t1)&> (a1); \
     const CONCAT2 (octave_, t2)& v2 = dynamic_cast<const CONCAT2 (octave_, t2)&> (a2); \
                                                                         \
     return octave_value (tc1 (v1.CONCAT2 (e1, _value) ()) . f (tc2 (v2.CONCAT2 (e2, _value) ()), ra_idx)); \
--- a/libinterp/options-usage.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/options-usage.h	Sun May 16 09:44:35 2021 +0200
@@ -36,12 +36,12 @@
 static const char *usage_string =
   "octave [-HVWdfhiqvx] [--debug] [--debug-jit] [--doc-cache-file file]\n\
        [--echo-commands] [--eval CODE] [--exec-path path]\n\
-       [--gui] [--help] [--image-path path]\n\
+       [--experimental-terminal-widget] [--gui] [--help] [--image-path path]\n\
        [--info-file file] [--info-program prog] [--interactive]\n\
        [--jit-compiler] [--line-editing] [--no-gui] [--no-history]\n\
        [--no-init-file] [--no-init-path] [--no-line-editing]\n\
        [--no-site-file] [--no-window-system] [--norc] [-p path]\n\
-       [--path path] [--persist] [--silent] [--traditional]\n\
+       [--path path] [--persist] [--server] [--silent] [--traditional]\n\
        [--verbose] [--version] [file]";
 
 // This is here so that it's more likely that the usage message and
@@ -75,8 +75,10 @@
 #define NO_LINE_EDITING_OPTION 15
 #define NO_SITE_FILE_OPTION 16
 #define PERSIST_OPTION 17
-#define TEXI_MACROS_FILE_OPTION 18
-#define TRADITIONAL_OPTION 19
+#define SERVER_OPTION 18
+#define TEXI_MACROS_FILE_OPTION 19
+#define TRADITIONAL_OPTION 20
+#define EXPERIMENTAL_TERMINAL_WIDGET_OPTION 21
 struct octave_getopt_options long_opts[] =
 {
   { "braindead",                octave_no_arg,       0, TRADITIONAL_OPTION },
@@ -87,6 +89,7 @@
   { "echo-commands",            octave_no_arg,       0, 'x' },
   { "eval",                     octave_required_arg, 0, EVAL_OPTION },
   { "exec-path",                octave_required_arg, 0, EXEC_PATH_OPTION },
+  { "experimental-terminal-widget", octave_no_arg,   0, EXPERIMENTAL_TERMINAL_WIDGET_OPTION },
   { "gui",                      octave_no_arg,       0, GUI_OPTION },
   { "help",                     octave_no_arg,       0, 'h' },
   { "image-path",               octave_required_arg, 0, IMAGE_PATH_OPTION },
@@ -106,6 +109,7 @@
   { "path",                     octave_required_arg, 0, 'p' },
   { "persist",                  octave_no_arg,       0, PERSIST_OPTION },
   { "quiet",                    octave_no_arg,       0, 'q' },
+  { "server",                   octave_no_arg,       0, SERVER_OPTION },
   { "silent",                   octave_no_arg,       0, 'q' },
   { "texi-macros-file",         octave_required_arg, 0, TEXI_MACROS_FILE_OPTION },
   { "traditional",              octave_no_arg,       0, TRADITIONAL_OPTION },
@@ -138,6 +142,8 @@
   --echo-commands, -x     Echo commands as they are executed.\n\
   --eval CODE             Evaluate CODE.  Exit when done unless --persist.\n\
   --exec-path PATH        Set path for executing subprograms.\n\
+  --experimental-terminal-widget\n\
+                          Use new experimental terminal widget in the GUI.\n\
   --gui                   Start the graphical user interface.\n\
   --help, -h,             Print short help message and exit.\n\
   --image-path PATH       Add PATH to head of image search path.\n\
@@ -156,6 +162,7 @@
   --norc, -f              Don't read any initialization files.\n\
   --path PATH, -p PATH    Add PATH to head of function search path.\n\
   --persist               Go interactive after --eval or reading from FILE.\n\
+  --server                Enter server mode at startup.\n\
   --silent, --quiet, -q   Don't print message at startup.\n\
   --texi-macros-file FILE Use Texinfo macros in FILE for makeinfo command.\n\
   --traditional           Set variables for closer MATLAB compatibility.\n\
--- a/libinterp/parse-tree/bp-table.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/bp-table.cc	Sun May 16 09:44:35 2021 +0200
@@ -35,6 +35,7 @@
 #include <string>
 
 #include "file-ops.h"
+#include "oct-env.h"
 
 #include "bp-table.h"
 #include "defun-int.h"
@@ -55,6 +56,62 @@
 
 namespace octave
 {
+  class bp_file_info
+  {
+  public:
+
+    bp_file_info (tree_evaluator& tw, const std::string& file)
+      : m_ok (false), m_file (file), m_dir (), m_fcn (), m_class_name ()
+    {
+      std::string abs_file = sys::env::make_absolute (file);
+
+      std::string dir = sys::file_ops::dirname (abs_file);
+      std::string fcn = sys::file_ops::tail (abs_file);
+      std::size_t len = fcn.length ();
+      if (len >= 2 && fcn[len-2] == '.' && fcn[len-1] == 'm')
+        fcn = fcn.substr (0, len-2);
+
+      std::size_t pos = dir.rfind (sys::file_ops::dir_sep_chars ());
+
+      if (pos != std::string::npos && pos < dir.length () - 1)
+        {
+          if (dir[pos+1] == '@')
+            {
+              m_class_name = dir.substr (pos+1);
+
+              fcn = sys::file_ops::concat (m_class_name, fcn);
+
+              dir = dir.substr (0, pos);
+            }
+        }
+
+      m_dir = dir;
+      m_fcn = fcn;
+
+      interpreter& interp = tw.get_interpreter ();
+
+      load_path& lp = interp.get_load_path ();
+
+      if (lp.contains_file_in_dir (m_file, m_dir))
+        m_ok = true;
+    }
+
+    std::string file (void) const { return m_file; }
+    std::string dir (void) const { return m_fcn; }
+    std::string fcn (void) const { return m_fcn; }
+    std::string class_name (void) const { return m_class_name; }
+
+    bool ok (void) const { return m_ok; }
+
+  private:
+
+    bool m_ok;
+    std::string m_file;
+    std::string m_dir;
+    std::string m_fcn;
+    std::string m_class_name;
+  };
+
   // Clear all reasons to stop, other than breakpoints.
 
   void bp_table::dbclear_all_signals (void)
@@ -174,9 +231,9 @@
 
   bool bp_table::add_breakpoint_1 (octave_user_code *fcn,
                                    const std::string& fname,
-                                   const bp_table::intmap& line,
+                                   const bp_table::bp_lines& line,
                                    const std::string& condition,
-                                   bp_table::intmap& retval)
+                                   bp_table::bp_lines& retval)
   {
     bool found = false;
 
@@ -192,9 +249,9 @@
 
         retval = cmds->add_breakpoint (evmgr, file, line, condition);
 
-        for (auto& idx_line_p : retval)
+        for (auto& lineno : retval)
           {
-            if (idx_line_p.second != 0)
+            if (lineno != 0)
               {
                 // Normalize to store only the file name.
                 // Otherwise, there can be an entry for both
@@ -283,14 +340,13 @@
                                           const octave_value_list& args,
                                           std::string& func_name,
                                           std::string& class_name,
-                                          bp_table::intmap& lines,
+                                          bp_table::bp_lines& lines,
                                           std::string& cond)
   {
     int nargin = args.length ();
-    int list_idx = 0;
     func_name = "";
     class_name = "";
-    lines = bp_table::intmap ();
+    lines = bp_table::bp_lines ();
 
     if (nargin == 0 || ! args(0).is_string ())
       print_usage (who);
@@ -397,7 +453,7 @@
                     int line = atoi (args(pos).string_value ().c_str ());
 
                     if (line > 0)
-                      lines[list_idx++] = line;
+                      lines.insert (line);
                     else
                       break;        // may be "if" or a method name
                   }
@@ -406,7 +462,7 @@
                     const NDArray arg = args(pos).array_value ();
 
                     for (octave_idx_type j = 0; j < arg.numel (); j++)
-                      lines[list_idx++] = static_cast<int> (arg.elem (j));
+                      lines.insert (static_cast<int> (arg.elem (j)));
                   }
                 else
                   error ("%s: Invalid argument type %s",
@@ -612,39 +668,56 @@
 
   // Given file name fname, find the subfunction at line and create
   // a breakpoint there.  Put the system into debug_mode.
-  bp_table::intmap bp_table::add_breakpoint (const std::string& fname,
-                                             const std::string& class_name,
-                                             const bp_table::intmap& line,
-                                             const std::string& condition)
+  int bp_table::add_breakpoint_in_function (const std::string& fname,
+                                            const std::string& class_name,
+                                            int line, const std::string& condition)
+  {
+    bp_lines line_info;
+    line_info.insert (line);
+
+    bp_lines result
+      = add_breakpoints_in_function (fname, class_name, line_info, condition);
+
+    return result.empty () ? 0 : *(result.begin ());
+  }
+
+  // Given file name fname, find the subfunction at line and create
+  // a breakpoint there.  Put the system into debug_mode.
+  bp_table::bp_lines
+  bp_table::add_breakpoints_in_function (const std::string& fname,
+                                         const std::string& class_name,
+                                         const bp_table::bp_lines& lines,
+                                         const std::string& condition)
   {
     octave_user_code *main_fcn = m_evaluator.get_user_code (fname, class_name);
 
     if (! main_fcn)
-      error ("add_breakpoint: unable to find function '%s'\n", fname.c_str ());
+      error ("add_breakpoints_in_function: unable to find function '%s'\n",
+             fname.c_str ());
 
     condition_valid (condition);  // Throw error if condition not valid.
 
-    intmap retval;
+    bp_lines retval;
 
-    octave_idx_type len = line.size ();
+    for (const auto& lineno : lines)
+      {
+        octave_user_code *dbg_fcn = find_fcn_by_line (main_fcn, lineno);
 
-    for (int i = 0; i < len; i++)
-      {
-        const_intmap_iterator m = line.find (i);
+        // We've found the right (sub)function.  Now insert the breakpoint.
+        bp_lines line_info;
+        line_info.insert (lineno);
 
-        if (m != line.end ())
+        bp_lines ret_one;
+        if (dbg_fcn && add_breakpoint_1 (dbg_fcn, fname, line_info,
+                                         condition, ret_one))
           {
-            int lineno = m->second;
-
-            octave_user_code *dbg_fcn = find_fcn_by_line (main_fcn, lineno);
+            if (! ret_one.empty ())
+              {
+                int line = *(ret_one.begin ());
 
-            // We've found the right (sub)function.  Now insert the breakpoint.
-            // We insert all breakpoints.
-            // If multiple are in the same function, we insert multiple times.
-            intmap ret_one;
-            if (dbg_fcn
-                && add_breakpoint_1 (dbg_fcn, fname, line, condition, ret_one))
-              retval.insert (std::pair<int,int> (i, ret_one.find (i)->second));
+                if (line)
+                  retval.insert (line);
+              }
           }
       }
 
@@ -653,9 +726,42 @@
     return retval;
   }
 
+  int bp_table::add_breakpoint_in_file (const std::string& file,
+                                        int line,
+                                        const std::string& condition)
+  {
+    // Duplicates what the GUI was doing previously, but this action
+    // should not be specific to the GUI.
+
+    bp_file_info info (m_evaluator, file);
+
+    if (! info.ok ())
+      return 0;
+
+    return add_breakpoint_in_function (info.fcn (), info.class_name (),
+                                       line, condition);
+  }
+
+  bp_table::bp_lines
+  bp_table::add_breakpoints_in_file (const std::string& file,
+                                     const bp_lines& lines,
+                                     const std::string& condition)
+  {
+    // Duplicates what the GUI was doing previously, but this action
+    // should not be specific to the GUI.
+
+    bp_file_info info (m_evaluator, file);
+
+    if (! info.ok ())
+      return bp_lines ();
+
+    return add_breakpoints_in_function (info.fcn (), info.class_name (),
+                                        lines, condition);
+  }
+
   int bp_table::remove_breakpoint_1 (octave_user_code *fcn,
                                      const std::string& fname,
-                                     const bp_table::intmap& line)
+                                     const bp_table::bp_lines& lines)
   {
     int retval = 0;
 
@@ -675,21 +781,12 @@
 
             event_manager& evmgr = interp.get_event_manager ();
 
-            octave_idx_type len = line.size ();
-
-            for (int i = 0; i < len; i++)
+            for (const auto& lineno : lines)
               {
-                const_intmap_iterator p = line.find (i);
+                cmds->delete_breakpoint (lineno);
 
-                if (p != line.end ())
-                  {
-                    int lineno = p->second;
-
-                    cmds->delete_breakpoint (lineno);
-
-                    if (! file.empty ())
-                      evmgr.update_breakpoint (false, file, lineno);
-                  }
+                if (! file.empty ())
+                  evmgr.update_breakpoint (false, file, lineno);
               }
 
             results = cmds->list_breakpoints ();
@@ -705,16 +802,24 @@
     return retval;
   }
 
-  int bp_table::remove_breakpoint (const std::string& fname,
-                                   const bp_table::intmap& line)
+  int
+  bp_table::remove_breakpoint_from_function (const std::string& fname, int line)
+  {
+    bp_lines line_info;
+    line_info.insert (line);
+
+    return remove_breakpoints_from_function (fname, line_info);
+  }
+
+  int
+  bp_table::remove_breakpoints_from_function (const std::string& fname,
+                                              const bp_table::bp_lines& lines)
   {
     int retval = 0;
 
-    octave_idx_type len = line.size ();
-
-    if (len == 0)
+    if (lines.empty ())
       {
-        intmap results = remove_all_breakpoints_in_file (fname);
+        bp_lines results = remove_all_breakpoints_from_function (fname);
         retval = results.size ();
       }
     else
@@ -722,10 +827,10 @@
         octave_user_code *dbg_fcn = m_evaluator.get_user_code (fname);
 
         if (! dbg_fcn)
-          error ("remove_breakpoint: unable to find function %s\n",
+          error ("remove_breakpoints_from_function: unable to find function %s\n",
                  fname.c_str ());
 
-        retval = remove_breakpoint_1 (dbg_fcn, fname, line);
+        retval = remove_breakpoint_1 (dbg_fcn, fname, lines);
 
         // Search subfunctions in the order they appear in the file.
 
@@ -743,7 +848,7 @@
               {
                 octave_user_code *dbg_subfcn = q->second.user_code_value ();
 
-                retval += remove_breakpoint_1 (dbg_subfcn, fname, line);
+                retval += remove_breakpoint_1 (dbg_subfcn, fname, lines);
               }
           }
       }
@@ -755,11 +860,11 @@
 
   // Remove all breakpoints from a file, including those in subfunctions.
 
-  bp_table::intmap
-  bp_table::remove_all_breakpoints_in_file (const std::string& fname,
-                                            bool silent)
+  bp_table::bp_lines
+  bp_table::remove_all_breakpoints_from_function (const std::string& fname,
+                                                  bool silent)
   {
-    intmap retval;
+    bp_lines retval;
 
     octave_user_code *dbg_fcn = m_evaluator.get_user_code (fname);
 
@@ -783,7 +888,7 @@
           }
       }
     else if (! silent)
-      error ("remove_all_breakpoint_in_file: "
+      error ("remove_all_breakpoints_from_function: "
              "unable to find function %s\n", fname.c_str ());
 
     m_evaluator.reset_debug_state ();
@@ -791,6 +896,50 @@
     return retval;
   }
 
+  int
+  bp_table::remove_breakpoint_from_file (const std::string& file, int line)
+  {
+    // Duplicates what the GUI was doing previously, but this action
+    // should not be specific to the GUI.
+
+    bp_file_info info (m_evaluator, file);
+
+    if (! info.ok ())
+      return 0;
+
+    return remove_breakpoint_from_function (info.fcn (), line);
+  }
+
+  int
+  bp_table::remove_breakpoints_from_file (const std::string& file,
+                                          const bp_lines& lines)
+  {
+    // Duplicates what the GUI was doing previously, but this action
+    // should not be specific to the GUI.
+
+    bp_file_info info (m_evaluator, file);
+
+    if (! info.ok ())
+      return 0;
+
+    return remove_breakpoints_from_function (info.fcn (), lines);
+  }
+
+  bp_table::bp_lines
+  bp_table::remove_all_breakpoints_from_file (const std::string& file,
+                                              bool silent)
+  {
+    // Duplicates what the GUI was doing previously, but this action
+    // should not be specific to the GUI.
+
+    bp_file_info info (m_evaluator, file);
+
+    if (! info.ok ())
+      return bp_lines ();
+
+    return remove_all_breakpoints_from_function (info.fcn (), silent);
+  }
+
   void bp_table::remove_all_breakpoints (void)
   {
     // Odd loop structure required because delete will invalidate
@@ -800,7 +949,7 @@
          it = it_next)
       {
         ++it_next;
-        remove_all_breakpoints_in_file (*it);
+        remove_all_breakpoints_from_function (*it);
       }
 
     m_evaluator.reset_debug_state ();
@@ -997,12 +1146,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	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/bp-table.h	Sun May 16 09:44:35 2021 +0200
@@ -61,13 +61,13 @@
 
     ~bp_table (void) = default;
 
-    // mapping from (FIXME: arbitrary index??) to line number of breakpoint
-    typedef std::map<int, int> intmap;
+    // Set of breakpoint lines.
+    typedef std::set<int> bp_lines;
 
-    typedef intmap::const_iterator const_intmap_iterator;
-    typedef intmap::iterator intmap_iterator;
+    typedef bp_lines::const_iterator const_bp_lines_iterator;
+    typedef bp_lines::iterator bp_lines_iterator;
 
-    typedef std::map <std::string, intmap> fname_line_map;
+    typedef std::map <std::string, bp_lines> fname_line_map;
 
     typedef fname_line_map::const_iterator const_fname_line_map_iterator;
     typedef fname_line_map::iterator fname_line_map_iterator;
@@ -76,19 +76,93 @@
     typedef fname_bp_map::const_iterator const_fname_bp_map_iterator;
     typedef fname_bp_map::iterator fname_bp_map_iterator;
 
-    // Add a breakpoint at the nearest executable line.
-    intmap add_breakpoint (const std::string& fname = "",
-                           const std::string& class_name = "",
-                           const intmap& lines = intmap (),
-                           const std::string& condition = "");
+    OCTAVE_DEPRECATED (7, "use 'bp_table::add_breakpoints_in_function' instead")
+    int add_breakpoint (const std::string& fname = "",
+                        const std::string& class_name = "",
+                        int line = 1,
+                        const std::string& condition = "")
+    {
+      return add_breakpoint_in_function (fname, class_name, line, condition);
+    }
+
+    OCTAVE_DEPRECATED (7, "use 'bp_table::add_breakpoints_in_function' instead")
+    bp_lines add_breakpoint (const std::string& fname = "",
+                             const std::string& class_name = "",
+                             const bp_lines& lines = bp_lines (),
+                             const std::string& condition = "")
+    {
+      return add_breakpoints_in_function (fname, class_name, lines, condition);
+    }
+
+    // Add a breakpoint at the nearest executable line in a function.
+    int add_breakpoint_in_function (const std::string& fname = "",
+                                    const std::string& class_name = "",
+                                    int line = 1,
+                                    const std::string& condition = "");
+
+    // Add a set of breakpoints at the nearest executable lines in a
+    // function.
+    bp_lines add_breakpoints_in_function (const std::string& fname = "",
+                                          const std::string& class_name = "",
+                                          const bp_lines& lines = bp_lines (),
+                                          const std::string& condition = "");
+
+    // Add a breakpoint at the nearest executable line in a file.
+    int add_breakpoint_in_file (const std::string& file = "",
+                                int line = 1,
+                                const std::string& condition = "");
+
+    // Add a set of breakpoints at the nearest executable lines in a
+    // file.
+    bp_lines add_breakpoints_in_file (const std::string& file = "",
+                                      const bp_lines& lines = bp_lines (),
+                                      const std::string& condition = "");
 
-    // Remove a breakpoint from a line in file.
+    OCTAVE_DEPRECATED (7, "use 'bp_table::remove_breakpoint_from_function' instead")
+    int remove_breakpoint (const std::string& fname = "",
+                           int line = 1)
+    {
+      return remove_breakpoint_from_function (fname, line);
+    }
+
+    OCTAVE_DEPRECATED (7, "use 'bp_table::remove_breakpoints_from_function' instead")
     int remove_breakpoint (const std::string& fname = "",
-                           const intmap& lines = intmap ());
+                           const bp_lines& lines = bp_lines ())
+    {
+      return remove_breakpoints_from_function (fname, lines);
+    }
+
+    // Remove a breakpoint from the given line in file.
+    int remove_breakpoint_from_function (const std::string& fname = "",
+                                         int line = 1);
+
+    // Remove a set of breakpoints from the given lines in file.
+    int remove_breakpoints_from_function (const std::string& fname = "",
+                                          const bp_lines& lines = bp_lines ());
 
-    // Remove all the breakpoints in a specified file.
-    intmap remove_all_breakpoints_in_file (const std::string& fname,
-                                           bool silent = false);
+    // Remove all the breakpoints in a specified function.
+    bp_lines remove_all_breakpoints_from_function (const std::string& fname,
+                                                   bool silent = false);
+
+    // Remove a breakpoint from the given line in file.
+    int remove_breakpoint_from_file (const std::string& file = "",
+                                     int line = 1);
+
+    // Remove a set of breakpoints from the given lines in file.
+    int remove_breakpoints_from_file (const std::string& file = "",
+                                      const bp_lines& lines = bp_lines ());
+
+
+    OCTAVE_DEPRECATED (7, "use 'bp_table::remove_all_breakpoints_from_function' instead")
+    bp_lines remove_all_breakpoints_in_file (const std::string& fname,
+                                             bool silent = false)
+    {
+      return remove_all_breakpoints_from_function (fname, silent);
+    }
+
+    // Remove all the breakpoints from a file.
+    bp_lines remove_all_breakpoints_from_file (const std::string& file,
+                                               bool silent = false);
 
     // Remove all the breakpoints registered with octave.
     void remove_all_breakpoints (void);
@@ -127,7 +201,7 @@
 
     void parse_dbfunction_params (const char *who, const octave_value_list& args,
                                   std::string& func_name, std::string& class_name,
-                                  bp_table::intmap& lines, std::string& cond);
+                                  bp_table::bp_lines& lines, std::string& cond);
 
   private:
 
@@ -155,18 +229,15 @@
                           std::set<std::string>& id_list);
 
     bool add_breakpoint_1 (octave_user_code *fcn, const std::string& fname,
-                           const intmap& line, const std::string& condition,
-                           intmap& retval);
+                           const bp_lines& line, const std::string& condition,
+                           bp_lines& retval);
 
     int remove_breakpoint_1 (octave_user_code *fcn, const std::string&,
-                             const intmap& lines);
+                             const bp_lines& lines);
 
-    intmap remove_all_breakpoints_in_file_1 (octave_user_code *fcn,
-                                             const std::string& fname);
+    bp_lines remove_all_breakpoints_in_file_1 (octave_user_code *fcn,
+                                               const std::string& fname);
   };
-
-  OCTAVE_DEPRECATED (5, "use 'octave::get_user_code' instead")
-  extern octave_user_code * get_user_code (const std::string& fname = "");
 }
 
 #endif
--- a/libinterp/parse-tree/jit-typeinfo.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/jit-typeinfo.cc	Sun May 16 09:44:35 2021 +0200
@@ -116,7 +116,7 @@
   extern "C" octave_idx_type
   octave_jit_compute_nelem (double base, double limit, double inc)
   {
-    Range rng = Range (base, limit, inc);
+    range<double> rng (base, inc, limit);
     return rng.numel ();
   }
 
@@ -167,7 +167,7 @@
   extern "C" octave_base_value *
   octave_jit_cast_any_range (jit_range *rng)
   {
-    Range temp (*rng);
+    range<double> temp (*rng);
     octave_value ret (temp);
     octave_base_value *rep = ret.internal_rep ();
     rep->grab ();
@@ -480,7 +480,7 @@
   bool
   jit_range::all_elements_are_ints () const
   {
-    Range r (*this);
+    range<double> r (*this);
     return r.all_elements_are_ints ();
   }
 
--- a/libinterp/parse-tree/jit-typeinfo.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/jit-typeinfo.h	Sun May 16 09:44:35 2021 +0200
@@ -52,14 +52,14 @@
   struct
   jit_range
   {
-    jit_range (const Range& from)
+    jit_range (const range<double>& from)
       : m_base (from.base ()), m_limit (from.limit ()), m_inc (from.inc ()),
         m_nelem (from.numel ())
     { }
 
-    operator Range () const
+    operator range<double> () const
     {
-      return Range (m_base, m_limit, m_inc);
+      return range<double> (m_base, m_inc, m_limit);
     }
 
     bool all_elements_are_ints (void) const;
--- a/libinterp/parse-tree/lex.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/lex.h	Sun May 16 09:44:35 2021 +0200
@@ -661,7 +661,9 @@
 
     bool whitespace_is_significant (void);
 
-    void handle_number (void);
+    // We only provide specializations with base equal to 2, 10, or 16.
+    template <int base>
+    int handle_number (void);
 
     void handle_continuation (void);
 
@@ -772,6 +774,10 @@
       : base_lexer (interp), m_reader (interp, file), m_initial_input (true)
     { }
 
+    lexer (FILE *file, interpreter& interp, const std::string& encoding)
+      : base_lexer (interp), m_reader (interp, file, encoding), m_initial_input (true)
+    { }
+
     lexer (const std::string& eval_string, interpreter& interp)
       : base_lexer (interp), m_reader (interp, eval_string),
         m_initial_input (true)
@@ -822,6 +828,10 @@
     bool m_initial_input;
   };
 
+  template <> int base_lexer::handle_number<2> ();
+  template <> int base_lexer::handle_number<10> ();
+  template <> int base_lexer::handle_number<16> ();
+
   class
   push_lexer : public base_lexer
   {
--- a/libinterp/parse-tree/lex.ll	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/lex.ll	Sun May 16 09:44:35 2021 +0200
@@ -92,6 +92,7 @@
 #include <cctype>
 #include <cstring>
 
+#include <algorithm>
 #include <iostream>
 #include <set>
 #include <sstream>
@@ -117,6 +118,7 @@
 #include "interpreter.h"
 #include "lex.h"
 #include "octave.h"
+#include "ov-magic-int.h"
 #include "ov.h"
 #include "parse.h"
 #include "pt-all.h"
@@ -251,6 +253,35 @@
      }                                                  \
    while (0)
 
+#define HANDLE_NUMBER(PATTERN, BASE)                            \
+  do                                                            \
+    {                                                           \
+     curr_lexer->lexer_debug (PATTERN);                         \
+                                                                \
+     if (curr_lexer->previous_token_may_be_command ()           \
+         &&  curr_lexer->space_follows_previous_token ())       \
+       {                                                        \
+         yyless (0);                                            \
+         curr_lexer->push_start_state (COMMAND_START);          \
+       }                                                        \
+     else                                                       \
+       {                                                        \
+         int tok = curr_lexer->previous_token_value ();         \
+                                                                \
+         if (curr_lexer->whitespace_is_significant ()           \
+             && curr_lexer->space_follows_previous_token ()     \
+             && ! (tok == '[' || tok == '{'                     \
+                   || curr_lexer->previous_token_is_binop ()))  \
+           {                                                    \
+             yyless (0);                                        \
+             curr_lexer->xunput (',');                          \
+           }                                                    \
+         else                                                   \
+           return curr_lexer->handle_number<BASE> ();           \
+       }                                                        \
+    }                                                           \
+  while (0)
+
 #define HANDLE_IDENTIFIER(pattern, get_set)                             \
    do                                                                   \
      {                                                                  \
@@ -326,15 +357,40 @@
 D_      [0-9_]
 S       [ \t]
 NL      ((\n)|(\r)|(\r\n))
-Im      [iIjJ]
 CCHAR   [#%]
 IDENT   ([_$a-zA-Z][_$a-zA-Z0-9]*)
 FQIDENT ({IDENT}({S}*\.{S}*{IDENT})*)
-EXPON   ([DdEe][+-]?{D}{D_}*)
-NUMBIN  (0[bB][01_]+)
-NUMHEX  (0[xX][0-9a-fA-F][0-9a-fA-F_]*)
-NUMREAL (({D}{D_}*\.?{D_}*{EXPON}?)|(\.{D}{D_}*{EXPON}?))
-NUMBER  ({NUMREAL}|{NUMHEX}|{NUMBIN})
+
+%{
+// Decimal numbers may be real or imaginary but always create
+// double precision constants initially.  Any conversion to single
+// precision happens as part of an expression evaluation in the
+// interpreter, not the lexer and parser.
+%}
+
+DECIMAL_DIGITS ({D}{D_}*)
+EXPONENT       ([DdEe][+-]?{DECIMAL_DIGITS})
+REAL_DECIMAL   ((({DECIMAL_DIGITS}\.?)|({DECIMAL_DIGITS}?\.{DECIMAL_DIGITS})){EXPONENT}?)
+IMAG_DECIMAL   ({REAL_DECIMAL}[IiJj])
+DECIMAL_NUMBER ({REAL_DECIMAL}|{IMAG_DECIMAL})
+
+%{
+// It is possible to specify signedness and size for binary and
+// hexadecimal numbers but there is no special syntax for imaginary
+// constants.  Binary and hexadecimal constants always create integer
+// valued constants ({u,}int{8,16,32,64}).  If a size is not specified,
+// the smallest integer type that will hold the value is used.  Negative
+// values may be created with a signed size specification by applying
+// twos-complement conversion (for example, 0xffs8 produces an 8-bit
+// signed integer equal to -1 and 0b10000000s8 produces an 8-bit signed
+// integer equal to -128).
+%}
+
+SIZE_SUFFIX        ([su](8|16|32|64))
+BINARY_BITS        (0[bB][01][01_]*)
+BINARY_NUMBER      ({BINARY_BITS}|{BINARY_BITS}{SIZE_SUFFIX})
+HEXADECIMAL_BITS   (0[xX][0-9a-fA-F][0-9a-fA-F_]*)
+HEXADECIMAL_NUMBER ({HEXADECIMAL_BITS}|{HEXADECIMAL_BITS}{SIZE_SUFFIX})
 
 ANY_EXCEPT_NL [^\r\n]
 ANY_INCLUDING_NL (.|{NL})
@@ -1027,7 +1083,8 @@
 <DQ_STRING_START>(\.\.\.){S}*{NL} {
     curr_lexer->lexer_debug ("<DQ_STRING_START>(\\.\\.\\.){S}*{NL}");
 
-    static const char *msg = "'...' continuations in double-quoted character strings are obsolete and will not be allowed in a future version of Octave; please use '\\' instead";
+    /* FIXME: Remove support for '...' continuation in Octave 9 */
+    static const char *msg = "'...' continuations in double-quoted character strings were deprecated in version 7 and will not be allowed in a future version of Octave; please use '\\' instead";
 
     std::string nm = curr_lexer->m_fcn_file_full_name;
 
@@ -1044,7 +1101,8 @@
 <DQ_STRING_START>\\{S}+{NL} {
     curr_lexer->lexer_debug ("<DQ_STRING_START>\\\\{S}+{NL}");
 
-    static const char *msg = "white space and comments after continuation markers in double-quoted character strings are obsolete and will not be allowed in a future version of Octave";
+    /* FIXME: Remove support for WS after line continuation in Octave 9 */
+    static const char *msg = "whitespace after continuation markers in double-quoted character strings were deprecated in version 7 and will not be allowed in a future version of Octave";
 
     std::string nm = curr_lexer->m_fcn_file_full_name;
 
@@ -1205,72 +1263,24 @@
     curr_lexer->pop_start_state ();
   }
 
-%{
-// Imaginary numbers.
-%}
-
-{NUMBER}{Im} {
-    curr_lexer->lexer_debug ("{NUMBER}{Im}");
-
-    if (curr_lexer->previous_token_may_be_command ()
-        &&  curr_lexer->space_follows_previous_token ())
-      {
-        yyless (0);
-        curr_lexer->push_start_state (COMMAND_START);
-      }
-    else
-      {
-        int tok = curr_lexer->previous_token_value ();
-
-        if (curr_lexer->whitespace_is_significant ()
-            && curr_lexer->space_follows_previous_token ()
-            && ! (tok == '[' || tok == '{'
-                  || curr_lexer->previous_token_is_binop ()))
-          {
-            yyless (0);
-            curr_lexer->xunput (',');
-          }
-        else
-          {
-            curr_lexer->handle_number ();
-            return curr_lexer->count_token_internal (IMAG_NUM);
-          }
-      }
+{BINARY_NUMBER} {
+    HANDLE_NUMBER ("{BINARY_NUMBER}", 2);
   }
 
 %{
-// Real numbers.  Don't grab the '.' part of a dot operator as part of
-// the constant.
+// Decimal numbers.  For expressions that are just digits followed
+// directly by an element-by-element operator, don't grab the '.'
+// part of the operator as part of the constant (for example, in an
+// expression like "13./x").
 %}
 
-{D}{D_}*/\.[\*/\\^\'] |
-{NUMBER} {
-    curr_lexer->lexer_debug ("{D}{D_}*/\\.[\\*/\\\\^\\']|{NUMBER}");
-
-    if (curr_lexer->previous_token_may_be_command ()
-        &&  curr_lexer->space_follows_previous_token ())
-      {
-        yyless (0);
-        curr_lexer->push_start_state (COMMAND_START);
-      }
-    else
-      {
-        int tok = curr_lexer->previous_token_value ();
-
-        if (curr_lexer->whitespace_is_significant ()
-            && curr_lexer->space_follows_previous_token ()
-            && ! (tok == '[' || tok == '{'
-                  || curr_lexer->previous_token_is_binop ()))
-          {
-            yyless (0);
-            curr_lexer->xunput (',');
-          }
-        else
-          {
-            curr_lexer->handle_number ();
-            return curr_lexer->count_token_internal (NUM);
-          }
-      }
+{DECIMAL_DIGITS}/\.[\*/\\^\'] |
+{DECIMAL_NUMBER} {
+    HANDLE_NUMBER ("{DECIMAL_DIGITS}/\\.[\\*/\\\\^\\']|{DECIMAL_NUMBER}", 10);
+  }
+
+{HEXADECIMAL_NUMBER} {
+    HANDLE_NUMBER ("{HEXADECIMAL_NUMBER}", 16);
   }
 
 %{
@@ -1302,7 +1312,8 @@
 \\{S}*{CCHAR}{ANY_EXCEPT_NL}*{NL} {
     curr_lexer->lexer_debug ("\\\\{S}*{NL}|\\\\{S}*{CCHAR}{ANY_EXCEPT_NL}*{NL}");
 
-    static const char *msg = "using continuation marker \\ outside of double quoted strings is deprecated and will be removed from a future version of Octave, use ... instead";
+    /* FIXME: Remove support for '\\' line continuation in Octave 9 */
+    static const char *msg = "using continuation marker \\ outside of double quoted strings was deprecated in version 7 and will be removed from a future version of Octave, use ... instead";
 
     std::string nm = curr_lexer->m_fcn_file_full_name;
 
@@ -2519,7 +2530,7 @@
 
     if (m_block_comment_nesting_level != 0)
       {
-        warning ("block comment open at end of input");
+        warning ("block comment unterminated at end of input");
 
         if ((m_reading_fcn_file || m_reading_script_file || m_reading_classdef_file)
             && ! m_fcn_file_name.empty ())
@@ -2784,7 +2795,6 @@
         m_at_beginning_of_statement = true;
         break;
 
-
       case for_kw:
       case parfor_kw:
       case while_kw:
@@ -2865,6 +2875,15 @@
           }
         break;
 
+      case spmd_kw:
+        m_at_beginning_of_statement = true;
+        break;
+
+      case endspmd_kw:
+        tok_val = new token (endspmd_kw, token::spmd_end, m_tok_beg, m_tok_end);
+        m_at_beginning_of_statement = true;
+        break;
+
       case magic_file_kw:
         {
           if ((m_reading_fcn_file || m_reading_script_file
@@ -2880,8 +2899,9 @@
       case magic_line_kw:
         {
           int l = m_tok_beg.line ();
-          tok_val = new token (magic_line_kw, static_cast<double> (l),
-                               "", m_tok_beg, m_tok_end);
+          octave_value ov_value (static_cast<double> (l));
+          tok_val = new token (magic_line_kw, ov_value, "",
+                               m_tok_beg, m_tok_end);
         }
         break;
 
@@ -2946,76 +2966,340 @@
   return (len > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
 }
 
+static inline octave_value
+make_integer_value (uintmax_t long_int_val, bool unsigned_val, int bytes)
+{
+  if (unsigned_val)
+    {
+     switch (bytes)
+       {
+       case 1:
+         return octave_value (octave_uint8 (long_int_val));
+
+       case 2:
+         return octave_value (octave_uint16 (long_int_val));
+
+       case 4:
+         return octave_value (octave_uint32 (long_int_val));
+
+       case 8:
+         return octave_value (octave_uint64 (long_int_val));
+
+       default:
+         panic_impossible ();
+       };
+    }
+  else
+    {
+      // FIXME: Conversion to signed values is supposed to follow
+      // twos-complement rules.  Do we need to be more carefule here?
+
+      switch (bytes)
+        {
+        case 1:
+          return octave_value (octave_int8 (int8_t (long_int_val)));
+
+        case 2:
+          return octave_value (octave_int16 (int16_t (long_int_val)));
+
+        case 4:
+          return octave_value (octave_int32 (int32_t (long_int_val)));
+
+        case 8:
+        return octave_value (octave_int64 (int64_t (long_int_val)));
+
+        default:
+          panic_impossible ();
+        };
+    }
+
+  return octave_value ();
+}
+
 namespace octave
 {
-  void
-  base_lexer::handle_number (void)
+  template <>
+  int
+  base_lexer::handle_number<2> (void)
   {
-    double value = 0.0;
-    int nread = 0;
-
-    char *yytxt = flex_yytext ();
-
-    // Strip any underscores
-    char *tmptxt = strsave (yytxt);
-    char *rptr = tmptxt;
-    char *wptr = tmptxt;
-    while (*rptr)
-      {
-        *wptr = *rptr++;
-        wptr += (*wptr != '_');
-      }
-    *wptr = '\0';
-
-    if (looks_like_hex (tmptxt, strlen (tmptxt)))
+    // Skip 0[bB] prefix.
+    std::string yytxt (flex_yytext () + 2);
+
+    yytxt.erase (std::remove (yytxt.begin (), yytxt.end (), '_'),
+                 yytxt.end ());
+
+    std::size_t pos = yytxt.find_first_of ("su");
+
+    bool unsigned_val = true;
+    int bytes = -1;
+
+    if (pos == std::string::npos)
       {
-        uintmax_t long_int_value;
-
-        nread = sscanf (tmptxt, "%jx", &long_int_value);
-
-        value = static_cast<double> (long_int_value);
-      }
-    else if (looks_like_bin (tmptxt, strlen (tmptxt)))
-      {
-        uintmax_t long_int_value = 0;
-
-        for (std::size_t i = 0; i < strlen (tmptxt); i++)
-          {
-            if (tmptxt[i] == '0')
-              long_int_value <<= 1;
-            else if (tmptxt[i] == '1')
-            {
-              long_int_value <<= 1;
-              long_int_value += 1;
-            }
-          }
-
-        value = static_cast<double> (long_int_value);
-
-        nread = 1;  // Just to pass the assert stmt below
+        std::size_t num_digits = yytxt.length ();
+
+        if (num_digits <= 8)
+          bytes = 1;
+        else if (num_digits <= 16)
+          bytes = 2;
+        else if (num_digits <= 32)
+          bytes = 4;
+        else if (num_digits <= 64)
+          bytes = 8;
       }
     else
       {
-        char *idx = strpbrk (tmptxt, "Dd");
-
-        if (idx)
-          *idx = 'e';
-
-        nread = sscanf (tmptxt, "%lf", &value);
+        unsigned_val = (yytxt[pos] == 'u');
+        std::string size_str = yytxt.substr (pos+1);
+        yytxt = yytxt.substr (0, pos);
+        std::size_t num_digits = yytxt.length ();
+
+        if (size_str == "8" && num_digits <= 8)
+          bytes = 1;
+        else if (size_str == "16" && num_digits <= 16)
+          bytes = 2;
+        else if (size_str == "32" && num_digits <= 32)
+          bytes = 4;
+        else if (size_str == "64" && num_digits <= 64)
+          bytes = 8;
       }
 
-    delete [] tmptxt;
-
-    // If yytext doesn't contain a valid number, we are in deep doo doo.
-
-    assert (nread == 1);
+    if (bytes < 0)
+      {
+        token *tok
+          = new token (LEXICAL_ERROR,
+                       "too many digits for binary constant",
+                       m_tok_beg, m_tok_end);
+
+        push_token (tok);
+
+        return count_token_internal (LEXICAL_ERROR);
+      }
+
+    // FIXME: is there a better way?  Can uintmax_t be anything other
+    // than long or long long?  Should we just be using uint64_t instead
+    // of uintmax_t?
+
+    errno = 0;
+    char *end;
+    uintmax_t long_int_val;
+    if (sizeof (uintmax_t) == sizeof (unsigned long long))
+      long_int_val = strtoull (yytxt.c_str (), &end, 2);
+    else if (sizeof (uintmax_t) == sizeof (unsigned long))
+      long_int_val = strtoul (yytxt.c_str (), &end, 2);
+    else
+      panic_impossible ();
+
+    if (errno == ERANGE)
+      panic_impossible ();
+
+    octave_value ov_value
+      = make_integer_value (long_int_val, unsigned_val, bytes);
 
     m_looking_for_object_index = false;
     m_at_beginning_of_statement = false;
 
     update_token_positions (flex_yyleng ());
 
-    push_token (new token (NUM, value, yytxt, m_tok_beg, m_tok_end));
+    push_token (new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end));
+
+    return count_token_internal (NUMBER);
+  }
+
+  static uint64_t
+  flintmax (void)
+  {
+    return (static_cast<uint64_t> (1) << std::numeric_limits<double>::digits);
+  }
+
+  template <>
+  int
+  base_lexer::handle_number<10> (void)
+  {
+    bool imag = false;
+    bool digits_only = true;
+
+    char *yytxt = flex_yytext ();
+    std::size_t yylng = flex_yyleng ();
+
+    OCTAVE_LOCAL_BUFFER (char, tmptxt, yylng + 1);
+    char *rp = yytxt;
+    char *p = &tmptxt[0];
+
+    char ch;
+    while ((ch = *rp++))
+      {
+        switch (ch)
+          {
+          case '_':
+            break;
+
+          case 'D':
+          case 'd':
+            *p++ = 'e';
+            digits_only = false;
+            break;
+
+          case 'I':
+          case 'J':
+          case 'i':
+          case 'j':
+            // Octave does not provide imaginary integers.
+            digits_only = false;
+            imag = true;
+            break;
+
+          case '+':
+          case '-':
+          case '.':
+          case 'E':
+          case 'e':
+            digits_only = false;
+            *p++ = ch;
+            break;
+
+          default:
+            *p++ = ch;
+            break;
+          }
+      }
+
+    *p = '\0';
+
+    double value = 0.0;
+    int nread = 0;
+
+    nread = sscanf (tmptxt, "%lf", &value);
+
+    // If yytext doesn't contain a valid number, we are in deep doo doo.
+
+    assert (nread == 1);
+
+    octave_value ov_value;
+
+    // Use >= because > will not return true until value is greater than
+    // flintmax + 2!
+
+    if (digits_only && value >= flintmax ())
+      {
+        // Try reading as an unsigned 64-bit integer.  If there is a
+        // range error, then create a double value.  Otherwise, create a
+        // special uint64 object that will be automatically converted to
+        // double unless it appears as the argument to one of the int64
+        // or uint64 functions.
+
+        errno = 0;
+        char *end;
+        uintmax_t long_int_val;
+        if (sizeof (uintmax_t) == sizeof (unsigned long long))
+          long_int_val = strtoull (tmptxt, &end, 10);
+        else if (sizeof (uintmax_t) == sizeof (unsigned long))
+          long_int_val = strtoul (tmptxt, &end, 10);
+        else
+          panic_impossible ();
+
+        if (errno != ERANGE)
+          {
+            // If possible, store the value as a signed integer.
+
+            octave_base_value *magic_int;
+            if (long_int_val > std::numeric_limits<int64_t>::max ())
+              magic_int = new octave_magic_uint (octave_uint64 (long_int_val));
+            else
+              magic_int = new octave_magic_int (octave_int64 (long_int_val));
+
+            ov_value = octave_value (magic_int);
+          }
+      }
+
+    m_looking_for_object_index = false;
+    m_at_beginning_of_statement = false;
+
+    update_token_positions (yylng);
+
+    if (ov_value.is_undefined ())
+      ov_value = (imag
+                  ? octave_value (Complex (0.0, value))
+                  : octave_value (value));
+
+    push_token (new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end));
+
+    return count_token_internal (NUMBER);
+  }
+
+  template <>
+  int
+  base_lexer::handle_number<16> (void)
+  {
+    // Skip 0[xX] prefix.
+    std::string yytxt (flex_yytext () + 2);
+
+    yytxt.erase (std::remove (yytxt.begin (), yytxt.end (), '_'),
+                 yytxt.end ());
+
+    std::size_t pos = yytxt.find_first_of ("su");
+
+    bool unsigned_val = true;
+    int bytes = -1;
+
+    if (pos == std::string::npos)
+      {
+        std::size_t num_digits = yytxt.length ();
+
+        if (num_digits <= 2)
+          bytes = 1;
+        else if (num_digits <= 4)
+          bytes = 2;
+        else if (num_digits <= 8)
+          bytes = 4;
+        else if (num_digits <= 16)
+          bytes = 8;
+      }
+    else
+      {
+        unsigned_val = (yytxt[pos] == 'u');
+        std::string size_str = yytxt.substr (pos+1);
+        yytxt = yytxt.substr (0, pos);
+        std::size_t num_digits = yytxt.length ();
+
+        if (size_str == "8" && num_digits <= 2)
+          bytes = 1;
+        else if (size_str == "16" && num_digits <= 4)
+          bytes = 2;
+        else if (size_str == "32" && num_digits <= 8)
+          bytes = 4;
+        else if (size_str == "64" && num_digits <= 16)
+          bytes = 8;
+      }
+
+    if (bytes < 0)
+      {
+        token *tok
+          = new token (LEXICAL_ERROR,
+                       "too many digits for hexadecimal constant",
+                       m_tok_beg, m_tok_end);
+
+        push_token (tok);
+
+        return count_token_internal (LEXICAL_ERROR);
+      }
+
+    // Assert here because if yytext doesn't contain a valid number, we
+    // are in deep doo doo.
+
+    uintmax_t long_int_val;
+    assert (sscanf (yytxt.c_str (), "%jx", &long_int_val));
+
+    octave_value ov_value
+      = make_integer_value (long_int_val, unsigned_val, bytes);
+
+    m_looking_for_object_index = false;
+    m_at_beginning_of_statement = false;
+
+    update_token_positions (flex_yyleng ());
+
+    push_token (new token (NUMBER, ov_value, yytxt, m_tok_beg, m_tok_end));
+
+    return count_token_internal (NUMBER);
   }
 
   void
@@ -3444,12 +3728,13 @@
       case POW: std::cerr << "POW\n"; break;
       case EPOW: std::cerr << "EPOW\n"; break;
 
-      case NUM:
-      case IMAG_NUM:
+      case NUMBER:
         {
           token *tok_val = current_token ();
-          std::cerr << (tok == NUM ? "NUM" : "IMAG_NUM")
-                    << " [" << tok_val->number () << "]\n";
+          std::cerr << "NUMBER [";
+          octave_value num = tok_val->number ();
+          num.print_raw (std::cerr);
+          std::cerr << "]\n";
         }
         break;
 
--- a/libinterp/parse-tree/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -38,6 +38,7 @@
   %reldir%/pt-misc.h \
   %reldir%/pt-pr-code.h \
   %reldir%/pt-select.h \
+  %reldir%/pt-spmd.h \
   %reldir%/pt-stmt.h \
   %reldir%/pt-tm-const.h \
   %reldir%/pt-unop.h \
@@ -87,6 +88,7 @@
   %reldir%/pt-misc.cc \
   %reldir%/pt-pr-code.cc \
   %reldir%/pt-select.cc \
+  %reldir%/pt-spmd.cc \
   %reldir%/pt-stmt.cc \
   %reldir%/pt-tm-const.cc \
   %reldir%/pt-unop.cc \
--- a/libinterp/parse-tree/oct-lvalue.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/oct-lvalue.cc	Sun May 16 09:44:35 2021 +0200
@@ -206,10 +206,10 @@
     return retval;
   }
 
-  void octave_lvalue::do_unary_op (octave_value::unary_op op)
+  void octave_lvalue::unary_op (octave_value::unary_op op)
   {
     if (! is_black_hole ())
-      m_frame->do_non_const_unary_op (op, m_sym, m_type, m_idx);
+      m_frame->non_const_unary_op (op, m_sym, m_type, m_idx);
   }
 
   octave_value octave_lvalue::value (void) const
--- a/libinterp/parse-tree/oct-lvalue.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/oct-lvalue.h	Sun May 16 09:44:35 2021 +0200
@@ -78,7 +78,13 @@
 
     bool index_is_colon (void) const;
 
-    void do_unary_op (octave_value::unary_op op);
+    void unary_op (octave_value::unary_op op);
+
+    OCTAVE_DEPRECATED (7, "use 'octave_lvalue::unary_op' instead")
+    void do_unary_op (octave_value::unary_op op)
+    {
+      return unary_op (op);
+    }
 
     octave_value value (void) const;
 
--- a/libinterp/parse-tree/oct-parse.yy	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/oct-parse.yy	Sun May 16 09:44:35 2021 +0200
@@ -207,12 +207,13 @@
 %token <tok_val> LEFTDIV EMUL EDIV ELEFTDIV EPLUS EMINUS
 %token <tok_val> HERMITIAN TRANSPOSE
 %token <tok_val> PLUS_PLUS MINUS_MINUS POW EPOW
-%token <tok_val> NUM IMAG_NUM
+%token <tok_val> NUMBER
 %token <tok_val> STRUCT_ELT
 %token <tok_val> NAME
 %token <tok_val> END
 %token <tok_val> DQ_STRING SQ_STRING
 %token <tok_val> FOR PARFOR WHILE DO UNTIL
+%token <tok_val> SPMD
 %token <tok_val> IF ELSEIF ELSE
 %token <tok_val> SWITCH CASE OTHERWISE
 %token <tok_val> BREAK CONTINUE FUNC_RET
@@ -261,7 +262,7 @@
 %type <tree_parameter_list_type> param_list1 param_list2
 %type <tree_parameter_list_type> return_list return_list1
 %type <tree_command_type> command select_command loop_command
-%type <tree_command_type> jump_command except_command
+%type <tree_command_type> jump_command spmd_command except_command
 %type <tree_function_def_type> function
 %type <tree_classdef_type> classdef
 %type <tree_command_type> file
@@ -548,10 +549,8 @@
                   { $$ = parser.make_constant (SQ_STRING, $1); }
                 ;
 
-constant        : NUM
-                  { $$ = parser.make_constant (NUM, $1); }
-                | IMAG_NUM
-                  { $$ = parser.make_constant (IMAG_NUM, $1); }
+constant        : NUMBER
+                  { $$ = parser.make_constant (NUMBER, $1); }
                 | string
                   { $$ = $1; }
                 ;
@@ -1064,6 +1063,8 @@
                   { $$ = $1; }
                 | jump_command
                   { $$ = $1; }
+                | spmd_command
+                  { $$ = $1; }
                 | except_command
                   { $$ = $1; }
                 | function
@@ -1334,6 +1335,25 @@
                   { $$ = parser.make_return_command ($1); }
                 ;
 
+// =======================
+// Parallel execution pool
+// =======================
+
+spmd_command    : SPMD stash_comment opt_sep opt_list END
+                  {
+                    OCTAVE_YYUSE ($3);
+
+                    octave::comment_list *lc = $2;
+                    octave::comment_list *tc = lexer.get_comment ();
+
+                    if (! ($$ = parser.make_spmd_command ($1, $4, $5, lc, tc)))
+                      {
+                        // make_spmd_command deleted $4, LC, and TC.
+                        YYABORT;
+                      }
+                  }
+                ;
+
 // ==========
 // Exceptions
 // ==========
@@ -2475,6 +2495,10 @@
         retval = "endproperties";
         break;
 
+      case token::spmd_end:
+        retval = "endspmd";
+        break;
+
       case token::switch_end:
         retval = "endswitch";
         break;
@@ -2548,7 +2572,7 @@
       m_max_fcn_depth = m_curr_fcn_depth;
 
     // Will get a real name later.
-    m_lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_fcn_symtab"));
+    m_lexer.m_symtab_context.push (symbol_scope ("parser:push_fcn_symtab"));
     m_function_scopes.push (m_lexer.m_symtab_context.curr_scope ());
 
     if (! m_lexer.m_reading_script_file && m_curr_fcn_depth == 0
@@ -2580,18 +2604,9 @@
 
     switch (op)
       {
-      case NUM:
+      case NUMBER:
         {
-          octave_value tmp (tok_val->number ());
-          retval = new tree_constant (tmp, l, c);
-          retval->stash_original_text (tok_val->text_rep ());
-        }
-        break;
-
-      case IMAG_NUM:
-        {
-          octave_value tmp (Complex (0.0, tok_val->number ()));
-          retval = new tree_constant (tmp, l, c);
+          retval = new tree_constant (tok_val->number (), l, c);
           retval->stash_original_text (tok_val->text_rep ());
         }
         break;
@@ -2747,15 +2762,15 @@
             // the previous value of last_warning_message and skip the
             // conversion to a constant value.
 
-            unwind_protect frame;
-
             error_system& es = interp.get_error_system ();
 
-            frame.add_method (es, &error_system::set_last_warning_message,
-                              es.last_warning_message (""));
-
-            frame.add_method (es, &error_system::set_discard_warning_messages,
-                              es.discard_warning_messages (true));
+            unwind_action restore_last_warning_message
+              (&error_system::set_last_warning_message, &es,
+               es.last_warning_message (""));
+
+            unwind_action restore_discard_warning_messages
+              (&error_system::set_discard_warning_messages, &es,
+               es.discard_warning_messages (true));
 
             tree_evaluator& tw = interp.get_evaluator ();
 
@@ -3241,6 +3256,34 @@
     return new tree_return_command (l, c);
   }
 
+  // Build an spmd command.
+
+  tree_spmd_command *
+  base_parser::make_spmd_command (token *spmd_tok, tree_statement_list *body,
+                                  token *end_tok, comment_list *lc,
+                                  comment_list *tc)
+  {
+    tree_spmd_command *retval = nullptr;
+
+    if (end_token_ok (end_tok, token::spmd_end))
+      {
+        int l = spmd_tok->line ();
+        int c = spmd_tok->column ();
+
+        retval = new tree_spmd_command (body, lc, tc, l, c);
+      }
+    else
+      {
+        delete body;
+        delete lc;
+        delete tc;
+
+        end_token_error (end_tok, token::spmd_end);
+      }
+
+    return retval;
+  }
+
   // Start an if command.
 
   tree_if_command_list *
@@ -3551,7 +3594,7 @@
         return nullptr;
       }
 
-    octave::symbol_scope curr_scope = m_lexer.m_symtab_context.curr_scope ();
+    symbol_scope curr_scope = m_lexer.m_symtab_context.curr_scope ();
     curr_scope.cache_name (id_name);
 
     m_lexer.m_parsed_function_name.top () = true;
@@ -4386,6 +4429,12 @@
                     return false;
                   }
               }
+            else if (iskeyword (name))
+              {
+                bison_error ("invalid use of keyword '" + name
+                             + "' in parameter list");
+                return false;
+              }
             else if (dict.find (name) != dict.end ())
               {
                 bison_error ("'" + name
@@ -4529,15 +4578,15 @@
             // the previous value of last_warning_message and skip the
             // conversion to a constant value.
 
-            unwind_protect frame;
-
             error_system& es = interp.get_error_system ();
 
-            frame.add_method (es, &error_system::set_last_warning_message,
-                              es.last_warning_message (""));
-
-            frame.add_method (es, &error_system::set_discard_warning_messages,
-                              es.discard_warning_messages (true));
+            unwind_action restore_last_warning_message
+              (&error_system::set_last_warning_message, &es,
+               es.last_warning_message (""));
+
+            unwind_action restore_discard_warning_messages
+              (&error_system::set_discard_warning_messages, &es,
+               es.discard_warning_messages (true));
 
             tree_evaluator& tw = interp.get_evaluator ();
 
@@ -4935,7 +4984,20 @@
     FILE *ffile = nullptr;
 
     if (! full_file.empty ())
+    {
+      // Check that m-file is not overly large which can segfault interpreter.
+      const int max_file_size = 512 * 1024 * 1024;  // 512 MB
+      sys::file_stat fs (full_file);
+
+      if (fs && fs.size () > max_file_size)
+        {
+          error ("file '%s' is too large, > 512 MB", full_file.c_str ());
+
+          return octave_value ();
+        }
+
       ffile = sys::fopen (full_file, "rb");
+    }
 
     if (! ffile)
       {
@@ -4945,12 +5007,11 @@
         return octave_value ();
       }
 
-    unwind_action act ([ffile] (void)
-                       {
-                         fclose (ffile);
-                       });
-
-    parser parser (ffile, interp);
+    unwind_action act ([=] (void) { ::fclose (ffile); });
+
+    // get the encoding for this folder
+    octave::input_system& input_sys = interp.get_input_system ();
+    parser parser (ffile, interp, input_sys.dir_encoding (dir_name));
 
     parser.m_curr_class_name = dispatch_type;
     parser.m_curr_package_name = package_name;
@@ -5510,23 +5571,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)
   {
@@ -5764,7 +5808,7 @@
   // the eval, then the message is stored in the exception object and we
   // will display it later, after the buffers have been restored.
 
-  octave::unwind_action act ([old_out_buf, old_err_buf] (void)
+  octave::unwind_action act ([=] (void)
                              {
                                octave_stdout.rdbuf (old_out_buf);
                                std::cerr.rdbuf (old_err_buf);
@@ -5904,10 +5948,10 @@
   if (nargin < 1 || nargin > 2)
     print_usage ();
 
-  std::string file = args(0).xstring_value ("__parse_file__: expecting filename as argument");
-
-  std::string full_file
-      = octave::sys::file_ops::tilde_expand (file);
+  std::string file
+    = args(0).xstring_value ("__parse_file__: expecting filename as argument");
+
+  std::string full_file = octave::sys::file_ops::tilde_expand (file);
 
   full_file = octave::sys::env::make_absolute (full_file);
 
--- a/libinterp/parse-tree/octave.gperf	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/octave.gperf	Sun May 16 09:44:35 2021 +0200
@@ -51,6 +51,7 @@
   endmethods_kw,
   endparfor_kw,
   endproperties_kw,
+  endspmd_kw,
   endswitch_kw,
   endwhile_kw,
   enumeration_kw,
@@ -69,6 +70,7 @@
   properties_kw,
   return_kw,
   set_kw,
+  spmd_kw,
   switch_kw,
   try_kw,
   until_kw,
@@ -102,6 +104,7 @@
 endmethods, END, endmethods_kw
 endparfor, END, endparfor_kw
 endproperties, END, endproperties_kw
+endspmd, END, endspmd_kw
 endswitch, END, endswitch_kw
 endwhile, END, endwhile_kw
 enumeration, ENUMERATION, enumeration_kw
@@ -118,6 +121,7 @@
 properties, PROPERTIES, properties_kw
 return, FUNC_RET, return_kw
 set, SET, set_kw
+spmd, SPMD, spmd_kw
 switch, SWITCH, switch_kw
 try, TRY, try_kw
 until, UNTIL, until_kw
@@ -125,4 +129,4 @@
 unwind_protect_cleanup, CLEANUP, unwind_protect_cleanup_kw
 while, WHILE, while_kw
 __FILE__, DQ_STRING, magic_file_kw
-__LINE__, NUM, magic_line_kw
+__LINE__, NUMBER, magic_line_kw
--- a/libinterp/parse-tree/parse.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/parse.h	Sun May 16 09:44:35 2021 +0200
@@ -81,6 +81,7 @@
   class tree_matrix;
   class tree_matrix;
   class tree_parameter_list;
+  class tree_spmd_command;
   class tree_statement;
   class tree_statement_list;
   class tree_statement_listtree_statement;
@@ -126,23 +127,23 @@
 
       ~parent_scope_info (void) = default;
 
-      std::size_t size (void) const;
+      OCTINTERP_API std::size_t size (void) const;
 
-      void push (const value_type& elt);
+      OCTINTERP_API void push (const value_type& elt);
 
-      void push (const symbol_scope& id);
+      OCTINTERP_API void push (const symbol_scope& id);
 
-      void pop (void);
+      OCTINTERP_API void pop (void);
 
-      bool name_ok (const std::string& name);
+      OCTINTERP_API bool name_ok (const std::string& name);
 
-      bool name_current_scope (const std::string& name);
+      OCTINTERP_API bool name_current_scope (const std::string& name);
 
-      symbol_scope parent_scope (void) const;
+      OCTINTERP_API symbol_scope parent_scope (void) const;
 
-      std::string parent_name (void) const;
+      OCTINTERP_API std::string parent_name (void) const;
 
-      void clear (void);
+      OCTINTERP_API void clear (void);
 
     private:
 
@@ -153,7 +154,7 @@
 
   public:
 
-    base_parser (base_lexer& lxr);
+    OCTINTERP_API base_parser (base_lexer& lxr);
 
     // No copying!
 
@@ -161,13 +162,13 @@
 
     base_parser& operator = (const base_parser&) = delete;
 
-    ~base_parser (void);
+    virtual ~base_parser (void);
 
     base_lexer& get_lexer (void) const { return m_lexer; }
 
     bool at_end_of_input (void) const { return m_lexer.m_end_of_input; }
 
-    void reset (void);
+    OCTINTERP_API void reset (void);
 
     void classdef_object (const std::shared_ptr<tree_classdef>& obj)
     {
@@ -179,7 +180,7 @@
       return m_classdef_object;
     }
 
-    void statement_list (std::shared_ptr<tree_statement_list>& lst);
+    OCTINTERP_API void statement_list (std::shared_ptr<tree_statement_list>& lst);
 
     std::shared_ptr<tree_statement_list> statement_list (void) const
     {
@@ -222,268 +223,281 @@
     }
 
     // Error messages for mismatched end tokens.
-    void end_token_error (token *tok, token::end_tok_type expected);
+    OCTINTERP_API void
+    end_token_error (token *tok, token::end_tok_type expected);
 
     // Check to see that end tokens are properly matched.
-    bool end_token_ok (token *tok, token::end_tok_type expected);
+    OCTINTERP_API bool end_token_ok (token *tok, token::end_tok_type expected);
 
     // Handle pushing symbol table for new function scope.
-    bool push_fcn_symtab (void);
+    OCTINTERP_API bool push_fcn_symtab (void);
 
     // Build a constant.
-    tree_constant * make_constant (int op, token *tok_val);
+    OCTINTERP_API tree_constant * make_constant (int op, token *tok_val);
 
     // Build a function handle.
-    tree_fcn_handle * make_fcn_handle (token *tok_val);
+    OCTINTERP_API tree_fcn_handle * make_fcn_handle (token *tok_val);
 
     // Build an anonymous function handle.
-    tree_anon_fcn_handle *
+    OCTINTERP_API tree_anon_fcn_handle *
     make_anon_fcn_handle (tree_parameter_list *param_list,
                           tree_expression * expr, const filepos& at_pos);
 
     // Build a colon expression.
-    tree_expression *
+    OCTINTERP_API tree_expression *
     make_colon_expression (tree_expression *base, tree_expression *limit,
                            tree_expression *incr = nullptr);
 
     // Build a binary expression.
-    tree_expression *
+    OCTINTERP_API tree_expression *
     make_binary_op (int op, tree_expression *op1, token *tok_val,
                     tree_expression *op2);
 
     // Build a boolean expression.
-    tree_expression *
+    OCTINTERP_API tree_expression *
     make_boolean_op (int op, tree_expression *op1, token *tok_val,
                      tree_expression *op2);
 
     // Build a prefix expression.
-    tree_expression *
+    OCTINTERP_API tree_expression *
     make_prefix_op (int op, tree_expression *op1, token *tok_val);
 
     // Build a postfix expression.
-    tree_expression *
+    OCTINTERP_API tree_expression *
     make_postfix_op (int op, tree_expression *op1, token *tok_val);
 
     // Build an unwind-protect command.
-    tree_command *
+    OCTINTERP_API tree_command *
     make_unwind_command (token *unwind_tok, tree_statement_list *body,
                          tree_statement_list *cleanup, token *end_tok,
                          comment_list *lc, comment_list *mc);
 
     // Build a try-catch command.
-    tree_command *
+    OCTINTERP_API tree_command *
     make_try_command (token *try_tok, tree_statement_list *body,
                       char catch_sep, tree_statement_list *cleanup,
                       token *end_tok, comment_list *lc,
                       comment_list *mc);
 
     // Build a while command.
-    tree_command *
+    OCTINTERP_API tree_command *
     make_while_command (token *while_tok, tree_expression *expr,
                         tree_statement_list *body, token *end_tok,
                         comment_list *lc);
 
     // Build a do-until command.
-    tree_command *
+    OCTINTERP_API tree_command *
     make_do_until_command (token *until_tok, tree_statement_list *body,
                            tree_expression *expr, comment_list *lc);
 
     // Build a for command.
-    tree_command *
+    OCTINTERP_API tree_command *
     make_for_command (int tok_id, token *for_tok, tree_argument_list *lhs,
                       tree_expression *expr, tree_expression *maxproc,
                       tree_statement_list *body, token *end_tok,
                       comment_list *lc);
 
     // Build a break command.
-    tree_command * make_break_command (token *break_tok);
+    OCTINTERP_API tree_command * make_break_command (token *break_tok);
 
     // Build a continue command.
-    tree_command * make_continue_command (token *continue_tok);
+    OCTINTERP_API tree_command * make_continue_command (token *continue_tok);
 
     // Build a return command.
-    tree_command * make_return_command (token *return_tok);
+    OCTINTERP_API tree_command * make_return_command (token *return_tok);
+
+    // Build an spmd command.
+
+    OCTINTERP_API tree_spmd_command *
+    make_spmd_command (token *spmd_tok, tree_statement_list *body,
+                       token *end_tok, comment_list *lc, comment_list *tc);
 
     // Start an if command.
-    tree_if_command_list *
+    OCTINTERP_API tree_if_command_list *
     start_if_command (tree_expression *expr, tree_statement_list *list);
 
     // Finish an if command.
-    tree_if_command *
+    OCTINTERP_API tree_if_command *
     finish_if_command (token *if_tok, tree_if_command_list *list,
                        token *end_tok, comment_list *lc);
 
     // Build an elseif clause.
-    tree_if_clause *
+    OCTINTERP_API tree_if_clause *
     make_elseif_clause (token *elseif_tok, tree_expression *expr,
                         tree_statement_list *list, comment_list *lc);
 
     // Finish a switch command.
-    tree_switch_command *
+    OCTINTERP_API tree_switch_command *
     finish_switch_command (token *switch_tok, tree_expression *expr,
                            tree_switch_case_list *list, token *end_tok,
                            comment_list *lc);
 
     // Build a switch case.
-    tree_switch_case *
+    OCTINTERP_API tree_switch_case *
     make_switch_case (token *case_tok, tree_expression *expr,
                       tree_statement_list *list, comment_list *lc);
 
     // Build an assignment to a variable.
-    tree_expression *
+    OCTINTERP_API tree_expression *
     make_assign_op (int op, tree_argument_list *lhs, token *eq_tok,
                     tree_expression *rhs);
 
     // Define a script.
-    void make_script (tree_statement_list *cmds, tree_statement *end_script);
+    OCTINTERP_API void
+    make_script (tree_statement_list *cmds, tree_statement *end_script);
 
     // Handle identifier that is recognized as a function name.
-    tree_identifier *
+    OCTINTERP_API tree_identifier *
     make_fcn_name (tree_identifier *id);
 
     // Define a function.
-    tree_function_def *
+    OCTINTERP_API tree_function_def *
     make_function (token *fcn_tok, tree_parameter_list *ret_list,
                    tree_identifier *id, tree_parameter_list *param_list,
                    tree_statement_list *body, tree_statement *end_fcn_stmt,
                    comment_list *lc);
 
     // Begin defining a function.
-    octave_user_function *
+    OCTINTERP_API octave_user_function *
     start_function (tree_identifier *id, tree_parameter_list *param_list,
                     tree_statement_list *body, tree_statement *end_function);
 
     // Create a no-op statement for end_function.
-    tree_statement * make_end (const std::string& type, bool eof,
-                               const filepos& beg_pos, const filepos& end_pos);
+    OCTINTERP_API tree_statement *
+    make_end (const std::string& type, bool eof,
+              const filepos& beg_pos, const filepos& end_pos);
 
     // Do most of the work for defining a function.
-    octave_user_function *
+    OCTINTERP_API octave_user_function *
     frob_function (tree_identifier *id, octave_user_function *fcn);
 
     // Finish defining a function.
-    tree_function_def *
+    OCTINTERP_API tree_function_def *
     finish_function (tree_parameter_list *ret_list,
                      octave_user_function *fcn, comment_list *lc,
                      int l, int c);
 
     // Reset state after parsing function.
-    void
+    OCTINTERP_API void
     recover_from_parsing_function (void);
 
-    tree_classdef *
+    OCTINTERP_API tree_classdef *
     make_classdef (token *tok_val, tree_classdef_attribute_list *a,
                    tree_identifier *id, tree_classdef_superclass_list *sc,
                    tree_classdef_body *body, token *end_tok,
                    comment_list *lc, comment_list *tc);
 
-    tree_classdef_properties_block *
+    OCTINTERP_API tree_classdef_properties_block *
     make_classdef_properties_block (token *tok_val,
                                     tree_classdef_attribute_list *a,
                                     tree_classdef_property_list *plist,
                                     token *end_tok, comment_list *lc,
                                     comment_list *tc);
 
-    tree_classdef_methods_block *
+    OCTINTERP_API tree_classdef_methods_block *
     make_classdef_methods_block (token *tok_val,
                                  tree_classdef_attribute_list *a,
                                  tree_classdef_methods_list *mlist,
                                  token *end_tok, comment_list *lc,
                                  comment_list *tc);
 
-    tree_classdef_events_block *
+    OCTINTERP_API tree_classdef_events_block *
     make_classdef_events_block (token *tok_val,
                                 tree_classdef_attribute_list *a,
                                 tree_classdef_events_list *elist,
                                 token *end_tok, comment_list *lc,
                                 comment_list *tc);
 
-    tree_classdef_enum_block *
+    OCTINTERP_API tree_classdef_enum_block *
     make_classdef_enum_block (token *tok_val,
                               tree_classdef_attribute_list *a,
                               tree_classdef_enum_list *elist,
                               token *end_tok, comment_list *lc,
                               comment_list *tc);
 
-    octave_user_function *
+    OCTINTERP_API octave_user_function *
     start_classdef_external_method (tree_identifier *id,
                                     tree_parameter_list *pl);
 
-    tree_function_def *
+    OCTINTERP_API tree_function_def *
     finish_classdef_external_method (octave_user_function *fcn,
                                      tree_parameter_list *ret_list,
                                      comment_list *cl);
 
-    void
+    OCTINTERP_API void
     finish_classdef_file (tree_classdef *cls,
                           tree_statement_list *local_fcns);
 
     // Make an index expression.
-    tree_index_expression *
+    OCTINTERP_API tree_index_expression *
     make_index_expression (tree_expression *expr,
                            tree_argument_list *args, char type);
 
     // Make an indirect reference expression.
-    tree_index_expression *
+    OCTINTERP_API tree_index_expression *
     make_indirect_ref (tree_expression *expr, const std::string&);
 
     // Make an indirect reference expression with dynamic field name.
-    tree_index_expression *
+    OCTINTERP_API tree_index_expression *
     make_indirect_ref (tree_expression *expr, tree_expression *field);
 
     // Make a declaration command.
-    tree_decl_command *
+    OCTINTERP_API tree_decl_command *
     make_decl_command (int tok, token *tok_val, tree_decl_init_list *lst);
 
     // Validate an function parameter list.
-    bool validate_param_list (tree_parameter_list *lst,
-                              tree_parameter_list::in_or_out type);
+    OCTINTERP_API bool
+    validate_param_list (tree_parameter_list *lst,
+                         tree_parameter_list::in_or_out type);
     // Validate matrix or cell
-    bool validate_array_list (tree_expression *e);
+    OCTINTERP_API bool validate_array_list (tree_expression *e);
 
     // Validate matrix object used in "[lhs] = ..." assignments.
-    tree_argument_list * validate_matrix_for_assignment (tree_expression *e);
+    OCTINTERP_API tree_argument_list *
+    validate_matrix_for_assignment (tree_expression *e);
 
     // Finish building an array_list (common action for finish_matrix
     // and finish_cell).
-    tree_expression * finish_array_list (tree_array_list *a, token *open_delim,
-                                         token *close_delim);
+    OCTINTERP_API tree_expression *
+    finish_array_list (tree_array_list *a, token *open_delim,
+                       token *close_delim);
 
     // Finish building a matrix list.
-    tree_expression * finish_matrix (tree_matrix *m, token *open_delim,
-                                     token *close_delim);
+    OCTINTERP_API tree_expression *
+    finish_matrix (tree_matrix *m, token *open_delim, token *close_delim);
 
     // Finish building a cell list.
-    tree_expression * finish_cell (tree_cell *c, token *open_delim,
-                                   token *close_delim);
+    OCTINTERP_API tree_expression *
+    finish_cell (tree_cell *c, token *open_delim, token *close_delim);
 
     // Set the print flag for a statement based on the separator type.
-    tree_statement_list *
+    OCTINTERP_API tree_statement_list *
     set_stmt_print_flag (tree_statement_list *, char, bool);
 
     // Finish building a statement.
     template <typename T>
-    tree_statement * make_statement (T *arg);
+    OCTINTERP_API tree_statement * make_statement (T *arg);
 
     // Create a statement list.
-    tree_statement_list * make_statement_list (tree_statement *stmt);
+    OCTINTERP_API tree_statement_list *
+    make_statement_list (tree_statement *stmt);
 
     // Append a statement to an existing statement list.
-    tree_statement_list *
+    OCTINTERP_API tree_statement_list *
     append_statement_list (tree_statement_list *list, char sep,
                            tree_statement *stmt, bool warn_missing_semi);
 
     // Don't allow parsing command syntax.  If the parser/lexer is
     // reset, this setting is also reset to the default (allow command
     // syntax).
-    void disallow_command_syntax (void);
+    OCTINTERP_API void disallow_command_syntax (void);
 
     // Generic error messages.
-    void bison_error (const std::string& s);
-    void bison_error (const std::string& s, const filepos& pos);
-    void bison_error (const std::string& s, int line, int column);
+    OCTINTERP_API void bison_error (const std::string& s);
+    OCTINTERP_API void bison_error (const std::string& s, const filepos& pos);
+    OCTINTERP_API void bison_error (const std::string& s, int line, int column);
 
-    friend octave_value
+    friend OCTINTERP_API octave_value
     parse_fcn_file (interpreter& interp, const std::string& full_file,
                     const std::string& file, const std::string& dir_name,
                     const std::string& dispatch_type,
@@ -573,18 +587,18 @@
 
     // Maybe print a warning if an assignment expression is used as the
     // test in a logical expression.
-    void maybe_warn_assign_as_truth_value (tree_expression *expr);
+    OCTINTERP_API void maybe_warn_assign_as_truth_value (tree_expression *expr);
 
     // Maybe print a warning about switch labels that aren't constants.
-    void maybe_warn_variable_switch_label (tree_expression *expr);
+    OCTINTERP_API void maybe_warn_variable_switch_label (tree_expression *expr);
 
     // Maybe print a warning.
-    void maybe_warn_missing_semi (tree_statement_list *);
+    OCTINTERP_API void maybe_warn_missing_semi (tree_statement_list *);
   };
 
   // Publish externally used friend functions.
 
-  extern OCTAVE_API octave_value
+  extern OCTINTERP_API octave_value
   parse_fcn_file (interpreter& interp, const std::string& full_file,
                   const std::string& file, const std::string& dir_name,
                   const std::string& dispatch_type,
@@ -603,6 +617,10 @@
       : base_parser (*(new lexer (file, interp)))
     { }
 
+    parser (FILE *file, interpreter& interp, std::string encoding)
+      : base_parser (*(new lexer (file, interp, encoding)))
+    { }
+
     parser (const std::string& eval_string, interpreter& interp)
       : base_parser (*(new lexer (eval_string, interp)))
     { }
@@ -623,7 +641,7 @@
 
     ~parser (void) = default;
 
-    int run (void);
+    OCTINTERP_API int run (void);
   };
 
   class push_parser : public base_parser
@@ -655,12 +673,12 @@
     // parser arranges for input through the M_READER object.  See, for
     // example, interpreter::main_loop.
 
-    int run (void);
+    OCTINTERP_API int run (void);
 
     // Parse INPUT.  M_READER is not used.  The user is responsible for
     // collecting input.
 
-    int run (const std::string& input, bool eof);
+    OCTINTERP_API int run (const std::string& input, bool eof);
 
   private:
 
@@ -712,14 +730,6 @@
   extern OCTINTERP_API octave_value_list
   feval (const octave_value_list& args, int nargout = 0);
 
-  OCTAVE_DEPRECATED (5, "use 'octave::interpreter::eval_string' instead")
-  extern OCTINTERP_API octave_value_list
-  eval_string (const std::string&, bool silent, int& parse_status, int nargout);
-
-  OCTAVE_DEPRECATED (5, "use 'octave::interpreter::eval_string' instead")
-  extern OCTINTERP_API octave_value
-  eval_string (const std::string&, bool silent, int& parse_status);
-
   extern OCTINTERP_API void
   cleanup_statement_list (tree_statement_list **lst);
 }
--- a/libinterp/parse-tree/profiler.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/profiler.cc	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,7 @@
 #endif
 
 #include "defun.h"
+#include "event-manager.h"
 #include "interpreter.h"
 #include "oct-time.h"
 #include "ov-struct.h"
@@ -255,7 +256,7 @@
   profiler::reset (void)
   {
     if (enabled ())
-      error ("Can't reset active profiler.");
+      error ("profile: can't reset active profiler");
 
     m_known_functions.clear ();
     m_fcn_index.clear ();
@@ -397,7 +398,16 @@
   octave::profiler& profiler = interp.get_profiler ();
 
   if (nargin == 1)
-    profiler.set_active (args(0).bool_value ());
+    {
+      profiler.set_active (args(0).bool_value ());
+
+      std::string status = "off";
+      if (args(0).bool_value ())
+        status = "on";
+
+      octave::event_manager& evmgr = interp.get_event_manager ();
+      evmgr.gui_status_update ("profiler", status);  // tell GUI
+    }
 
   return ovl (profiler.enabled ());
 }
--- a/libinterp/parse-tree/pt-all.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-all.h	Sun May 16 09:44:35 2021 +0200
@@ -52,6 +52,7 @@
 #include "pt-misc.h"
 #include "pt-pr-code.h"
 #include "pt-select.h"
+#include "pt-spmd.h"
 #include "pt-stmt.h"
 #include "pt-unop.h"
 #include "pt-pr-code.h"
--- a/libinterp/parse-tree/pt-arg-list.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-arg-list.h	Sun May 16 09:44:35 2021 +0200
@@ -116,10 +116,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-// tree_argument_list is derived from a template.
-
 #endif
-
-#endif
--- a/libinterp/parse-tree/pt-assign.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-assign.cc	Sun May 16 09:44:35 2021 +0200
@@ -137,11 +137,11 @@
                 feval ("display", args);
               }
           }
-        catch (index_exception& e)
+        catch (index_exception& ie)
           {
-            e.set_var (m_lhs->name ());
-            std::string msg = e.message ();
-            error_with_id (e.err_id (), "%s", msg.c_str ());
+            ie.set_var (m_lhs->name ());
+            std::string msg = ie.message ();
+            error_with_id (ie.err_id (), "%s", msg.c_str ());
           }
       }
 
--- a/libinterp/parse-tree/pt-binop.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-binop.cc	Sun May 16 09:44:35 2021 +0200
@@ -137,7 +137,7 @@
 
                 type_info& ti = interp.get_type_info ();
 
-                val = ::do_binary_op (ti, m_etype, a, b);
+                val = binary_op (ti, m_etype, a, b);
               }
           }
       }
--- a/libinterp/parse-tree/pt-cbinop.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-cbinop.cc	Sun May 16 09:44:35 2021 +0200
@@ -54,7 +54,7 @@
 
                 type_info& ti = interp.get_type_info ();
 
-                val = ::do_binary_op (ti, m_etype, a, b);
+                val = binary_op (ti, m_etype, a, b);
               }
           }
       }
--- a/libinterp/parse-tree/pt-classdef.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-classdef.h	Sun May 16 09:44:35 2021 +0200
@@ -768,7 +768,7 @@
   {
   public:
 
-    tree_classdef (const octave::symbol_scope& scope,
+    tree_classdef (const symbol_scope& scope,
                    tree_classdef_attribute_list *a, tree_identifier *i,
                    tree_classdef_superclass_list *sc,
                    tree_classdef_body *b, comment_list *lc,
@@ -795,7 +795,7 @@
       delete m_trail_comm;
     }
 
-    octave::symbol_scope scope (void) { return m_scope; }
+    symbol_scope scope (void) { return m_scope; }
 
     tree_classdef_attribute_list *
     attribute_list (void) { return m_attr_list; }
@@ -831,7 +831,7 @@
     // corresponds to any identifiers that were found in attribute lists
     // (for example).  Used again when computing the meta class object.
 
-    octave::symbol_scope m_scope;
+    symbol_scope m_scope;
 
     tree_classdef_attribute_list *m_attr_list;
 
@@ -848,10 +848,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-// Hmm, a lot of these are templates, so not sure how to typedef them.
-
 #endif
-
-#endif
--- a/libinterp/parse-tree/pt-colon.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-colon.cc	Sun May 16 09:44:35 2021 +0200
@@ -57,52 +57,22 @@
     if (! m_base || ! m_limit)
       return val;
 
-    octave_value ov_base = m_base->evaluate (tw);
-
-    octave_value ov_limit = m_limit->evaluate (tw);
-
-    if (ov_base.isobject () || ov_limit.isobject ())
-      {
-        octave_value_list tmp1;
-
-        if (m_increment)
-          {
-            octave_value ov_increment = m_increment->evaluate (tw);
+    octave_value ov_base;
+    octave_value ov_increment;
+    octave_value ov_limit;
 
-            tmp1(2) = ov_limit;
-            tmp1(1) = ov_increment;
-            tmp1(0) = ov_base;
-          }
-        else
-          {
-            tmp1(1) = ov_limit;
-            tmp1(0) = ov_base;
-          }
-
-        interpreter& interp = tw.get_interpreter ();
-
-        symbol_table& symtab = interp.get_symbol_table ();
-
-        octave_value fcn = symtab.find_function ("colon", tmp1);
-
-        if (! fcn.is_defined ())
-          error ("can not find overloaded colon function");
-
-        octave_value_list tmp2 = feval (fcn, tmp1, 1);
-
-        val = tmp2 (0);
+    if (m_increment)
+      {
+        ov_base = m_base->evaluate (tw);
+        ov_increment = m_increment->evaluate (tw);
+        ov_limit = m_limit->evaluate (tw);
       }
     else
       {
-        octave_value ov_increment = 1.0;
-
-        if (m_increment)
-          ov_increment = m_increment->evaluate (tw);
-
-        val = do_colon_op (ov_base, ov_increment, ov_limit,
-                           is_for_cmd_expr ());
+        ov_base = m_base->evaluate (tw);
+        ov_limit = m_limit->evaluate (tw);
       }
 
-    return val;
+    return colon_op (ov_base, ov_increment, ov_limit, is_for_cmd_expr ());
   }
 }
--- a/libinterp/parse-tree/pt-eval.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-eval.cc	Sun May 16 09:44:35 2021 +0200
@@ -29,9 +29,12 @@
 
 #include <cctype>
 
+#include <condition_variable>
 #include <iostream>
 #include <list>
+#include <mutex>
 #include <string>
+#include <thread>
 
 #include "cmd-edit.h"
 #include "file-ops.h"
@@ -111,14 +114,13 @@
         m_execution_mode (EX_NORMAL), m_in_debug_repl (false)
     { }
 
+    int server_loop (void);
+
     void repl (const std::string& prompt = "debug> ");
 
     bool in_debug_repl (void) const { return m_in_debug_repl; }
 
-    void dbcont (void)
-    {
-      m_execution_mode = EX_CONTINUE;
-    }
+    void dbcont (void) { m_execution_mode = EX_CONTINUE; }
 
     void dbquit (bool all = false)
     {
@@ -140,6 +142,121 @@
     bool m_in_debug_repl;
   };
 
+  // FIXME: Could the debugger server_loop and repl functions be merged
+  // with the corresponding tree_evaluator functions or do they need to
+  // remain separate?  They perform nearly the same functions.
+
+  int debugger::server_loop (void)
+  {
+    // Process events from the event queue.
+
+    tree_evaluator& tw = m_interpreter.get_evaluator ();
+
+    void (tree_evaluator::*server_mode_fptr) (bool)
+      = &tree_evaluator::server_mode;
+    unwind_action act (server_mode_fptr, &tw, true);
+
+    int exit_status = 0;
+
+    do
+      {
+        if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
+          break;
+
+        if (quitting_debugger ())
+          break;
+
+        try
+          {
+            // FIXME: Should we call octave_quit in the octave::sleep
+            // and/or command_editor::run_event_hooks functions?
+
+            octave_quit ();
+
+            // FIXME: Running the event queue should be decoupled from
+            // the command_editor.
+
+            // FIXME: Is it OK to use command_editor::run_event_hooks
+            // here?  It may run more than one queued function per call,
+            // and it seems that the checks at the top of the loop
+            // probably need to be done after each individual event
+            // function is executed.  For now, maybe the simplest thing
+            // would be to pass a predicate function (lambda expression)
+            // to the command_editor::run_event_hooks and have it check
+            // that and break out of the eval loop(s) if the condition
+            // is met?
+
+            // FIXME: We should also use a condition variable to manage
+            // the execution of entries in the queue and eliminate the
+            // need for the busy-wait loop.
+
+            command_editor::run_event_hooks ();
+
+            octave::sleep (0.1);
+          }
+        catch (const interrupt_exception&)
+          {
+            octave_interrupt_state = 1;
+            m_interpreter.recover_from_exception ();
+
+            // Required newline when the user does Ctrl+C at the prompt.
+            if (m_interpreter.interactive ())
+              octave_stdout << "\n";
+          }
+        catch (const index_exception& e)
+          {
+            m_interpreter.recover_from_exception ();
+
+            std::cerr << "error: unhandled index exception: "
+                      << e.message () << " -- trying to return to prompt"
+                      << std::endl;
+          }
+        catch (const execution_exception& ee)
+          {
+            error_system& es = m_interpreter.get_error_system ();
+
+            es.save_exception (ee);
+            es.display_exception (ee);
+
+            if (m_interpreter.interactive ())
+              {
+                m_interpreter.recover_from_exception ();
+              }
+            else
+              {
+                // We should exit with a nonzero status.
+                exit_status = 1;
+                break;
+              }
+          }
+        catch (const quit_debug_exception& qde)
+          {
+            if (qde.all ())
+              throw;
+
+            // Continue in this debug level.
+          }
+        catch (const std::bad_alloc&)
+          {
+            m_interpreter.recover_from_exception ();
+
+            std::cerr << "error: out of memory -- trying to return to prompt"
+                      << std::endl;
+          }
+      }
+    while (exit_status == 0);
+
+    if (exit_status == EOF)
+      {
+        if (m_interpreter.interactive ())
+          octave_stdout << "\n";
+
+        exit_status = 0;
+      }
+
+    return exit_status;
+  }
+
   void debugger::repl (const std::string& prompt_arg)
   {
     unwind_protect frame;
@@ -153,8 +270,8 @@
 
     bool silent = tw.quiet_breakpoint_flag (false);
 
-    frame.add_method (tw, &tree_evaluator::restore_frame,
-                      tw.current_call_stack_frame_number ());
+    frame.add (&tree_evaluator::restore_frame, &tw,
+               tw.current_call_stack_frame_number ());
 
     tw.goto_frame (tw.debug_frame ());
 
@@ -173,6 +290,8 @@
 
     input_system& input_sys = m_interpreter.get_input_system ();
 
+    event_manager& evmgr = m_interpreter.get_event_manager ();
+
     if (! fcn_nm.empty ())
       {
         if (input_sys.gud_mode ())
@@ -194,16 +313,12 @@
                 frm->display_stopped_in_message (buf);
               }
 
-            event_manager& evmgr = m_interpreter.get_event_manager ();
-
             evmgr.enter_debugger_event (fcn_nm, fcn_file_nm, curr_debug_line);
 
             evmgr.set_workspace ();
 
-            frame.add ([&evmgr, fcn_nm, curr_debug_line] (void) {
-                         evmgr.execute_in_debugger_event (fcn_nm,
-                                                          curr_debug_line);
-                       });
+            frame.add (&event_manager::execute_in_debugger_event, &evmgr,
+                       fcn_nm, curr_debug_line);
 
             if (! silent)
               {
@@ -223,143 +338,167 @@
 
     std::string stopped_in_msg = buf.str ();
 
-    if (! stopped_in_msg.empty ())
-      std::cerr << stopped_in_msg << std::endl;
-
-    std::string tmp_prompt = prompt_arg;
-    if (m_level > 0)
-      tmp_prompt = "[" + std::to_string (m_level) + "]" + prompt_arg;
-
-    frame.add_method (input_sys, &input_system::set_PS1, input_sys.PS1 ());
-    input_sys.PS1 (tmp_prompt);
-
-    if (! m_interpreter.interactive ())
+    if (m_interpreter.server_mode ())
       {
-
-        frame.add_method (m_interpreter, &interpreter::interactive,
-                          m_interpreter.interactive ());
-
-        m_interpreter.interactive (true);
-
-        // FIXME: should debugging be possible in an embedded
-        // interpreter?
-
-        application *app = application::app ();
-
-        if (app)
+        if (! stopped_in_msg.empty ())
+          octave_stdout << stopped_in_msg << std::endl;
+
+        evmgr.push_event_queue ();
+
+        frame.add (&event_manager::pop_event_queue, &evmgr);
+
+        frame.add (&tree_evaluator::set_parser, &tw, tw.get_parser ());
+
+        std::shared_ptr<push_parser>
+          debug_parser (new push_parser (m_interpreter));
+
+        tw.set_parser (debug_parser);
+
+        server_loop ();
+      }
+    else
+      {
+        if (! stopped_in_msg.empty ())
+          std::cerr << stopped_in_msg << std::endl;
+
+        std::string tmp_prompt = prompt_arg;
+        if (m_level > 0)
+          tmp_prompt = "[" + std::to_string (m_level) + "]" + prompt_arg;
+
+        frame.add (&input_system::set_PS1, &input_sys, input_sys.PS1 ());
+        input_sys.PS1 (tmp_prompt);
+
+        if (! m_interpreter.interactive ())
           {
-            frame.add_method (app, &application::forced_interactive,
-                              app->forced_interactive ());
-
-            app->forced_interactive (true);
+            void (interpreter::*interactive_fptr) (bool)
+              = &interpreter::interactive;
+            frame.add (interactive_fptr, &m_interpreter,
+                       m_interpreter.interactive ());
+
+            m_interpreter.interactive (true);
+
+            // FIXME: should debugging be possible in an embedded
+            // interpreter?
+
+            application *app = application::app ();
+
+            if (app)
+              {
+                void (application::*forced_interactive_fptr) (bool)
+                  = &application::forced_interactive;
+                frame.add (forced_interactive_fptr, app,
+                           app->forced_interactive ());
+
+                app->forced_interactive (true);
+              }
           }
-      }
-
-#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
-
-    input_reader reader (m_interpreter);
-
-    push_parser debug_parser (m_interpreter);
-
-#else
-
-    parser debug_parser (m_interpreter);
-
-#endif
-
-    error_system& es = m_interpreter.get_error_system ();
-
-    while (m_in_debug_repl)
-      {
-        if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
-          break;
-
-        if (quitting_debugger ())
-          break;
-
-        try
-          {
-            debug_parser.reset ();
 
 #if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
 
-            int retval = 0;
-
-            std::string prompt
-              = command_editor::decode_prompt_string (tmp_prompt);
-
-            do
-              {
-                bool eof = false;
-                std::string input_line = reader.get_input (prompt, eof);
-
-                if (eof)
-                  {
-                    retval = EOF;
-                    break;
-                  }
-
-                retval = debug_parser.run (input_line, false);
-
-                prompt = command_editor::decode_prompt_string (input_sys.PS2 ());
-              }
-            while (retval < 0);
+        input_reader reader (m_interpreter);
+
+        push_parser debug_parser (m_interpreter);
 
 #else
 
-            int retval = debug_parser.run ();
+        parser debug_parser (m_interpreter);
 
 #endif
-            if (command_editor::interrupt (false))
+
+        error_system& es = m_interpreter.get_error_system ();
+
+        while (m_in_debug_repl)
+          {
+            if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
+              break;
+
+            if (quitting_debugger ())
+              break;
+
+            try
               {
-                // Break regardless of m_execution_mode value.
-
-                quitting_debugger ();
-
-                break;
-              }
-            else
-              {
-                if (retval == 0)
+                debug_parser.reset ();
+
+#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
+
+                int retval = 0;
+
+                std::string prompt
+                  = command_editor::decode_prompt_string (tmp_prompt);
+
+                do
+                  {
+                    bool eof = false;
+                    std::string input_line = reader.get_input (prompt, eof);
+
+                    if (eof)
+                      {
+                        retval = EOF;
+                        break;
+                      }
+
+                    retval = debug_parser.run (input_line, false);
+
+                    prompt = command_editor::decode_prompt_string (input_sys.PS2 ());
+                  }
+                while (retval < 0);
+
+#else
+
+                int retval = debug_parser.run ();
+
+#endif
+                if (command_editor::interrupt (false))
                   {
-                    std::shared_ptr<tree_statement_list> stmt_list
-                      = debug_parser.statement_list ();
-
-                    if (stmt_list)
-                      stmt_list->accept (tw);
-
-                    if (octave_completion_matches_called)
-                      octave_completion_matches_called = false;
-
-                    // FIXME: the following statement is here because
-                    // the last command may have been a dbup, dbdown, or
-                    // dbstep command that changed the current debug
-                    // frame.  If so, we need to reset the current frame
-                    // for the call stack.  But is this right way to do
-                    // this job?  What if the statement list was
-                    // something like "dbup; dbstack"?  Will the call to
-                    // dbstack use the right frame?  If not, how can we
-                    // fix this problem?
-                    tw.goto_frame (tw.debug_frame ());
+                    // Break regardless of m_execution_mode value.
+
+                    quitting_debugger ();
+
+                    break;
                   }
-
-                octave_quit ();
+                else
+                  {
+                    if (retval == 0)
+                      {
+                        std::shared_ptr<tree_statement_list> stmt_list
+                          = debug_parser.statement_list ();
+
+                        if (stmt_list)
+                          stmt_list->accept (tw);
+
+                        if (octave_completion_matches_called)
+                          octave_completion_matches_called = false;
+
+                        // FIXME: the following statement is here because
+                        // the last command may have been a dbup, dbdown, or
+                        // dbstep command that changed the current debug
+                        // frame.  If so, we need to reset the current frame
+                        // for the call stack.  But is this right way to do
+                        // this job?  What if the statement list was
+                        // something like "dbup; dbstack"?  Will the call to
+                        // dbstack use the right frame?  If not, how can we
+                        // fix this problem?
+                        tw.goto_frame (tw.debug_frame ());
+                      }
+
+                    octave_quit ();
+                  }
               }
-          }
-        catch (const execution_exception& ee)
-          {
-            es.save_exception (ee);
-            es.display_exception (ee, std::cerr);
-
-            // Ignore errors when in debugging mode;
-            m_interpreter.recover_from_exception ();
-          }
-        catch (const quit_debug_exception& qde)
-          {
-            if (qde.all ())
-              throw;
-
-            // Continue in this debug level.
+            catch (const execution_exception& ee)
+              {
+                es.save_exception (ee);
+                es.display_exception (ee);
+
+                // Ignore errors when in debugging mode;
+                m_interpreter.recover_from_exception ();
+              }
+            catch (const quit_debug_exception& qde)
+              {
+                if (qde.all ())
+                  throw;
+
+                // Continue in this debug level.
+              }
           }
       }
   }
@@ -371,7 +510,8 @@
         // If there is no enclosing debug level or the top-level
         // repl is not active, handle dbquit the same as dbcont.
 
-        if (m_level > 0 || m_interpreter.in_top_level_repl ())
+        if (m_level > 0 || m_interpreter.server_mode ()
+            || m_interpreter.in_top_level_repl ())
           throw quit_debug_exception ();
         else
           return true;
@@ -382,7 +522,7 @@
         // If the top-level repl is not active, handle "dbquit all"
         // the same as dbcont.
 
-        if (m_interpreter.in_top_level_repl ())
+        if (m_interpreter.server_mode () || m_interpreter.in_top_level_repl ())
           throw quit_debug_exception (true);
         else
           return true;
@@ -396,38 +536,6 @@
     return m_call_stack.at_top_level ();
   }
 
-  void tree_evaluator::eval (std::shared_ptr<tree_statement_list>& stmt_list,
-                             bool interactive)
-  {
-    try
-      {
-        stmt_list->accept (*this);
-
-        octave_quit ();
-
-        if (! interactive)
-          {
-            bool quit = (m_returning || m_breaking);
-
-            if (m_returning)
-              m_returning = 0;
-
-            if (m_breaking)
-              m_breaking--;
-
-            if (quit)
-              return;
-          }
-
-        if (octave_completion_matches_called)
-          octave_completion_matches_called = false;
-      }
-    catch (const quit_debug_exception&)
-      {
-        m_interpreter.recover_from_exception ();
-      }
-  }
-
   std::string
   tree_evaluator::mfilename (const std::string& opt) const
   {
@@ -464,6 +572,435 @@
     return fname;
   }
 
+  void tree_evaluator::parse_and_execute (const std::string& input,
+                                          bool& incomplete_parse)
+  {
+    incomplete_parse = false;
+
+    unwind_protect_var<bool> upv (m_in_top_level_repl, true);
+
+    if (at_top_level ())
+      {
+        dbstep_flag (0);
+        reset_debug_state ();
+      }
+
+    // FIXME: OK to do this job here, or should it be in the functions
+    // that do the actual prompting?
+
+    // Update the time stamp for the "prompt" so that automatically
+    // finding modified files based on file modification times will
+    // work.  In the future, we may do something completely different to
+    // check for changes to files but for now, we rely on the prompt
+    // time stamp to limit the checks for file modification times.
+
+    Vlast_prompt_time.stamp ();
+
+    bool eof = false;
+
+    event_manager& evmgr = m_interpreter.get_event_manager ();
+
+    if (command_history::add (input))
+      evmgr.append_history (input);
+
+    m_exit_status = m_parser->run (input, eof);
+
+    if (m_exit_status == 0)
+      {
+        std::shared_ptr<tree_statement_list>
+          stmt_list = m_parser->statement_list ();
+
+        if (stmt_list)
+          {
+            command_editor::increment_current_command_number ();
+
+            eval (stmt_list, m_interpreter.interactive ());
+
+            evmgr.set_workspace ();
+          }
+        else if (m_parser->at_end_of_input ())
+          m_exit_status = EOF;
+      }
+    else
+      incomplete_parse = true;
+
+    // FIXME: Should we be checking m_exit_status or incomplete_parse or
+    // both here?  Could EOF have a value other than -1, and is there
+    // possible confusion between that state and the parser returning -1?
+
+    if (m_exit_status == -1)
+      m_exit_status = 0;
+    else
+      m_parser->reset ();
+
+    evmgr.pre_input_event ();
+  }
+
+  void tree_evaluator::get_line_and_eval (void)
+  {
+    std::mutex mtx;
+    std::unique_lock<std::mutex> lock (mtx);
+    std::condition_variable cv;
+    bool incomplete_parse = false;
+    bool evaluation_pending = false;
+    bool exiting = false;
+
+    input_system& input_sys = m_interpreter.get_input_system ();
+    event_manager& evmgr = m_interpreter.get_event_manager ();
+
+    while (true)
+      {
+        // FIXME: Detect EOF?  Use readline?  If
+        // so, then we need to disable idle event loop hook function
+        // execution.
+
+        std::string ps = incomplete_parse ? input_sys.PS2 () : input_sys.PS1 ();
+
+        std::cout << command_editor::decode_prompt_string (ps);
+
+        std::string input;
+        std::getline (std::cin, input);
+
+        if (input.empty ())
+          continue;
+
+        incomplete_parse = false;
+        evaluation_pending = true;
+        exiting = false;
+
+        evmgr.post_event
+          ([&] (interpreter& interp)
+           {
+             // INTERPRETER THREAD
+
+             std::lock_guard<std::mutex> local_lock (mtx);
+
+             try
+               {
+                 interp.parse_and_execute (input, incomplete_parse);
+               }
+             catch (const exit_exception&)
+               {
+                 evaluation_pending = false;
+                 exiting = true;
+                 cv.notify_all ();
+                 throw;
+               }
+             catch (const execution_exception& ee)
+               {
+                 error_system& es = m_interpreter.get_error_system ();
+
+                 es.save_exception (ee);
+                 es.display_exception (ee);
+
+                 if (m_interpreter.interactive ())
+                   {
+                     m_interpreter.recover_from_exception ();
+                     m_parser->reset ();
+                     evaluation_pending = false;
+                     cv.notify_all ();
+                   }
+                 else
+                   {
+                     evaluation_pending = false;
+                     cv.notify_all ();
+                     throw exit_exception (1);
+                   }
+               }
+             catch (...)
+               {
+                 evaluation_pending = false;
+                 cv.notify_all ();
+                 throw;
+               }
+
+             evaluation_pending = false;
+             cv.notify_all ();
+           });
+
+        // Wait until evaluation is finished before prompting for input
+        // again.
+
+        cv.wait (lock, [&] { return ! evaluation_pending; });
+
+        if (exiting)
+          break;
+      }
+  }
+
+  int tree_evaluator::repl (void)
+  {
+    // The big loop.  Read, Eval, Print, Loop.  Normally user
+    // interaction at the command line in a terminal session, but we may
+    // also end up here when reading from a pipe or when stdin is
+    // connected to a file by the magic of input redirection.
+
+    int exit_status = 0;
+
+    // FIXME: should this choice be a command-line option?  Note that we
+    // intend that the push parser interface only be used for
+    // interactive sessions.
+
+#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
+    static bool use_command_line_push_parser = true;
+#else
+    static bool use_command_line_push_parser = false;
+#endif
+
+    // The following logic is written as it is to allow easy transition
+    // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to
+    // simplify the logic of the main loop below by using the same
+    // base_parser::run interface for both push and pull parsers.
+
+    std::shared_ptr<base_parser> repl_parser;
+
+    if (m_interpreter.interactive ())
+      {
+        if (use_command_line_push_parser)
+          {
+            push_parser *pp
+              = new push_parser (m_interpreter,
+                                 new input_reader (m_interpreter));
+
+            repl_parser = std::shared_ptr<base_parser> (pp);
+          }
+        else
+          {
+            parser *pp = new parser (new lexer (m_interpreter));
+            repl_parser = std::shared_ptr<base_parser> (pp);
+          }
+      }
+    else
+      {
+        parser *pp = new parser (new lexer (stdin, m_interpreter));
+        repl_parser = std::shared_ptr<base_parser> (pp);
+      }
+
+    do
+      {
+        try
+          {
+            unwind_protect_var<bool> upv (m_in_top_level_repl, true);
+
+            repl_parser->reset ();
+
+            if (at_top_level ())
+              {
+                dbstep_flag (0);
+                reset_debug_state ();
+              }
+
+            exit_status = repl_parser->run ();
+
+            if (exit_status == 0)
+              {
+                std::shared_ptr<tree_statement_list>
+                  stmt_list = repl_parser->statement_list ();
+
+                if (stmt_list)
+                  {
+                    command_editor::increment_current_command_number ();
+
+                    eval (stmt_list, m_interpreter.interactive ());
+                  }
+                else if (repl_parser->at_end_of_input ())
+                  {
+                    exit_status = EOF;
+                    break;
+                  }
+              }
+          }
+        catch (const interrupt_exception&)
+          {
+            m_interpreter.recover_from_exception ();
+
+            // Required newline when the user does Ctrl+C at the prompt.
+            if (m_interpreter.interactive ())
+              octave_stdout << "\n";
+          }
+        catch (const index_exception& ie)
+          {
+            m_interpreter.recover_from_exception ();
+
+            std::cerr << "error: unhandled index exception: "
+                      << ie.message () << " -- trying to return to prompt"
+                      << std::endl;
+          }
+        catch (const execution_exception& ee)
+          {
+            error_system& es = m_interpreter.get_error_system ();
+
+            es.save_exception (ee);
+            es.display_exception (ee);
+
+            if (m_interpreter.interactive ())
+              m_interpreter.recover_from_exception ();
+            else
+              {
+                // We should exit with a nonzero status.
+                exit_status = 1;
+                break;
+              }
+          }
+        catch (const std::bad_alloc&)
+          {
+            m_interpreter.recover_from_exception ();
+
+            std::cerr << "error: out of memory -- trying to return to prompt"
+                      << std::endl;
+          }
+      }
+    while (exit_status == 0);
+
+    if (exit_status == EOF)
+      {
+        if (m_interpreter.interactive ())
+          octave_stdout << "\n";
+
+        exit_status = 0;
+      }
+
+    return exit_status;
+  }
+
+  int tree_evaluator::server_loop (void)
+  {
+    // Process events from the event queue.
+
+    unwind_protect_var<bool> upv1 (m_server_mode, true);
+
+    m_exit_status = 0;
+
+    std::shared_ptr<push_parser> parser (new push_parser (m_interpreter));
+    unwind_protect_var<std::shared_ptr<push_parser>> upv2 (m_parser, parser);
+
+    // FIXME: We are currently resetting the parser after every call to
+    // recover_from_exception.  This action should probably be handled
+    // in a more consistent way, but resetting the parser in every call
+    // to interpreter::recover_from_exception appears to cause
+    // segfaults in the test suite.
+
+    do
+      {
+        try
+          {
+            // FIXME: Should we call octave_quit in the octave::sleep
+            // and/or command_editor::run_event_hooks functions?
+
+            octave_quit ();
+
+            // FIXME: Running the event queue should be decoupled from
+            // the command_editor.  We should also use a condition
+            // variable to manage the execution of entries in the queue
+            // and eliminate the need for the busy-wait loop.
+
+            command_editor::run_event_hooks ();
+
+            octave::sleep (0.1);
+          }
+        catch (const interrupt_exception&)
+          {
+            octave_interrupt_state = 1;
+            m_interpreter.recover_from_exception ();
+            m_parser->reset ();
+
+            // Required newline when the user does Ctrl+C at the prompt.
+            if (m_interpreter.interactive ())
+              octave_stdout << "\n";
+          }
+        catch (const index_exception& e)
+          {
+            m_interpreter.recover_from_exception ();
+            m_parser->reset ();
+
+            std::cerr << "error: unhandled index exception: "
+                      << e.message () << " -- trying to return to prompt"
+                      << std::endl;
+          }
+        catch (const execution_exception& ee)
+          {
+            error_system& es = m_interpreter.get_error_system ();
+
+            es.save_exception (ee);
+            es.display_exception (ee);
+
+            if (m_interpreter.interactive ())
+              {
+                m_interpreter.recover_from_exception ();
+                m_parser->reset ();
+              }
+            else
+              {
+                // We should exit with a nonzero status.
+                m_exit_status = 1;
+                break;
+              }
+          }
+        catch (const quit_debug_exception&)
+          {
+            octave_interrupt_state = 1;
+            m_interpreter.recover_from_exception ();
+            m_parser->reset ();
+          }
+        catch (const exit_exception& xe)
+          {
+            m_exit_status = xe.exit_status ();
+            break;
+          }
+        catch (const std::bad_alloc&)
+          {
+            m_interpreter.recover_from_exception ();
+            m_parser->reset ();
+
+            std::cerr << "error: out of memory -- trying to return to prompt"
+                      << std::endl;
+          }
+      }
+    while (m_exit_status == 0);
+
+    if (m_exit_status == EOF)
+      {
+        if (m_interpreter.interactive ())
+          octave_stdout << "\n";
+
+        m_exit_status = 0;
+      }
+
+    return m_exit_status;
+  }
+
+  void tree_evaluator::eval (std::shared_ptr<tree_statement_list>& stmt_list,
+                             bool interactive)
+  {
+    try
+      {
+        stmt_list->accept (*this);
+
+        octave_quit ();
+
+        if (! interactive)
+          {
+            bool quit = (m_returning || m_breaking);
+
+            if (m_returning)
+              m_returning = 0;
+
+            if (m_breaking)
+              m_breaking--;
+
+            if (quit)
+              return;
+          }
+
+        if (octave_completion_matches_called)
+          octave_completion_matches_called = false;
+      }
+    catch (const quit_debug_exception&)
+      {
+        m_interpreter.recover_from_exception ();
+      }
+  }
+
   octave_value_list
   tree_evaluator::eval_string (const std::string& eval_str, bool silent,
                                int& parse_status, int nargout)
@@ -618,7 +1155,7 @@
                                             const std::string& try_code,
                                             int nargout)
   {
-    unwind_action act ([this] (std::size_t frm)
+    unwind_action act ([=] (std::size_t frm)
                        {
                          m_call_stack.restore_frame (frm);
                        }, m_call_stack.current_frame ());
@@ -628,7 +1165,7 @@
     else if (context == "base")
       m_call_stack.goto_base_frame ();
     else
-      error ("evalin: CONTEXT must be \"caller\" or \"base\"");
+      error (R"(evalin: CONTEXT must be "caller" or "base")");
 
     int parse_status = 0;
 
@@ -642,7 +1179,7 @@
   {
     octave_value_list retval;
 
-    unwind_action act1 ([this] (std::size_t frm)
+    unwind_action act1 ([=] (std::size_t frm)
                         {
                           m_call_stack.restore_frame (frm);
                         }, m_call_stack.current_frame ());
@@ -652,7 +1189,7 @@
     else if (context == "base")
       m_call_stack.goto_base_frame ();
     else
-      error ("evalin: CONTEXT must be \"caller\" or \"base\"");
+      error (R"(evalin: CONTEXT must be "caller" or "base")");
 
     error_system& es = m_interpreter.get_error_system ();
 
@@ -730,7 +1267,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -755,7 +1294,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -777,7 +1318,9 @@
   void
   tree_evaluator::reset_debug_state (void)
   {
-    m_debug_mode = (m_bp_table.have_breakpoints () || m_dbstep_flag != 0
+    m_debug_mode = (m_bp_table.have_breakpoints ()
+                    || m_dbstep_flag != 0
+                    || m_break_on_next_stmt
                     || in_debug_repl ());
   }
 
@@ -792,24 +1335,23 @@
   {
     unwind_protect frame;
 
-    frame.add_fcn (command_history::ignore_entries,
-                   command_history::ignoring_entries ());
+    frame.add (command_history::ignore_entries,
+               command_history::ignoring_entries ());
 
     command_history::ignore_entries (false);
 
-    frame.add_method (m_call_stack, &call_stack::restore_frame,
-                      m_call_stack.current_frame ());
+    frame.add (&call_stack::restore_frame, &m_call_stack,
+               m_call_stack.current_frame ());
 
     // Don't allow errors or warnings at the debug prompt to push us
     // into deeper levels of debugging.
 
     error_system& es = m_interpreter.get_error_system ();
 
-    frame.add_method (es, &error_system::set_debug_on_error,
-                      es.debug_on_error ());
-
-    frame.add_method (es, &error_system::set_debug_on_warning,
-                      es.debug_on_warning ());
+    frame.add (&error_system::set_debug_on_error, &es, es.debug_on_error ());
+
+    frame.add (&error_system::set_debug_on_warning, &es,
+               es.debug_on_warning ());
 
     es.debug_on_error (false);
     es.debug_on_warning (false);
@@ -828,10 +1370,11 @@
 
     m_debugger_stack.push (dbgr);
 
-    frame.add ([this] (void)
+    frame.add ([=] (void)
                {
                  delete m_debugger_stack.top ();
                  m_debugger_stack.pop ();
+                 reset_debug_state ();
                });
 
     dbgr->repl (prompt);
@@ -1414,7 +1957,7 @@
     // by getting a reference to the caller or base stack frame and
     // calling assign on that?
 
-    unwind_action act ([this] (std::size_t frm)
+    unwind_action act ([=] (std::size_t frm)
                        {
                          m_call_stack.restore_frame (frm);
                        }, m_call_stack.current_frame ());
@@ -1424,7 +1967,7 @@
     else if (context == "base")
       m_call_stack.goto_base_frame ();
     else
-      error ("assignin: CONTEXT must be \"caller\" or \"base\"");
+      error (R"(assignin: CONTEXT must be "caller" or "base")");
 
     if (valid_identifier (name))
       {
@@ -1506,15 +2049,15 @@
 
     if (! context.empty ())
       {
-        frame.add_method (m_call_stack, &call_stack::restore_frame,
-                          m_call_stack.current_frame ());
+        frame.add (&call_stack::restore_frame, &m_call_stack,
+                   m_call_stack.current_frame ());
 
         if (context == "caller")
           m_call_stack.goto_caller_frame ();
         else if (context == "base")
           m_call_stack.goto_base_frame ();
         else
-          error ("source: context must be \"caller\" or \"base\"");
+          error (R"(source: CONTEXT must be "caller" or "base")");
       }
 
     // Find symbol name that would be in symbol_table, if it were loaded.
@@ -1565,9 +2108,9 @@
                                       file_name, dir_name, "", "",
                                       require_file, true, false, false);
           }
-        catch (execution_exception& e)
+        catch (execution_exception& ee)
           {
-            error (e, "source: error sourcing file '%s'",
+            error (ee, "source: error sourcing file '%s'",
                    file_full_name.c_str ());
           }
       }
@@ -1683,7 +2226,7 @@
 %! fail ("__undef_sym__ (end)",
 %!       "invalid use of 'end': may only be used to index existing value");
 
-%!test <58953>
+%!test <*58953>
 %! x = 1:10;
 %! assert (x(end), 10);
 %! assert (x(minus (end, 1)), 9);
@@ -2372,7 +2915,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -2421,10 +2966,42 @@
       }
   }
 
+  template <typename T>
+  void
+  tree_evaluator::execute_range_loop (const range<T>& rng, int line,
+                                      octave_lvalue& ult,
+                                      tree_statement_list *loop_body)
+  {
+    octave_idx_type steps = rng.numel ();
+
+    if (math::isinf (rng.limit ()))
+      warning_with_id ("Octave:infinite-loop",
+                       "FOR loop limit is infinite, will stop after %"
+                       OCTAVE_IDX_TYPE_FORMAT " steps", steps);
+
+    for (octave_idx_type i = 0; i < steps; i++)
+      {
+        if (m_echo_state)
+          m_echo_file_pos = line;
+
+        octave_value val (rng.elem (i));
+
+        ult.assign (octave_value::op_asn_eq, val);
+
+        if (loop_body)
+          loop_body->accept (*this);
+
+        if (quit_loop_now ())
+          break;
+      }
+  }
+
   void
   tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd)
   {
-    std::size_t line = cmd.line ();
+    int line = cmd.line ();
+    if (line < 0)
+      line = 1;
 
     if (m_echo_state)
       {
@@ -2460,27 +3037,70 @@
 
     if (rhs.is_range ())
       {
-        Range rng = rhs.range_value ();
-
-        octave_idx_type steps = rng.numel ();
-
-        for (octave_idx_type i = 0; i < steps; i++)
+        // FIXME: is there a better way to dispatch here?
+
+        if (rhs.is_double_type ())
+          {
+            execute_range_loop (rhs.range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int64_type ())
+          {
+            execute_range_loop (rhs.int64_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint64_type ())
+          {
+            execute_range_loop (rhs.uint64_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int32_type ())
+          {
+            execute_range_loop (rhs.int32_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint32_type ())
           {
-            if (m_echo_state)
-              m_echo_file_pos = line;
-
-            octave_value val (rng.elem (i));
-
-            ult.assign (octave_value::op_asn_eq, val);
-
-            if (loop_body)
-              loop_body->accept (*this);
-
-            if (quit_loop_now ())
-              break;
+            execute_range_loop (rhs.uint32_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int16_type ())
+          {
+            execute_range_loop (rhs.int16_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint16_type ())
+          {
+            execute_range_loop (rhs.uint16_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_int8_type ())
+          {
+            execute_range_loop (rhs.int8_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_uint8_type ())
+          {
+            execute_range_loop (rhs.uint8_range_value (), line, ult, loop_body);
+            return;
+          }
+
+        if (rhs.is_single_type ())
+          {
+            execute_range_loop (rhs.float_range_value (), line, ult, loop_body);
+            return;
           }
       }
-    else if (rhs.is_scalar_type ())
+
+    if (rhs.is_scalar_type ())
       {
         if (m_echo_state)
           m_echo_file_pos = line;
@@ -2492,9 +3112,15 @@
 
         // Maybe decrement break and continue states.
         quit_loop_now ();
+
+        return;
       }
-    else if (rhs.is_matrix_type () || rhs.iscell () || rhs.is_string ()
-             || rhs.isstruct ())
+
+    // Also handle any range types not explicitly handled above, though
+    // not as efficiently as the specialized code above.
+
+    if (rhs.is_range () || rhs.is_matrix_type () || rhs.iscell ()
+        || rhs.is_string () || rhs.isstruct ())
       {
         // A matrix or cell is reshaped to 2 dimensions and iterated by
         // columns.
@@ -2531,9 +3157,9 @@
                 if (m_echo_state)
                   m_echo_file_pos = line;
 
-                // do_index_op expects one-based indices.
+                // index_op expects one-based indices.
                 idx(iidx) = i;
-                octave_value val = arg.do_index_op (idx);
+                octave_value val = arg.index_op (idx);
 
                 ult.assign (octave_value::op_asn_eq, val);
 
@@ -2549,16 +3175,20 @@
             // Handle empty cases, while still assigning to loop var.
             ult.assign (octave_value::op_asn_eq, arg);
           }
+
+        return;
       }
-    else
-      error ("invalid type in for loop expression near line %d, column %d",
-             cmd.line (), cmd.column ());
+
+    error ("invalid type in for loop expression near line %d, column %d",
+           cmd.line (), cmd.column ());
   }
 
   void
   tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd)
   {
-    std::size_t line = cmd.line ();
+    int line = cmd.line ();
+    if (line < 0)
+      line = 1;
 
     if (m_echo_state)
       {
@@ -2629,6 +3259,16 @@
       }
   }
 
+  void tree_evaluator::visit_spmd_command (tree_spmd_command& cmd)
+  {
+    // For now, we just execute the commands serially.
+
+    tree_statement_list *body = cmd.body ();
+
+    if (body)
+      body->accept (*this);
+  }
+
   void
   tree_evaluator::visit_octave_user_script (octave_user_script&)
   {
@@ -2653,6 +3293,9 @@
     if (! cmd_list)
       return retval;
 
+    // FIXME: Maybe this check belongs in the places where we push a new
+    // stack frame?  Or in the call_stack push method itself?
+
     if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
       error ("max_recursion_depth exceeded");
 
@@ -2663,6 +3306,8 @@
     if (echo ())
       push_echo_state (tree_evaluator::ECHO_SCRIPTS, file_name);
 
+    // FIXME: Should we be using tree_evaluator::eval here?
+
     cmd_list->accept (*this);
 
     if (m_returning)
@@ -2688,53 +3333,75 @@
   {
     octave_value_list retval;
 
-    tree_statement_list *cmd_list = user_function.body ();
-
-    if (! cmd_list)
-      return retval;
-
     // If this function is a classdef constructor, extract the first input
     // argument, which must be the partially constructed object instance.
 
     octave_value_list args (xargs);
     octave_value_list ret_args;
 
+    int nargin = args.length ();
+
     if (user_function.is_classdef_constructor ())
       {
-        if (args.length () > 0)
+        if (nargin > 0)
           {
             ret_args = args.slice (0, 1, true);
-            args = args.slice (1, args.length () - 1, true);
+            --nargin;
+            args = args.slice (1, nargin, true);
           }
         else
           panic_impossible ();
       }
 
+    // FIXME: this probably shouldn't be a double-precision matrix.
+    Matrix ignored_outputs = ignored_fcn_outputs ();
+
+    tree_parameter_list *param_list = user_function.parameter_list ();
+
+    if (param_list)
+      {
+        int max_inputs = param_list->length ();
+
+        if (! param_list->takes_varargs () && nargin > max_inputs)
+          {
+            std::string name = user_function.name ();
+
+            error ("%s: function called with too many inputs", name.c_str ());
+          }
+
+        if (! param_list->varargs_only ())
+          define_parameter_list_from_arg_vector (param_list, args);
+      }
+
+    tree_parameter_list *ret_list = user_function.return_list ();
+
+    if (ret_list && ! ret_list->takes_varargs ())
+      {
+        int max_outputs = ret_list->length ();
+
+        if (nargout > max_outputs)
+          {
+            std::string name = user_function.name ();
+
+            error ("%s: function called with too many outputs", name.c_str ());
+          }
+      }
+
+    // FIXME: Is this in the right place now?
+
 #if defined (HAVE_LLVM)
     if (user_function.is_special_expr ()
         && tree_jit::execute (user_function, args, retval))
       return retval;
 #endif
 
-    if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
-      error ("max_recursion_depth exceeded");
-
-    Matrix ignored_outputs = ignored_fcn_outputs ();
-
-    bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, args.length (),
+    bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, nargin,
                         nargout, user_function.takes_varargs (),
                         user_function.all_va_args (args));
 
-    tree_parameter_list *param_list = user_function.parameter_list ();
-
-    if (param_list && ! param_list->varargs_only ())
-      define_parameter_list_from_arg_vector (param_list, args);
-
     // For classdef constructor, pre-populate the output arguments
     // with the pre-initialized object instance, extracted above.
 
-    tree_parameter_list *ret_list = user_function.return_list ();
-
     if (user_function.is_classdef_constructor ())
       {
         if (! ret_list)
@@ -2744,6 +3411,12 @@
         define_parameter_list_from_arg_vector (ret_list, ret_args);
       }
 
+    // FIXME: Maybe this check belongs in the places where we push a
+    // new stack frame?  Or in the call_stack push method itself?
+
+    if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
+      error ("max_recursion_depth exceeded");
+
     unwind_action act2 ([&user_function] () {
                           user_function.restore_warning_states ();
                         });
@@ -2752,37 +3425,41 @@
 
     unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_FUNCTION);
 
-    {
-      profiler::enter<octave_user_function> block (m_profiler, user_function);
-
-      if (echo ())
-        push_echo_state (tree_evaluator::ECHO_FUNCTIONS,
-                         user_function.fcn_file_name ());
-
-      if (user_function.is_special_expr ())
-        {
-          assert (cmd_list->length () == 1);
-
-          tree_statement *stmt = cmd_list->front ();
-
-          tree_expression *expr = stmt->expression ();
-
-          if (expr)
-            {
-              m_call_stack.set_location (stmt->line (), stmt->column ());
-
-              retval = expr->evaluate_n (*this, nargout);
-            }
-        }
-      else
-        cmd_list->accept (*this);
-    }
-
-    if (m_returning)
-      m_returning = 0;
-
-    if (m_breaking)
-      m_breaking--;
+    tree_statement_list *cmd_list = user_function.body ();
+
+    if (cmd_list)
+      {
+        profiler::enter<octave_user_function>
+          block (m_profiler, user_function);
+
+        if (echo ())
+          push_echo_state (tree_evaluator::ECHO_FUNCTIONS,
+                           user_function.fcn_file_name ());
+
+        if (user_function.is_special_expr ())
+          {
+            assert (cmd_list->length () == 1);
+
+            tree_statement *stmt = cmd_list->front ();
+
+            tree_expression *expr = stmt->expression ();
+
+            if (expr)
+              {
+                m_call_stack.set_location (stmt->line (), stmt->column ());
+
+                retval = expr->evaluate_n (*this, nargout);
+              }
+          }
+        else
+          cmd_list->accept (*this);
+
+        if (m_returning)
+          m_returning = 0;
+
+        if (m_breaking)
+          m_breaking--;
+      }
 
     // Copy return values out.
 
@@ -2857,7 +3534,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -2926,7 +3605,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -2970,7 +3651,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -3019,7 +3702,9 @@
               {
                 if (m_echo_state)
                   {
-                    std::size_t line = stmt.line ();
+                    int line = stmt.line ();
+                    if (line < 0)
+                      line = 1;
                     echo_code (line);
                     m_echo_file_pos = line + 1;
                   }
@@ -3086,7 +3771,7 @@
                 && in_user_code ())
               {
                 es.save_exception (ee);
-                es.display_exception (ee, std::cerr);
+                es.display_exception (ee);
 
                 enter_debugger ();
 
@@ -3169,7 +3854,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -3209,7 +3896,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -3285,10 +3974,11 @@
     // We want to preserve the last location info for possible
     // backtracking.
 
-    frame.add_method (m_call_stack, &call_stack::set_line,
-                      m_call_stack.current_line ());
-    frame.add_method (m_call_stack, &call_stack::set_column,
-                      m_call_stack.current_column ());
+    frame.add (&call_stack::set_line, &m_call_stack,
+               m_call_stack.current_line ());
+
+    frame.add (&call_stack::set_column, &m_call_stack,
+               m_call_stack.current_column ());
 
     // Similarly, if we have seen a return or break statement, allow all
     // the cleanup code to run before returning or handling the break.
@@ -3361,7 +4051,9 @@
   {
     if (m_echo_state)
       {
-        std::size_t line = cmd.line ();
+        int line = cmd.line ();
+        if (line < 0)
+          line = 1;
         echo_code (line);
         m_echo_file_pos = line + 1;
       }
@@ -3412,7 +4104,9 @@
   void
   tree_evaluator::visit_while_command (tree_while_command& cmd)
   {
-    std::size_t line = cmd.line ();
+    int line = cmd.line ();
+    if (line < 0)
+      line = 1;
 
     if (m_echo_state)
       {
@@ -3458,7 +4152,9 @@
   void
   tree_evaluator::visit_do_until_command (tree_do_until_command& cmd)
   {
-    std::size_t line = cmd.line ();
+    int line = cmd.line ();
+    if (line < 0)
+      line = 1;
 
     if (m_echo_state)
       {
@@ -3530,11 +4226,18 @@
           }
         else
           {
+            // FIXME: Maybe assign could also return the assigned value,
+            // just for convenience?
+
             assign (ans, val);
 
             if (print)
               {
-                octave_value_list args = ovl (val);
+                // Use varval instead of displaying VAL directly so that
+                // we get the right type and value for things like
+                // magic_int values that may mutate when stored.
+
+                octave_value_list args = ovl (varval (ans));
                 args.stash_name_tags (string_vector (ans));
                 feval ("display", args);
               }
@@ -3610,6 +4313,11 @@
           m_dbstep_flag = -1;
       }
 
+    if (! break_on_this_statement)
+      break_on_this_statement = m_break_on_next_stmt;
+
+    m_break_on_next_stmt = false;
+
     if (break_on_this_statement)
       {
         m_dbstep_flag = 0;
@@ -3772,7 +4480,7 @@
   // variable being indexed, if any, then issue an error.  (Will this also
   // be needed by pt-lvalue, which calls subsref?)
 
-  void tree_evaluator::final_index_error (index_exception& e,
+  void tree_evaluator::final_index_error (index_exception& ie,
                                           const tree_expression *expr)
   {
     std::string extra_message;
@@ -3781,7 +4489,7 @@
       {
         std::string var = expr->name ();
 
-        e.set_var (var);
+        ie.set_var (var);
 
         symbol_table& symtab = m_interpreter.get_symbol_table ();
 
@@ -3797,9 +4505,9 @@
           }
       }
 
-    std::string msg = e.message () + extra_message;
-
-    error_with_id (e.err_id (), "%s", msg.c_str ());
+    std::string msg = ie.message () + extra_message;
+
+    error_with_id (ie.err_id (), "%s", msg.c_str ());
   }
 
   octave_value
@@ -3877,7 +4585,7 @@
 
   void
   tree_evaluator::push_echo_state (int type, const std::string& file_name,
-                                   std::size_t pos)
+                                   int pos)
   {
     unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame ();
 
@@ -3891,7 +4599,7 @@
 
   void
   tree_evaluator::set_echo_state (int type, const std::string& file_name,
-                                  std::size_t pos)
+                                  int pos)
   {
     m_echo_state = echo_this_file (file_name, type);
     m_echo_file_name = file_name;
@@ -3900,7 +4608,7 @@
 
   void
   tree_evaluator::uwp_set_echo_state (bool state, const std::string& file_name,
-                                      std::size_t pos)
+                                      int pos)
   {
     m_echo_state = state;
     m_echo_file_name = file_name;
@@ -3920,7 +4628,14 @@
 
         std::string file_name = fcn->fcn_file_name ();
 
-        std::size_t pos = m_call_stack.current_line ();
+        // We want the line where "echo" was called, not the line number
+        // stored in the stack frame that was created for the echo
+        // function (that will always be -1).
+
+        int pos = m_call_stack.current_user_code_line ();
+
+        if (pos < 0)
+          pos = 1;
 
         set_echo_state (type, file_name, pos);
       }
@@ -3929,8 +4644,8 @@
   void
   tree_evaluator::push_echo_state_cleanup (unwind_protect& frame)
   {
-    frame.add_method (this, &tree_evaluator::uwp_set_echo_state,
-                      m_echo_state, m_echo_file_name, m_echo_file_pos);
+    frame.add (&tree_evaluator::uwp_set_echo_state, this,
+               m_echo_state, m_echo_file_name, m_echo_file_pos);
   }
 
   bool tree_evaluator::maybe_push_echo_state_cleanup (void)
@@ -4176,7 +4891,7 @@
             // evaluate the partial expression that the special "end"
             // token applies to in the calling stack frame.
 
-            unwind_action act ([this] (std::size_t frm)
+            unwind_action act ([=] (std::size_t frm)
                                {
                                  m_call_stack.restore_frame (frm);
                                }, m_call_stack.current_frame ());
@@ -4198,7 +4913,7 @@
             if (expr_result.is_cs_list ())
               err_indexed_cs_list ();
           }
-        catch (index_exception&)
+        catch (const index_exception&)
           {
             error ("error evaluating partial expression for END");
           }
@@ -4263,7 +4978,7 @@
     return false;
   }
 
-  void tree_evaluator::echo_code (std::size_t line)
+  void tree_evaluator::echo_code (int line)
   {
     std::string prefix = command_editor::decode_prompt_string (m_PS4);
 
@@ -4273,7 +4988,7 @@
       {
         octave_user_code *code = dynamic_cast<octave_user_code *> (curr_fcn);
 
-        std::size_t num_lines = line - m_echo_file_pos + 1;
+        int num_lines = line - m_echo_file_pos + 1;
 
         std::deque<std::string> lines
           = code->get_code_lines (m_echo_file_pos, num_lines);
@@ -4389,7 +5104,7 @@
 %! max_recursion_depth (orig_val);
 %! assert (max_recursion_depth (), orig_val);
 
-%!error (max_recursion_depth (1, 2))
+%!error max_recursion_depth (1, 2)
 */
 
 DEFMETHOD (whos_line_format, interp, args, nargout,
@@ -4457,7 +5172,7 @@
 
 The default format is:
 
-@qcode{"  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;@xbackslashchar{}n"}
+@qcode{"  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;@backslashchar{}n"}
 
 When called from inside a function with the @qcode{"local"} option, the
 variable is changed locally for the function and any subroutines it calls.
@@ -4501,7 +5216,7 @@
 %! silent_functions (orig_val);
 %! assert (silent_functions (), orig_val);
 
-%!error (silent_functions (1, 2))
+%!error silent_functions (1, 2)
 */
 
 DEFMETHOD (string_fill_char, interp, args, nargout,
@@ -4550,7 +5265,7 @@
 
 %!assert ( [ [], {1} ], {1} )
 
-%!error (string_fill_char (1, 2))
+%!error string_fill_char (1, 2)
 */
 
 DEFMETHOD (PS4, interp, args, nargout,
--- a/libinterp/parse-tree/pt-eval.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-eval.h	Sun May 16 09:44:35 2021 +0200
@@ -55,6 +55,7 @@
 
   class debugger;
   class interpreter;
+  class push_parser;
   class unwind_protect;
 
   // How to evaluate the code that the parse trees represent.
@@ -127,16 +128,17 @@
     typedef void (*decl_elt_init_fcn) (tree_decl_elt&);
 
     tree_evaluator (interpreter& interp)
-      : m_interpreter (interp), m_statement_context (SC_OTHER),
+      : m_interpreter (interp), m_parser (), m_statement_context (SC_OTHER),
         m_lvalue_list (nullptr), m_autoload_map (), m_bp_table (*this),
         m_call_stack (*this), m_profiler (), m_debug_frame (0),
         m_debug_mode (false), m_quiet_breakpoint_flag (false),
-        m_debugger_stack (), m_max_recursion_depth (256),
+        m_debugger_stack (), m_exit_status (0), m_max_recursion_depth (256),
         m_whos_line_format ("  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;\n"),
-        m_silent_functions (false), m_string_fill_char (' '),
-        m_PS4 ("+ "), m_dbstep_flag (0), m_echo (ECHO_OFF),
+        m_silent_functions (false), m_string_fill_char (' '), m_PS4 ("+ "),
+        m_dbstep_flag (0), m_break_on_next_stmt (false), m_echo (ECHO_OFF),
         m_echo_state (false), m_echo_file_name (), m_echo_file_pos (1),
-        m_echo_files (), m_in_loop_command (false),
+        m_echo_files (), m_in_top_level_repl (false),
+        m_server_mode (false), m_in_loop_command (false),
         m_breaking (0), m_continuing (0), m_returning (0),
         m_indexed_object (), m_index_list (), m_index_type (),
         m_index_position (0), m_num_indices (0)
@@ -150,13 +152,41 @@
 
     ~tree_evaluator (void) = default;
 
+    std::shared_ptr<push_parser> get_parser (void)
+    {
+      return m_parser;
+    }
+
+    void set_parser (const std::shared_ptr<push_parser>& parser)
+    {
+      m_parser = parser;
+    }
+
     bool at_top_level (void) const;
 
+    std::string mfilename (const std::string& opt = "") const;
+
+    // Parse a line of input.  If input ends at a complete statement
+    // boundary, execute the resulting parse tree.  Useful to handle
+    // parsing user input when running in server mode.
+
+    void parse_and_execute (const std::string& input, bool& incomplete_parse);
+
+    void get_line_and_eval (void);
+
+    int repl (void);
+
+    bool in_top_level_repl (void) const { return m_in_top_level_repl; }
+
+    int server_loop (void);
+
+    bool server_mode (void) const { return m_server_mode; }
+
+    void server_mode (bool arg) { m_server_mode = arg; }
+
     void eval (std::shared_ptr<tree_statement_list>& stmt_list,
                bool interactive);
 
-    std::string mfilename (const std::string& opt = "") const;
-
     octave_value_list eval_string (const std::string& eval_str, bool silent,
                                    int& parse_status, int nargout);
 
@@ -202,6 +232,8 @@
 
     void visit_complex_for_command (tree_complex_for_command&);
 
+    void visit_spmd_command (tree_spmd_command&);
+
     void visit_octave_user_script (octave_user_script&);
 
     octave_value_list
@@ -613,8 +645,39 @@
 
     void dbcont (void);
 
+    // Return true if we are in the debug repl and m_execution_mode is
+    // set to exit the debugger.  Otherwise, do nothing.
+
     void dbquit (bool all = false);
 
+    // Add EXPR to the set of expressions that may be evaluated when the
+    // debugger stops at a breakpoint.
+    void add_debug_watch_expression (const std::string& expr)
+    {
+      m_debug_watch_expressions.insert (expr);
+    }
+
+    // Remove EXPR from the set of expressions that may be evaluated
+    // when the debugger stops at a breakpoint.
+    void remove_debug_watch_expression (const std::string& expr)
+    {
+      m_debug_watch_expressions.erase (expr);
+    }
+
+    // Clear the set of expressions that may be evaluated when the
+    // debugger stops at a breakpoint.
+    void clear_debug_watch_expressions (void)
+    {
+      m_debug_watch_expressions.clear ();
+    }
+
+    // Return the set of expressions that may be evaluated when the
+    // debugger stops at a breakpoint.
+    std::set<std::string> debug_watch_expressions (void) const
+    {
+      return m_debug_watch_expressions;
+    }
+
     octave_value PS4 (const octave_value_list& args, int nargout);
 
     std::string PS4 (void) const { return m_PS4; }
@@ -719,6 +782,23 @@
 
     void set_dbstep_flag (int step) { m_dbstep_flag = step; }
 
+    bool break_on_next_statement (void) const
+    {
+      return m_break_on_next_stmt;
+    }
+
+    bool break_on_next_statement (bool val)
+    {
+      bool old_val = m_break_on_next_stmt;
+      m_break_on_next_stmt = val;
+      return old_val;
+    }
+
+    void set_break_on_next_statement (bool val)
+    {
+      m_break_on_next_stmt = val;
+    }
+
     octave_value echo (const octave_value_list& args, int nargout);
 
     int echo (void) const { return m_echo; }
@@ -733,7 +813,7 @@
     octave_value
     string_fill_char (const octave_value_list& args, int nargout);
 
-    void final_index_error (index_exception& e, const tree_expression *expr);
+    void final_index_error (index_exception& ie, const tree_expression *expr);
 
     octave_value do_who (int argc, const string_vector& argv,
                          bool return_list, bool verbose = false);
@@ -743,12 +823,16 @@
 
     std::list<octave_lvalue> make_lvalue_list (tree_argument_list *);
 
-    void push_echo_state (int type, const std::string& file_name,
-                          std::size_t pos = 1);
+    void push_echo_state (int type, const std::string& file_name, int pos = 1);
 
   private:
 
-    void set_echo_state (int type, const std::string& file_name, std::size_t pos);
+    template <typename T>
+    void execute_range_loop (const range<T>& rng, int line,
+                             octave_lvalue& ult,
+                             tree_statement_list *loop_body);
+
+    void set_echo_state (int type, const std::string& file_name, int pos);
 
     void maybe_set_echo_state (void);
 
@@ -764,12 +848,11 @@
     bool is_logically_true (tree_expression *expr, const char *warn_for);
 
     // For unwind-protect.
-    void uwp_set_echo_state (bool state, const std::string& file_name,
-                             std::size_t pos);
+    void uwp_set_echo_state (bool state, const std::string& file_name, int pos);
 
     bool echo_this_file (const std::string& file, int type) const;
 
-    void echo_code (std::size_t line);
+    void echo_code (int line);
 
     bool quit_loop_now (void);
 
@@ -782,6 +865,8 @@
 
     interpreter& m_interpreter;
 
+    std::shared_ptr<push_parser> m_parser;
+
     // The context for the current evaluation.
     stmt_list_type m_statement_context;
 
@@ -810,6 +895,10 @@
     // previous debugger (if any) that is now at the top of the stack.
     std::stack<debugger *> m_debugger_stack;
 
+    std::set<std::string> m_debug_watch_expressions;
+
+    int m_exit_status;
+
     // Maximum nesting level for functions, scripts, or sourced files
     // called recursively.
     int m_max_recursion_depth;
@@ -833,6 +922,10 @@
     // If < 0, stop executing at the next possible stopping point.
     int m_dbstep_flag;
 
+    // If TRUE, and we are not stopping for another reason (dbstep or a
+    // breakpoint) then stop at next statement and enter the debugger.
+    bool m_break_on_next_stmt;
+
     // Echo commands as they are executed?
     //
     //   1  ==>  echo commands read from script files
@@ -847,11 +940,24 @@
 
     std::string m_echo_file_name;
 
-    // Next line to echo, counting from 1.
-    std::size_t m_echo_file_pos;
+    // Next line to echo, counting from 1.  We use int here because the
+    // parser does.  It also initializes line and column numbers to the
+    // invalid value -1 and that can cause trouble if cast to an
+    // unsigned value.  When updating this value and echoing ranges of
+    // code, we also check to ensure that the line numbers stored in the
+    // parse tree are valid.  It would be better to ensure that the
+    // parser always stores valid position info, but that's more
+    // difficult to always do correctly.
+    int m_echo_file_pos;
 
     std::map<std::string, bool> m_echo_files;
 
+    // TRUE if we are in the top level interactive read eval print loop.
+    bool m_in_top_level_repl;
+
+    // TRUE means we are executing in the server_loop function.
+    bool m_server_mode;
+
     // TRUE means we are evaluating some kind of looping construct.
     bool m_in_loop_command;
 
--- a/libinterp/parse-tree/pt-idx.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-idx.cc	Sun May 16 09:44:35 2021 +0200
@@ -401,9 +401,9 @@
                   {
                     retval = fcn->call (tw, nargout, first_args);
                   }
-                catch (index_exception& e)
+                catch (index_exception& ie)
                   {
-                    tw.final_index_error (e, m_expr);
+                    tw.final_index_error (ie, m_expr);
                   }
 
                 beg++;
@@ -527,9 +527,9 @@
                           indexing_object = true;
                         }
                     }
-                  catch (index_exception& e)
+                  catch (index_exception& ie)
                     {
-                      tw.final_index_error (e, m_expr);
+                      tw.final_index_error (ie, m_expr);
                     }
                 }
             }
@@ -588,9 +588,9 @@
                 beg = n;
                 idx_list.clear ();
               }
-            catch (index_exception& e)
+            catch (index_exception& ie)
               {
-                tw.final_index_error (e, m_expr);
+                tw.final_index_error (ie, m_expr);
               }
           }
         else
@@ -624,9 +624,9 @@
 
                     retval = fcn->call (tw, nargout, final_args);
                   }
-                catch (index_exception& e)
+                catch (index_exception& ie)
                   {
-                    tw.final_index_error (e, m_expr);
+                    tw.final_index_error (ie, m_expr);
                   }
               }
           }
--- a/libinterp/parse-tree/pt-jit.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-jit.cc	Sun May 16 09:44:35 2021 +0200
@@ -715,7 +715,7 @@
       }
     else if (ty == jit_typeinfo::get_range ())
       {
-        Range rv = v.range_value ();
+        range<double> rv = v.range_value ();
         m_result = m_factory.create<jit_const_range> (rv);
       }
     else if (ty == jit_typeinfo::get_complex ())
@@ -1234,9 +1234,8 @@
 
     for (std::size_t idx = 0; iter != arg_list->end (); ++idx, ++iter)
       {
-        unwind_protect frame;
-        frame.add_method (&m_end_context,
-                          &std::vector<jit_magic_end::context>::pop_back);
+        unwind_action pop_end_context
+          (&std::vector<jit_magic_end::context>::pop_back, &m_end_context));
 
         jit_magic_end::context ctx (m_factory, object, idx, narg);
         m_end_context.push_back (ctx);
@@ -1365,7 +1364,7 @@
 
         convert (blocks, constants);
       }
-    catch (const jit_fail_exception& e)
+    catch (const jit_fail_exception&)
       {
         m_function->eraseFromParent ();
         throw;
@@ -1411,7 +1410,7 @@
 
         convert (blocks, constants);
       }
-    catch (const jit_fail_exception& e)
+    catch (const jit_fail_exception&)
       {
         m_function->eraseFromParent ();
         throw;
@@ -2314,7 +2313,7 @@
   {
     if (bounds.is_range ())
       {
-        Range rng = bounds.range_value ();
+        range<double> rng = bounds.range_value ();
         return rng.numel ();
       }
 
@@ -2596,14 +2595,14 @@
             m_function = reinterpret_cast<jited_function> (void_fn);
           }
       }
-    catch (const jit_fail_exception& e)
+    catch (const jit_fail_exception& jfe)
       {
         m_argument_types.clear ();
 
         if (Vdebug_jit)
           {
-            if (e.known ())
-              octave_stdout << "jit fail: " << e.what () << std::endl;
+            if (jfe.known ())
+              octave_stdout << "jit fail: " << jfe.what () << std::endl;
           }
 
         Vjit_failcnt++;
@@ -2772,16 +2771,15 @@
 
         m_bounds = conv.get_bounds ();
       }
-    catch (const jit_fail_exception& e)
+    catch (const jit_fail_exception& jfe)
       {
         if (Vdebug_jit)
           {
-            if (e.known ())
-              octave_stdout << "jit fail: " << e.what () << std::endl;
+            if (jfe.known ())
+              octave_stdout << "jit fail: " << jfe.what () << std::endl;
           }
 
         Vjit_failcnt++;
-
       }
 
     if (llvm_function)
--- a/libinterp/parse-tree/pt-misc.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-misc.h	Sun May 16 09:44:35 2021 +0200
@@ -115,10 +115,4 @@
   };
 }
 
-#if defined (OCTAVE_USE_DEPRECATED_FUNCTIONS)
-
-// tree_parameter_list is derived from a template.
-
 #endif
-
-#endif
--- a/libinterp/parse-tree/pt-pr-code.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-pr-code.cc	Sun May 16 09:44:35 2021 +0200
@@ -293,6 +293,35 @@
   }
 
   void
+  tree_print_code::visit_spmd_command (tree_spmd_command& cmd)
+  {
+    print_comment_list (cmd.leading_comment ());
+
+    indent ();
+
+    m_os << "spmd";
+
+    newline ();
+
+    tree_statement_list *list = cmd.body ();
+
+    if (list)
+      {
+        increment_indent_level ();
+
+        list->accept (*this);
+
+        decrement_indent_level ();
+      }
+
+    print_indented_comment (cmd.trailing_comment ());
+
+    indent ();
+
+    m_os << "endspmd";
+  }
+
+  void
   tree_print_code::visit_octave_user_script (octave_user_script& fcn)
   {
     reset ();
--- a/libinterp/parse-tree/pt-pr-code.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-pr-code.h	Sun May 16 09:44:35 2021 +0200
@@ -88,6 +88,8 @@
 
     void visit_complex_for_command (tree_complex_for_command&);
 
+    void visit_spmd_command (tree_spmd_command&);
+
     void visit_octave_user_script (octave_user_script&);
 
     void visit_octave_user_function (octave_user_function&);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-spmd.cc	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "comment-list.h"
+#include "pt-spmd.h"
+#include "pt-stmt.h"
+
+namespace octave
+{
+  tree_spmd_command::~tree_spmd_command (void)
+  {
+    delete m_body;
+    delete m_lead_comm;
+    delete m_trail_comm;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-spmd.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,83 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_pt_spmd_command_h)
+#define octave_pt_spmd_command_h 1
+
+#include "octave-config.h"
+
+#include "base-list.h"
+#include "pt-cmd.h"
+#include "pt-walk.h"
+
+namespace octave
+{
+  class tree_comment_list;
+  class tree_statement_list;
+
+  // Spmd.
+
+  class tree_spmd_command : public tree_command
+  {
+  public:
+
+    tree_spmd_command (tree_statement_list *body, comment_list *lc,
+                       comment_list *tc, int l = -1, int c = -1)
+      : tree_command (l, c), m_body (body), m_lead_comm (lc), m_trail_comm (tc)
+    { }
+
+    // No copying!
+
+    tree_spmd_command (const tree_spmd_command&) = delete;
+
+    tree_spmd_command& operator = (const tree_spmd_command&) = delete;
+
+    ~tree_spmd_command (void);
+
+    tree_statement_list * body (void) { return m_body; }
+
+    comment_list * leading_comment (void) { return m_lead_comm; }
+
+    comment_list * trailing_comment (void) { return m_trail_comm; }
+
+    void accept (tree_walker& tw)
+    {
+      tw.visit_spmd_command (*this);
+    }
+
+  private:
+
+    // List of commands.
+    tree_statement_list *m_body;
+
+    // Comment preceding SPMD token.
+    comment_list *m_lead_comm;
+
+    // Comment preceding ENDSPMD token.
+    comment_list *m_trail_comm;
+  };
+}
+
+#endif
--- a/libinterp/parse-tree/pt-stmt.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-stmt.cc	Sun May 16 09:44:35 2021 +0200
@@ -249,49 +249,45 @@
   // Updates GUI via  event_manager::update_breakpoint.
   // FIXME: COME BACK TO ME.
 
-  bp_table::intmap
+  bp_table::bp_lines
   tree_statement_list::add_breakpoint (event_manager& evmgr,
                                        const std::string& file,
-                                       const bp_table::intmap& line,
+                                       const bp_table::bp_lines& lines,
                                        const std::string& condition)
   {
-    bp_table::intmap retval;
-
-    octave_idx_type len = line.size ();
+    bp_table::bp_lines retval;
 
-    for (int i = 0; i < len; i++)
+    for (const auto& lineno : lines)
       {
-        bp_table::const_intmap_iterator p = line.find (i);
+        int line = set_breakpoint (lineno, condition);
 
-        if (p != line.end ())
+        if (line)
           {
-            int lineno = p->second;
+            if (! file.empty ())
+              evmgr.update_breakpoint (true, file, line, condition);
 
-            retval[i] = set_breakpoint (lineno, condition);
-
-            if (retval[i] != 0 && ! file.empty ())
-              evmgr.update_breakpoint (true, file, retval[i], condition);
+            retval.insert (line);
           }
       }
 
     return retval;
   }
 
-  bp_table::intmap
+  bp_table::bp_lines
   tree_statement_list::remove_all_breakpoints (event_manager& evmgr,
                                                const std::string& file)
   {
-    bp_table::intmap retval;
+    bp_table::bp_lines retval;
 
     octave_value_list bkpts = list_breakpoints ();
 
     for (int i = 0; i < bkpts.length (); i++)
       {
-        int lineno = static_cast<int> (bkpts(i).int_value ());
+        int lineno = bkpts(i).int_value ();
 
         delete_breakpoint (lineno);
 
-        retval[i] = lineno;
+        retval.insert (lineno);
 
         if (! file.empty ())
           evmgr.update_breakpoint (false, file, lineno);
--- a/libinterp/parse-tree/pt-stmt.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-stmt.h	Sun May 16 09:44:35 2021 +0200
@@ -188,13 +188,13 @@
 
     std::list<bp_type> breakpoints_and_conds (void);
 
-    bp_table::intmap add_breakpoint (event_manager& evmgr,
-                                     const std::string& file,
-                                     const bp_table::intmap& line,
-                                     const std::string& condition);
+    bp_table::bp_lines add_breakpoint (event_manager& evmgr,
+                                       const std::string& file,
+                                       const bp_table::bp_lines& lines,
+                                       const std::string& condition);
 
-    bp_table::intmap remove_all_breakpoints (event_manager& evmgr,
-                                             const std::string& file);
+    bp_table::bp_lines remove_all_breakpoints (event_manager& evmgr,
+                                               const std::string& file);
 
     void accept (tree_walker& tw)
     {
--- a/libinterp/parse-tree/pt-tm-const.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-tm-const.cc	Sun May 16 09:44:35 2021 +0200
@@ -461,7 +461,7 @@
     // full.  This is done since it means that there is no recopying of
     // data, as would happen if we used a single resize.  It should be
     // noted that resize operation is also significantly slower than the
-    // do_cat_op function, so it makes sense to have an empty matrix and
+    // cat_op function, so it makes sense to have an empty matrix and
     // copy all data.
     //
     // We might also start with a empty octave_value using
@@ -532,7 +532,7 @@
             if (elt.isempty ())
               continue;
 
-            ctmp = do_cat_op (ti, ctmp, elt, ra_idx);
+            ctmp = cat_op (ti, ctmp, elt, ra_idx);
 
             ra_idx (1) += elt.columns ();
           }
--- a/libinterp/parse-tree/pt-unop.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-unop.cc	Sun May 16 09:44:35 2021 +0200
@@ -71,7 +71,7 @@
             profiler::enter<tree_prefix_expression>
               block (tw.get_profiler (), *this);
 
-            op_ref.do_unary_op (m_etype);
+            op_ref.unary_op (m_etype);
 
             val = op_ref.value ();
           }
@@ -87,14 +87,14 @@
                 // Attempt to do the operation in-place if it is unshared
                 // (a temporary expression).
                 if (op_val.get_count () == 1)
-                  val = op_val.do_non_const_unary_op (m_etype);
+                  val = op_val.non_const_unary_op (m_etype);
                 else
                   {
                     interpreter& interp = tw.get_interpreter ();
 
                     type_info& ti = interp.get_type_info ();
 
-                    val = ::do_unary_op (ti, m_etype, op_val);
+                    val = unary_op (ti, m_etype, op_val);
                   }
               }
           }
@@ -134,7 +134,7 @@
             profiler::enter<tree_postfix_expression>
               block (tw.get_profiler (), *this);
 
-            ref.do_unary_op (m_etype);
+            ref.unary_op (m_etype);
           }
         else
           {
@@ -149,7 +149,7 @@
 
                 type_info& ti = interp.get_type_info ();
 
-                val = ::do_unary_op (ti, m_etype, op_val);
+                val = unary_op (ti, m_etype, op_val);
               }
           }
       }
--- a/libinterp/parse-tree/pt-walk.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-walk.cc	Sun May 16 09:44:35 2021 +0200
@@ -174,6 +174,14 @@
       list->accept (*this);
   }
 
+  void tree_walker::visit_spmd_command (tree_spmd_command& cmd)
+  {
+    tree_statement_list *body = cmd.body ();
+
+    if (body)
+      body->accept (*this);
+  }
+
   void tree_walker::visit_octave_user_script (octave_user_script& fcn)
   {
     tree_statement_list *cmd_list = fcn.body ();
--- a/libinterp/parse-tree/pt-walk.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt-walk.h	Sun May 16 09:44:35 2021 +0200
@@ -53,6 +53,7 @@
   class tree_decl_elt;
   class tree_simple_for_command;
   class tree_complex_for_command;
+  class tree_spmd_command;
   class tree_function_def;
   class tree_identifier;
   class tree_if_clause;
@@ -142,6 +143,8 @@
 
     virtual void visit_complex_for_command (tree_complex_for_command&);
 
+    virtual void visit_spmd_command (tree_spmd_command&);
+
     virtual void visit_octave_user_script (octave_user_script&);
 
     virtual void visit_octave_user_function (octave_user_function&);
--- a/libinterp/parse-tree/pt.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/pt.cc	Sun May 16 09:44:35 2021 +0200
@@ -91,13 +91,13 @@
             else
               warning ("Error parsing breakpoint condition");
           }
-        catch (const execution_exception& e)
+        catch (const execution_exception& ee)
           {
             interpreter& interp = tw.get_interpreter ();
 
             interp.recover_from_exception ();
 
-            std::string tmp = e.message ();
+            std::string tmp = ee.message ();
 
             warning ("Error evaluating breakpoint condition:\n    %s",
                      tmp.c_str ());
--- a/libinterp/parse-tree/token.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/token.cc	Sun May 16 09:44:35 2021 +0200
@@ -62,11 +62,11 @@
       m_tok_info (s), m_orig_text ()
   { }
 
-  token::token (int tv, double d, const std::string& s, const filepos& beg_pos,
-                const filepos& end_pos)
+  token::token (int tv, const octave_value& val, const std::string& s,
+                const filepos& beg_pos, const filepos& end_pos)
     : m_maybe_cmd (false), m_tspc (false), m_beg_pos (beg_pos),
-      m_end_pos (end_pos), m_tok_val (tv), m_type_tag (double_token),
-      m_tok_info (d), m_orig_text (s)
+      m_end_pos (end_pos), m_tok_val (tv), m_type_tag (numeric_token),
+      m_tok_info (val), m_orig_text (s)
   { }
 
   token::token (int tv, end_tok_type t, const filepos& beg_pos,
@@ -114,11 +114,11 @@
     return m_tok_info.m_sr->name ();
   }
 
-  double
+  octave_value
   token::number (void) const
   {
-    assert (m_type_tag == double_token);
-    return m_tok_info.m_num;
+    assert (m_type_tag == numeric_token);
+    return *m_tok_info.m_num;
   }
 
   token::token_type
--- a/libinterp/parse-tree/token.h	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/parse-tree/token.h	Sun May 16 09:44:35 2021 +0200
@@ -31,6 +31,7 @@
 #include <string>
 
 #include "filepos.h"
+#include "ov.h"
 #include "symrec.h"
 
 namespace octave
@@ -44,7 +45,7 @@
       generic_token,
       keyword_token,
       string_token,
-      double_token,
+      numeric_token,
       ettype_token,
       sym_rec_token,
       scls_name_token,
@@ -65,6 +66,7 @@
       switch_end,
       try_catch_end,
       unwind_protect_end,
+      spmd_end,
       while_end,
     };
 
@@ -79,8 +81,8 @@
     token (int tv, const std::string& s, const filepos& beg_pos,
            const filepos& end_pos);
 
-    token (int tv, double d, const std::string& s, const filepos& beg_pos,
-           const filepos& end_pos);
+    token (int tv, const octave_value& val, const std::string& s,
+           const filepos& beg_pos, const filepos& end_pos);
 
     token (int tv, end_tok_type t, const filepos& beg_pos,
            const filepos& end_pos);
@@ -123,12 +125,6 @@
       return m_type_tag == keyword_token || m_type_tag == ettype_token;
     }
 
-    OCTAVE_DEPRECATED (5, "use 'octave::iskeyword' instead")
-    bool is_keyword (void) const
-    {
-      return iskeyword ();
-    }
-
     bool is_symbol (void) const
     {
       return m_type_tag == sym_rec_token;
@@ -136,7 +132,7 @@
 
     std::string text (void) const;
     std::string symbol_name (void) const;
-    double number (void) const;
+    octave_value number (void) const;
     token_type ttype (void) const;
     end_tok_type ettype (void) const;
     symbol_record sym_rec (void) const;
@@ -167,7 +163,7 @@
 
       tok_info (const std::string& str) : m_str (new std::string (str)) { }
 
-      tok_info (double num) : m_num (num) { }
+      tok_info (const octave_value& num) : m_num (new octave_value (num)) { }
 
       tok_info (end_tok_type et) : m_et (et) { }
 
@@ -187,7 +183,7 @@
 
       std::string *m_str;
 
-      double m_num;
+      octave_value *m_num;
 
       end_tok_type m_et;
 
--- a/libinterp/template-inst/Array-jit.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/template-inst/Array-jit.cc	Sun May 16 09:44:35 2021 +0200
@@ -37,12 +37,16 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
+
+NO_INSTANTIATE_ARRAY_SORT (octave::jit_function, OCTINTERP_API);
 
-NO_INSTANTIATE_ARRAY_SORT (octave::jit_function);
-
+// Visibility attributes are ignored on template instantiation.
+// As a work-around, set visibility to default overriding compiler options.
+#pragma GCC visibility push(default)
 INSTANTIATE_ARRAY (octave::jit_function, OCTINTERP_API);
+#pragma GCC visibility pop
 
 #if defined (Cell_h)
 #  error Must not include Cell.h in Array-jit.h
--- a/libinterp/template-inst/Array-tc.cc	Sun May 16 09:43:43 2021 +0200
+++ b/libinterp/template-inst/Array-tc.cc	Sun May 16 09:44:35 2021 +0200
@@ -41,21 +41,26 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<Complex>;
-extern template class OCTAVE_API Array<FloatComplex>;
-extern template class OCTAVE_API Array<bool>;
-extern template class OCTAVE_API Array<char>;
-extern template class OCTAVE_API Array<double>;
-extern template class OCTAVE_API Array<float>;
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
-extern template class OCTAVE_API Array<std::string>;
+extern template class Array<Complex>;
+extern template class Array<FloatComplex>;
+extern template class Array<bool>;
+extern template class Array<char>;
+extern template class Array<double>;
+extern template class Array<float>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
+extern template class Array<std::string>;
 
-NO_INSTANTIATE_ARRAY_SORT (octave_value);
+// Visibility attributes are ignored on template instantiation.
+// As a work-around, set visibility to default overriding compiler options.
+#pragma GCC visibility push(default)
+NO_INSTANTIATE_ARRAY_SORT (octave_value, OCTINTERP_API);
 INSTANTIATE_ARRAY (octave_value, OCTINTERP_API);
 
-NO_INSTANTIATE_ARRAY_SORT (octave_value *);
+NO_INSTANTIATE_ARRAY_SORT (octave_value *, OCTINTERP_API);
 INSTANTIATE_ARRAY (octave_value *, OCTINTERP_API);
 
-NO_INSTANTIATE_ARRAY_SORT (octave::cdef_object);
+NO_INSTANTIATE_ARRAY_SORT (octave::cdef_object, OCTINTERP_API);
 INSTANTIATE_ARRAY (octave::cdef_object, OCTINTERP_API);
+#pragma GCC visibility pop
+
--- a/liboctave/array/Array-C.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-C.cc	Sun May 16 09:44:35 2021 +0200
@@ -39,8 +39,8 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
 template <>
 inline bool
@@ -92,7 +92,7 @@
   return result;
 }
 
-template class OCTAVE_API octave_sort<Complex>;
+template class octave_sort<Complex>;
 
 INSTANTIATE_ARRAY (Complex, OCTAVE_API);
 
@@ -102,4 +102,4 @@
 #include "DiagArray2.h"
 #include "DiagArray2.cc"
 
-template class OCTAVE_API DiagArray2<Complex>;
+template class DiagArray2<Complex>;
--- a/liboctave/array/Array-b.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-b.cc	Sun May 16 09:44:35 2021 +0200
@@ -39,8 +39,8 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
 // Specialize bool sorting (aka stable partitioning).
 
@@ -118,7 +118,7 @@
   do_bool_partition<true> (data, idx, nel);
 }
 
-template class OCTAVE_API octave_sort<bool>;
+template class octave_sort<bool>;
 
 INSTANTIATE_ARRAY (bool, OCTAVE_API);
 
@@ -128,4 +128,4 @@
 #include "DiagArray2.h"
 #include "DiagArray2.cc"
 
-template class OCTAVE_API DiagArray2<bool>;
+template class DiagArray2<bool>;
--- a/liboctave/array/Array-ch.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-ch.cc	Sun May 16 09:44:35 2021 +0200
@@ -39,10 +39,10 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
-template class OCTAVE_API octave_sort<char>;
+template class octave_sort<char>;
 
 INSTANTIATE_ARRAY (char, OCTAVE_API);
 
@@ -52,4 +52,4 @@
 #include "DiagArray2.h"
 #include "DiagArray2.cc"
 
-template class OCTAVE_API DiagArray2<char>;
+template class DiagArray2<char>;
--- a/liboctave/array/Array-d.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-d.cc	Sun May 16 09:44:35 2021 +0200
@@ -41,8 +41,8 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
 template <>
 inline bool
@@ -163,7 +163,7 @@
   return mode;
 }
 
-template class OCTAVE_API octave_sort<double>;
+template class octave_sort<double>;
 
 INSTANTIATE_ARRAY (double, OCTAVE_API);
 
@@ -173,4 +173,4 @@
 #include "DiagArray2.h"
 #include "DiagArray2.cc"
 
-template class OCTAVE_API DiagArray2<double>;
+template class DiagArray2<double>;
--- a/liboctave/array/Array-f.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-f.cc	Sun May 16 09:44:35 2021 +0200
@@ -41,8 +41,8 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
 template <>
 inline bool
@@ -163,7 +163,7 @@
   return mode;
 }
 
-template class OCTAVE_API octave_sort<float>;
+template class octave_sort<float>;
 
 INSTANTIATE_ARRAY (float, OCTAVE_API);
 
@@ -173,4 +173,4 @@
 #include "DiagArray2.h"
 #include "DiagArray2.cc"
 
-template class OCTAVE_API DiagArray2<float>;
+template class DiagArray2<float>;
--- a/liboctave/array/Array-fC.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-fC.cc	Sun May 16 09:44:35 2021 +0200
@@ -39,8 +39,8 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
 template <>
 inline bool
@@ -92,7 +92,7 @@
   return result;
 }
 
-template class OCTAVE_API octave_sort<FloatComplex>;
+template class octave_sort<FloatComplex>;
 
 INSTANTIATE_ARRAY (FloatComplex, OCTAVE_API);
 
@@ -102,4 +102,4 @@
 #include "DiagArray2.h"
 #include "DiagArray2.cc"
 
-template class OCTAVE_API DiagArray2<FloatComplex>;
+template class DiagArray2<FloatComplex>;
--- a/liboctave/array/Array-i.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-i.cc	Sun May 16 09:44:35 2021 +0200
@@ -41,34 +41,53 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
+extern template class Array<octave::idx_vector>;
 
-template class OCTAVE_API octave_sort<int>;
-template class OCTAVE_API octave_sort<long>;
+template class octave_sort<signed char>;
+//template class octave_sort<short>;
+template class octave_sort<int>;
+template class octave_sort<long>;
 #if defined (OCTAVE_HAVE_LONG_LONG_INT)
-template class OCTAVE_API octave_sort<long long>;
+template class octave_sort<long long>;
 #endif
 
+INSTANTIATE_ARRAY (signed char, OCTAVE_API);
+//INSTANTIATE_ARRAY (short, OCTAVE_API);
 INSTANTIATE_ARRAY (int, OCTAVE_API);
 INSTANTIATE_ARRAY (long, OCTAVE_API);
 #if defined (OCTAVE_HAVE_LONG_LONG_INT)
 INSTANTIATE_ARRAY (long long, OCTAVE_API);
 #endif
 
-template class OCTAVE_API octave_sort<octave_int8>;
-template class OCTAVE_API octave_sort<octave_int16>;
-template class OCTAVE_API octave_sort<octave_int32>;
-template class OCTAVE_API octave_sort<octave_int64>;
+template class octave_sort<unsigned char>;
+template class octave_sort<unsigned short>;
+template class octave_sort<unsigned int>;
+template class octave_sort<unsigned long>;
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+template class octave_sort<unsigned long long>;
+#endif
+
+INSTANTIATE_ARRAY (unsigned char, OCTAVE_API);
+INSTANTIATE_ARRAY (unsigned short, OCTAVE_API);
+INSTANTIATE_ARRAY (unsigned int, OCTAVE_API);
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+INSTANTIATE_ARRAY (unsigned long long, OCTAVE_API);
+#endif
+
+template class octave_sort<octave_int8>;
+template class octave_sort<octave_int16>;
+template class octave_sort<octave_int32>;
+template class octave_sort<octave_int64>;
 
 INSTANTIATE_ARRAY (octave_int8, OCTAVE_API);
 INSTANTIATE_ARRAY (octave_int16, OCTAVE_API);
 INSTANTIATE_ARRAY (octave_int32, OCTAVE_API);
 INSTANTIATE_ARRAY (octave_int64, OCTAVE_API);
 
-template class OCTAVE_API octave_sort<octave_uint8>;
-template class OCTAVE_API octave_sort<octave_uint16>;
-template class OCTAVE_API octave_sort<octave_uint32>;
-template class OCTAVE_API octave_sort<octave_uint64>;
+template class octave_sort<octave_uint8>;
+template class octave_sort<octave_uint16>;
+template class octave_sort<octave_uint32>;
+template class octave_sort<octave_uint64>;
 
 INSTANTIATE_ARRAY (octave_uint8, OCTAVE_API);
 INSTANTIATE_ARRAY (octave_uint16, OCTAVE_API);
@@ -78,4 +97,4 @@
 #include "DiagArray2.h"
 #include "DiagArray2.cc"
 
-template class OCTAVE_API DiagArray2<int>;
+template class DiagArray2<int>;
--- a/liboctave/array/Array-idx-vec.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-idx-vec.cc	Sun May 16 09:44:35 2021 +0200
@@ -37,8 +37,8 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave_idx_type>;
 
-NO_INSTANTIATE_ARRAY_SORT (idx_vector);
+NO_INSTANTIATE_ARRAY_SORT (octave::idx_vector, OCTAVE_API);
 
-INSTANTIATE_ARRAY (idx_vector, OCTAVE_API);
+INSTANTIATE_ARRAY (octave::idx_vector, OCTAVE_API);
--- a/liboctave/array/Array-s.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-s.cc	Sun May 16 09:44:35 2021 +0200
@@ -39,10 +39,10 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
-template class OCTAVE_API octave_sort<short>;
+template class octave_sort<short>;
 
 INSTANTIATE_ARRAY (short, OCTAVE_API);
 
--- a/liboctave/array/Array-str.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-str.cc	Sun May 16 09:44:35 2021 +0200
@@ -39,9 +39,9 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
-template class OCTAVE_API octave_sort<std::string>;
+template class octave_sort<std::string>;
 
 INSTANTIATE_ARRAY (std::string, OCTAVE_API);
--- a/liboctave/array/Array-util.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-util.cc	Sun May 16 09:44:35 2021 +0200
@@ -236,7 +236,7 @@
 }
 
 Array<octave_idx_type>
-conv_to_int_array (const Array<idx_vector>& a)
+conv_to_int_array (const Array<octave::idx_vector>& a)
 {
   Array<octave_idx_type> retval (a.dims ());
 
@@ -246,10 +246,10 @@
   return retval;
 }
 
-Array<idx_vector>
-conv_to_array (const idx_vector *tmp, const octave_idx_type len)
+Array<octave::idx_vector>
+conv_to_array (const octave::idx_vector *tmp, const octave_idx_type len)
 {
-  Array<idx_vector> retval (dim_vector (len, 1));
+  Array<octave::idx_vector> retval (dim_vector (len, 1));
 
   for (octave_idx_type i = 0; i < len; i++)
     retval(i) = tmp[i];
@@ -258,7 +258,7 @@
 }
 
 dim_vector
-freeze (Array<idx_vector>& ra_idx, const dim_vector& dimensions, int resize_ok)
+freeze (Array<octave::idx_vector>& ra_idx, const dim_vector& dimensions, int resize_ok)
 {
   dim_vector retval;
 
@@ -299,7 +299,7 @@
 }
 
 bool
-all_ok (const Array<idx_vector>& ra_idx)
+all_ok (const Array<octave::idx_vector>& ra_idx)
 {
   bool retval = true;
 
@@ -318,7 +318,7 @@
 }
 
 bool
-any_orig_empty (const Array<idx_vector>& ra_idx)
+any_orig_empty (const Array<octave::idx_vector>& ra_idx)
 {
   bool retval = false;
 
@@ -337,7 +337,7 @@
 }
 
 bool
-all_colon_equiv (const Array<idx_vector>& ra_idx,
+all_colon_equiv (const Array<octave::idx_vector>& ra_idx,
                  const dim_vector& frozen_lengths)
 {
   bool retval = true;
@@ -378,7 +378,7 @@
 }
 
 Array<octave_idx_type>
-get_elt_idx (const Array<idx_vector>& ra_idx,
+get_elt_idx (const Array<octave::idx_vector>& ra_idx,
              const Array<octave_idx_type>& result_idx)
 {
   octave_idx_type n = ra_idx.numel ();
@@ -426,7 +426,7 @@
 }
 
 dim_vector
-zero_dims_inquire (const Array<idx_vector>& ia, const dim_vector& rhdv)
+zero_dims_inquire (const Array<octave::idx_vector>& ia, const dim_vector& rhdv)
 {
   int ial = ia.numel ();
   int rhdvl = rhdv.ndims ();
@@ -483,7 +483,7 @@
 }
 
 dim_vector
-zero_dims_inquire (const idx_vector& i, const idx_vector& j,
+zero_dims_inquire (const octave::idx_vector& i, const octave::idx_vector& j,
                    const dim_vector& rhdv)
 {
   bool icol = i.is_colon ();
@@ -531,10 +531,10 @@
   void operator ()(octave_idx_type k) { (*ind++ *= n) += k; }
 };
 
-idx_vector
-sub2ind (const dim_vector& dv, const Array<idx_vector>& idxa)
+octave::idx_vector
+sub2ind (const dim_vector& dv, const Array<octave::idx_vector>& idxa)
 {
-  idx_vector retval;
+  octave::idx_vector retval;
   octave_idx_type len = idxa.numel ();
 
   if (len == 0)
@@ -548,7 +548,7 @@
     {
       try
         {
-          idx_vector idx = idxa(i);
+          octave::idx_vector idx = idxa(i);
           octave_idx_type n = dvx(i);
 
           all_ranges = all_ranges && idx.is_range ();
@@ -561,13 +561,13 @@
           if (idx.extent (n) > n)
             octave::err_index_out_of_range (len, i+1, idx.extent (n), n, dv);
         }
-      catch (octave::index_exception& e)
+      catch (octave::index_exception& ie)
         {
-          e.set_pos_if_unset (len, i+1);
-          e.set_var ();
-          std::string msg = e.message ();
+          ie.set_pos_if_unset (len, i+1);
+          ie.set_var ();
+          std::string msg = ie.message ();
           (*current_liboctave_error_with_id_handler)
-            (e.err_id (), "%s", msg.c_str ());
+            (ie.err_id (), "%s", msg.c_str ());
         }
     }
   // idxa known to be valid.
@@ -581,7 +581,7 @@
       octave_idx_type idx = idxa(len-1)(0);
       for (octave_idx_type i = len - 2; i >= 0; i--)
         idx = dvx(i) * idx + idxa(i)(0);
-      retval = idx_vector (idx);
+      retval = octave::idx_vector (idx);
     }
   else if (all_ranges && clen != 0)
     {
@@ -595,7 +595,7 @@
           start = dvx(i) * start + xstart;
           step = dvx(i) * step + xstep;
         }
-      retval = idx_vector::make_range (start, step, clen);
+      retval = octave::idx_vector::make_range (start, step, clen);
     }
   else
     {
@@ -610,18 +610,18 @@
             idxa(i).copy_data (idx_vec);
         }
 
-      retval = idx_vector (idx);
+      retval = octave::idx_vector (idx);
     }
 
   return retval;
 }
 
-Array<idx_vector>
-ind2sub (const dim_vector& dv, const idx_vector& idx)
+Array<octave::idx_vector>
+ind2sub (const dim_vector& dv, const octave::idx_vector& idx)
 {
   octave_idx_type len = idx.length (0);
   octave_idx_type n = dv.ndims ();
-  Array<idx_vector> retval (dim_vector (n, 1));
+  Array<octave::idx_vector> retval (dim_vector (n, 1));
   octave_idx_type numel = dv.numel ();
 
   if (idx.extent (numel) > numel)
--- a/liboctave/array/Array-util.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-util.h	Sun May 16 09:44:35 2021 +0200
@@ -66,45 +66,47 @@
 compute_index (const Array<octave_idx_type>& ra_idx, const dim_vector& dims);
 
 extern OCTAVE_API Array<octave_idx_type>
-conv_to_int_array (const Array<idx_vector>& a);
+conv_to_int_array (const Array<octave::idx_vector>& a);
 
-extern OCTAVE_API Array<idx_vector> conv_to_array (const idx_vector *tmp,
-                                                   const octave_idx_type len);
+extern OCTAVE_API Array<octave::idx_vector>
+conv_to_array (const octave::idx_vector *tmp, const octave_idx_type len);
 
-extern OCTAVE_API dim_vector freeze (Array<idx_vector>& ra_idx,
-                                     const dim_vector& dimensions,
-                                     int resize_ok);
+extern OCTAVE_API dim_vector
+freeze (Array<octave::idx_vector>& ra_idx, const dim_vector& dimensions,
+        int resize_ok);
 
 extern OCTAVE_API bool vector_equivalent (const dim_vector& dv);
 
-extern OCTAVE_API bool all_ok (const Array<idx_vector>& ra_idx);
+extern OCTAVE_API bool all_ok (const Array<octave::idx_vector>& ra_idx);
 
-extern OCTAVE_API bool any_orig_empty (const Array<idx_vector>& ra_idx);
+extern OCTAVE_API bool
+any_orig_empty (const Array<octave::idx_vector>& ra_idx);
 
-extern OCTAVE_API bool all_colon_equiv (const Array<idx_vector>& ra_idx,
-                                        const dim_vector& frozen_lengths);
+extern OCTAVE_API bool
+all_colon_equiv (const Array<octave::idx_vector>& ra_idx,
+                 const dim_vector& frozen_lengths);
 
 extern OCTAVE_API bool all_ones (const Array<octave_idx_type>& arr);
 
 extern OCTAVE_API Array<octave_idx_type>
-get_elt_idx (const Array<idx_vector>& ra_idx,
+get_elt_idx (const Array<octave::idx_vector>& ra_idx,
              const Array<octave_idx_type>& result_idx);
 
 extern OCTAVE_API Array<octave_idx_type> get_ra_idx (octave_idx_type idx,
                                                      const dim_vector& dims);
 
-extern OCTAVE_API dim_vector zero_dims_inquire (const Array<idx_vector>& ia,
-                                                const dim_vector& rhdv);
+extern OCTAVE_API dim_vector
+zero_dims_inquire (const Array<octave::idx_vector>& ia, const dim_vector& rhdv);
 
-extern OCTAVE_API dim_vector zero_dims_inquire (const idx_vector& i,
-                                                const idx_vector& j,
-                                                const dim_vector& rhdv);
+extern OCTAVE_API dim_vector
+zero_dims_inquire (const octave::idx_vector& i, const octave::idx_vector& j,
+                   const dim_vector& rhdv);
 
-extern OCTAVE_API idx_vector sub2ind (const dim_vector& dv,
-                                      const Array<idx_vector>& idxa);
+extern OCTAVE_API octave::idx_vector
+sub2ind (const dim_vector& dv, const Array<octave::idx_vector>& idxa);
 
-extern OCTAVE_API Array<idx_vector> ind2sub (const dim_vector& dv,
-                                             const idx_vector& idx);
+extern OCTAVE_API Array<octave::idx_vector>
+ind2sub (const dim_vector& dv, const octave::idx_vector& idx);
 
 struct
 permute_vector
--- a/liboctave/array/Array-voidp.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array-voidp.cc	Sun May 16 09:44:35 2021 +0200
@@ -37,9 +37,9 @@
 // Prevent implicit instantiations on some systems (Windows, others?)
 // that can lead to duplicate definitions of static data members.
 
-extern template class OCTAVE_API Array<idx_vector>;
-extern template class OCTAVE_API Array<octave_idx_type>;
+extern template class Array<octave::idx_vector>;
+extern template class Array<octave_idx_type>;
 
-NO_INSTANTIATE_ARRAY_SORT (void *);
+NO_INSTANTIATE_ARRAY_SORT (void *, OCTAVE_API);
 
 INSTANTIATE_ARRAY (void *, OCTAVE_API);
--- a/liboctave/array/Array.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array.cc	Sun May 16 09:44:35 2021 +0200
@@ -510,12 +510,12 @@
   int top;
   octave_idx_type *dim;
   octave_idx_type *cdim;
-  idx_vector *idx;
+  octave::idx_vector *idx;
 
 public:
-  rec_index_helper (const dim_vector& dv, const Array<idx_vector>& ia)
+  rec_index_helper (const dim_vector& dv, const Array<octave::idx_vector>& ia)
     : n (ia.numel ()), top (0), dim (new octave_idx_type [2*n]),
-      cdim (dim + n), idx (new idx_vector [n])
+      cdim (dim + n), idx (new octave::idx_vector [n])
   {
     assert (n > 0 && (dv.ndims () == std::max (n, 2)));
 
@@ -695,7 +695,7 @@
 
 template <typename T>
 Array<T>
-Array<T>::index (const idx_vector& i) const
+Array<T>::index (const octave::idx_vector& i) const
 {
   // Colon:
   //
@@ -762,7 +762,7 @@
 
 template <typename T>
 Array<T>
-Array<T>::index (const idx_vector& i, const idx_vector& j) const
+Array<T>::index (const octave::idx_vector& i, const octave::idx_vector& j) const
 {
   // Get dimensions, allowing Fortran indexing in the 2nd dim.
   dim_vector dv = dimensions.redim (2);
@@ -786,7 +786,7 @@
       octave_idx_type il = i.length (r);
       octave_idx_type jl = j.length (c);
 
-      idx_vector ii (i);
+      octave::idx_vector ii (i);
 
       if (ii.maybe_reduce (r, j, c))
         {
@@ -820,7 +820,7 @@
 
 template <typename T>
 Array<T>
-Array<T>::index (const Array<idx_vector>& ia) const
+Array<T>::index (const Array<octave::idx_vector>& ia) const
 {
   int ial = ia.numel ();
   Array<T> retval;
@@ -1030,7 +1030,7 @@
 
 template <typename T>
 Array<T>
-Array<T>::index (const idx_vector& i, bool resize_ok, const T& rfv) const
+Array<T>::index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const
 {
   Array<T> tmp = *this;
   if (resize_ok)
@@ -1054,7 +1054,7 @@
 
 template <typename T>
 Array<T>
-Array<T>::index (const idx_vector& i, const idx_vector& j,
+Array<T>::index (const octave::idx_vector& i, const octave::idx_vector& j,
                  bool resize_ok, const T& rfv) const
 {
   Array<T> tmp = *this;
@@ -1082,7 +1082,7 @@
 
 template <typename T>
 Array<T>
-Array<T>::index (const Array<idx_vector>& ia,
+Array<T>::index (const Array<octave::idx_vector>& ia,
                  bool resize_ok, const T& rfv) const
 {
   Array<T> tmp = *this;
@@ -1113,7 +1113,7 @@
 
 template <typename T>
 void
-Array<T>::assign (const idx_vector& i, const Array<T>& rhs, const T& rfv)
+Array<T>::assign (const octave::idx_vector& i, const Array<T>& rhs, const T& rfv)
 {
   octave_idx_type n = numel ();
   octave_idx_type rhl = rhs.numel ();
@@ -1160,7 +1160,7 @@
 // Assignment to a 2-dimensional array
 template <typename T>
 void
-Array<T>::assign (const idx_vector& i, const idx_vector& j,
+Array<T>::assign (const octave::idx_vector& i, const octave::idx_vector& j,
                   const Array<T>& rhs, const T& rfv)
 {
   bool initial_dims_all_zero = dimensions.all_zero ();
@@ -1228,7 +1228,7 @@
           octave_idx_type n = numel ();
           octave_idx_type r = dv(0);
           octave_idx_type c = dv(1);
-          idx_vector ii (i);
+          octave::idx_vector ii (i);
 
           const T *src = rhs.data ();
           T *dest = fortran_vec ();
@@ -1264,7 +1264,7 @@
 // Assignment to a multi-dimensional array
 template <typename T>
 void
-Array<T>::assign (const Array<idx_vector>& ia,
+Array<T>::assign (const Array<octave::idx_vector>& ia,
                   const Array<T>& rhs, const T& rfv)
 {
   int ial = ia.numel ();
@@ -1365,14 +1365,19 @@
           // dimension mismatch, unless LHS and RHS both empty
           bool lhsempty, rhsempty;
           lhsempty = rhsempty = false;
+          dim_vector lhs_dv = dim_vector::alloc (ial);
           for (int i = 0; i < ial; i++)
             {
               octave_idx_type l = ia(i).length (rdv(i));
+              lhs_dv(i) = l;
               lhsempty = lhsempty || (l == 0);
               rhsempty = rhsempty || (rhdv(j++) == 0);
             }
           if (! lhsempty || ! rhsempty)
-            octave::err_nonconformant ("=", dv, rhdv);
+            {
+              lhs_dv.chop_trailing_singletons ();
+              octave::err_nonconformant ("=", lhs_dv, rhdv);
+            }
         }
     }
 }
@@ -1387,7 +1392,7 @@
 
 template <typename T>
 void
-Array<T>::delete_elements (const idx_vector& i)
+Array<T>::delete_elements (const octave::idx_vector& i)
 {
   octave_idx_type n = numel ();
   if (i.is_colon ())
@@ -1427,7 +1432,7 @@
 
 template <typename T>
 void
-Array<T>::delete_elements (int dim, const idx_vector& i)
+Array<T>::delete_elements (int dim, const octave::idx_vector& i)
 {
   if (dim < 0 || dim >= ndims ())
     (*current_liboctave_error_handler) ("invalid dimension in delete_elements");
@@ -1474,7 +1479,7 @@
       else
         {
           // Use index.
-          Array<idx_vector> ia (dim_vector (ndims (), 1), idx_vector::colon);
+          Array<octave::idx_vector> ia (dim_vector (ndims (), 1), octave::idx_vector::colon);
           ia (dim) = i.complement (n);
           *this = index (ia);
         }
@@ -1483,7 +1488,7 @@
 
 template <typename T>
 void
-Array<T>::delete_elements (const Array<idx_vector>& ia)
+Array<T>::delete_elements (const Array<octave::idx_vector>& ia)
 {
   int ial = ia.numel ();
 
@@ -1562,17 +1567,17 @@
 Array<T>&
 Array<T>::insert (const Array<T>& a, octave_idx_type r, octave_idx_type c)
 {
-  idx_vector i (r, r + a.rows ());
-  idx_vector j (c, c + a.columns ());
+  octave::idx_vector i (r, r + a.rows ());
+  octave::idx_vector j (c, c + a.columns ());
   if (ndims () == 2 && a.ndims () == 2)
     assign (i, j, a);
   else
     {
-      Array<idx_vector> idx (dim_vector (a.ndims (), 1));
+      Array<octave::idx_vector> idx (dim_vector (a.ndims (), 1));
       idx(0) = i;
       idx(1) = j;
       for (int k = 2; k < a.ndims (); k++)
-        idx(k) = idx_vector (0, a.dimensions(k));
+        idx(k) = octave::idx_vector (0, a.dimensions(k));
       assign (idx, a);
     }
 
@@ -1584,10 +1589,10 @@
 Array<T>::insert (const Array<T>& a, const Array<octave_idx_type>& ra_idx)
 {
   octave_idx_type n = ra_idx.numel ();
-  Array<idx_vector> idx (dim_vector (n, 1));
+  Array<octave::idx_vector> idx (dim_vector (n, 1));
   const dim_vector dva = a.dims ().redim (n);
   for (octave_idx_type k = 0; k < n; k++)
-    idx(k) = idx_vector (ra_idx(k), ra_idx(k) + dva(k));
+    idx(k) = octave::idx_vector (ra_idx(k), ra_idx(k) + dva(k));
 
   assign (idx, a);
 
@@ -2303,7 +2308,7 @@
 
 template <typename T>
 Array<T>
-Array<T>::nth_element (const idx_vector& n, int dim) const
+Array<T>::nth_element (const octave::idx_vector& n, int dim) const
 {
   if (dim < 0)
     (*current_liboctave_error_handler) ("nth_element: invalid dimension");
@@ -2330,11 +2335,11 @@
 
   switch (n.idx_class ())
     {
-    case idx_vector::class_scalar:
+    case octave::idx_vector::class_scalar:
       mode = ASCENDING;
       lo = n(0);
       break;
-    case idx_vector::class_range:
+    case octave::idx_vector::class_range:
       {
         octave_idx_type inc = n.increment ();
         if (inc == 1)
@@ -2349,7 +2354,7 @@
           }
       }
       break;
-    case idx_vector::class_vector:
+    case octave::idx_vector::class_vector:
       // This case resolves bug #51329, a fallback to allow the given index
       // to be a sequential vector instead of the typical scalar or range
       if (n(1) - n(0) == 1)
@@ -2466,60 +2471,60 @@
   return m;
 }
 
-#define NO_INSTANTIATE_ARRAY_SORT(T)                                    \
-  template <> Array<T>                                                  \
+#define NO_INSTANTIATE_ARRAY_SORT(T, API)                               \
+  template <> API Array<T>                                              \
   Array<T>::sort (int, sortmode) const                                  \
   {                                                                     \
     return *this;                                                       \
   }                                                                     \
-  template <> Array<T>                                                  \
+  template <> API Array<T>                                              \
   Array<T>::sort (Array<octave_idx_type> &sidx, int, sortmode) const    \
   {                                                                     \
     sidx = Array<octave_idx_type> ();                                   \
     return *this;                                                       \
   }                                                                     \
-  template <> sortmode                                                  \
-  Array<T>::issorted (sortmode) const                                  \
+  template <> API sortmode                                              \
+  Array<T>::issorted (sortmode) const                                   \
   {                                                                     \
     return UNSORTED;                                                    \
   }                                                                     \
-  Array<T>::compare_fcn_type                                            \
+  API Array<T>::compare_fcn_type                                        \
   safe_comparator (sortmode, const Array<T>&, bool)                     \
   {                                                                     \
     return nullptr;                                                     \
   }                                                                     \
-  template <> Array<octave_idx_type>                                    \
+  template <> API Array<octave_idx_type>                                \
   Array<T>::sort_rows_idx (sortmode) const                              \
   {                                                                     \
     return Array<octave_idx_type> ();                                   \
   }                                                                     \
-  template <> sortmode                                                  \
+  template <> API sortmode                                              \
   Array<T>::is_sorted_rows (sortmode) const                             \
   {                                                                     \
     return UNSORTED;                                                    \
   }                                                                     \
-  template <> octave_idx_type                                           \
+  template <> API octave_idx_type                                       \
   Array<T>::lookup (T const &, sortmode) const                          \
   {                                                                     \
     return 0;                                                           \
   }                                                                     \
-  template <> Array<octave_idx_type>                                    \
+  template <> API Array<octave_idx_type>                                \
   Array<T>::lookup (const Array<T>&, sortmode) const                    \
   {                                                                     \
     return Array<octave_idx_type> ();                                   \
   }                                                                     \
-  template <> octave_idx_type                                           \
+  template <> API octave_idx_type                                       \
   Array<T>::nnz (void) const                                            \
   {                                                                     \
     return 0;                                                           \
   }                                                                     \
-  template <> Array<octave_idx_type>                                    \
+  template <> API Array<octave_idx_type>                                \
   Array<T>::find (octave_idx_type, bool) const                          \
   {                                                                     \
     return Array<octave_idx_type> ();                                   \
   }                                                                     \
-  template <> Array<T>                                                  \
-  Array<T>::nth_element (const idx_vector&, int) const {                \
+  template <> API Array<T>                                              \
+  Array<T>::nth_element (const octave::idx_vector&, int) const {                \
     return Array<T> ();                                                 \
   }
 
@@ -2697,7 +2702,7 @@
     return retval;
 
   int nidx = std::max (dv.ndims (), static_cast<octave_idx_type> (dim + 1));
-  Array<idx_vector> idxa (dim_vector (nidx, 1), idx_vector::colon);
+  Array<octave::idx_vector> idxa (dim_vector (nidx, 1), octave::idx_vector::colon);
   octave_idx_type l = 0;
 
   for (octave_idx_type i = 0; i < n; i++)
@@ -2719,7 +2724,7 @@
       else
         u = l + 1;
 
-      idxa(dim) = idx_vector (l, u);
+      idxa(dim) = octave::idx_vector (l, u);
 
       retval.assign (idxa, array_list[i]);
 
@@ -2764,9 +2769,15 @@
   T::__xXxXx__ ();
 }
 
-#define INSTANTIATE_ARRAY(T, API)                       \
-  template <> void Array<T>::instantiation_guard () { } \
-  template class API Array<T>
+#if defined (__clang__)
+#  define INSTANTIATE_ARRAY(T, API)                            \
+     template <> API void Array<T>::instantiation_guard () { } \
+     template class API Array<T>
+#else
+#  define INSTANTIATE_ARRAY(T, API)                            \
+     template <> API void Array<T>::instantiation_guard () { } \
+     template class Array<T>
+#endif
 
 // FIXME: is this used?
 
--- a/liboctave/array/Array.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Array.h	Sun May 16 09:44:35 2021 +0200
@@ -122,6 +122,9 @@
 //!   - string_vector: Array<std::string> with 1 column
 //!   - Cell: Array<octave_value>, equivalent to an Octave cell.
 
+// forward declare template with visibility attribute
+template <typename T> class OCTARRAY_API Array;
+
 template <typename T>
 class
 Array
@@ -178,7 +181,7 @@
 
     // No assignment!
 
-    ArrayRep& operator = (const ArrayRep& a);
+    OCTARRAY_API ArrayRep& operator = (const ArrayRep& a);
   };
 
   //--------------------------------------------------------------------
@@ -239,7 +242,7 @@
 
 private:
 
-  static typename Array<T>::ArrayRep *nil_rep (void);
+  static OCTARRAY_API typename Array<T>::ArrayRep *nil_rep (void);
 
 protected:
 
@@ -279,7 +282,7 @@
   }
 
   //! Reshape constructor.
-  Array (const Array<T>& a, const dim_vector& dv);
+  OCTARRAY_API Array (const Array<T>& a, const dim_vector& dv);
 
   //! Constructor from standard library sequence containers.
   template<template <typename...> class Container>
@@ -365,10 +368,10 @@
     return *this;
   }
 
-  void fill (const T& val);
+  OCTARRAY_API void fill (const T& val);
 
-  void clear (void);
-  void clear (const dim_vector& dv);
+  OCTARRAY_API void clear (void);
+  OCTARRAY_API void clear (const dim_vector& dv);
 
   void clear (octave_idx_type r, octave_idx_type c)
   { clear (dim_vector (r, c)); }
@@ -453,12 +456,12 @@
   const dim_vector& dims (void) const { return dimensions; }
 
   //! Chop off leading singleton dimensions
-  Array<T> squeeze (void) const;
+  OCTARRAY_API Array<T> squeeze (void) const;
 
-  octave_idx_type compute_index (octave_idx_type i, octave_idx_type j) const;
-  octave_idx_type compute_index (octave_idx_type i, octave_idx_type j,
+  OCTARRAY_API octave_idx_type compute_index (octave_idx_type i, octave_idx_type j) const;
+  OCTARRAY_API octave_idx_type compute_index (octave_idx_type i, octave_idx_type j,
                                  octave_idx_type k) const;
-  octave_idx_type compute_index (const Array<octave_idx_type>& ra_idx) const;
+  OCTARRAY_API octave_idx_type compute_index (const Array<octave_idx_type>& ra_idx) const;
 
   octave_idx_type compute_index_unchecked (const Array<octave_idx_type>& ra_idx)
   const
@@ -488,13 +491,13 @@
   // FIXME: would be nice to fix this so that we don't unnecessarily force
   //        a copy, but that is not so easy, and I see no clean way to do it.
 
-  T& checkelem (octave_idx_type n);
+  OCTARRAY_API T& checkelem (octave_idx_type n);
 
-  T& checkelem (octave_idx_type i, octave_idx_type j);
+  OCTARRAY_API T& checkelem (octave_idx_type i, octave_idx_type j);
 
-  T& checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k);
+  OCTARRAY_API T& checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k);
 
-  T& checkelem (const Array<octave_idx_type>& ra_idx);
+  OCTARRAY_API T& checkelem (const Array<octave_idx_type>& ra_idx);
 
   T& elem (octave_idx_type n)
   {
@@ -517,14 +520,14 @@
   T& operator () (const Array<octave_idx_type>& ra_idx)
   { return elem (ra_idx); }
 
-  crefT checkelem (octave_idx_type n) const;
+  OCTARRAY_API crefT checkelem (octave_idx_type n) const;
 
-  crefT checkelem (octave_idx_type i, octave_idx_type j) const;
+  OCTARRAY_API crefT checkelem (octave_idx_type i, octave_idx_type j) const;
 
-  crefT checkelem (octave_idx_type i, octave_idx_type j,
+  OCTARRAY_API crefT checkelem (octave_idx_type i, octave_idx_type j,
                    octave_idx_type k) const;
 
-  crefT checkelem (const Array<octave_idx_type>& ra_idx) const;
+  OCTARRAY_API crefT checkelem (const Array<octave_idx_type>& ra_idx) const;
 
   crefT elem (octave_idx_type n) const { return xelem (n); }
 
@@ -549,13 +552,13 @@
   // Fast extractors.  All of these produce shallow copies.
 
   //! Extract column: A(:,k+1).
-  Array<T> column (octave_idx_type k) const;
+  OCTARRAY_API Array<T> column (octave_idx_type k) const;
   //! Extract page: A(:,:,k+1).
-  Array<T> page (octave_idx_type k) const;
+  OCTARRAY_API Array<T> page (octave_idx_type k) const;
 
   //! Extract a slice from this array as a column vector: A(:)(lo+1:up).
   //! Must be 0 <= lo && up <= numel.  May be up < lo.
-  Array<T> linear_slice (octave_idx_type lo, octave_idx_type up) const;
+  OCTARRAY_API Array<T> linear_slice (octave_idx_type lo, octave_idx_type up) const;
 
   Array<T> reshape (octave_idx_type nr, octave_idx_type nc) const
   { return Array<T> (*this, dim_vector (nr, nc)); }
@@ -563,7 +566,7 @@
   Array<T> reshape (const dim_vector& new_dims) const
   { return Array<T> (*this, new_dims); }
 
-  Array<T> permute (const Array<octave_idx_type>& vec, bool inv = false) const;
+  OCTARRAY_API Array<T> permute (const Array<octave_idx_type>& vec, bool inv = false) const;
   Array<T> ipermute (const Array<octave_idx_type>& vec) const
   { return permute (vec, true); }
 
@@ -575,14 +578,14 @@
 
   bool is_nd_vector (void) const { return dimensions.is_nd_vector (); }
 
-  Array<T> transpose (void) const;
-  Array<T> hermitian (T (*fcn) (const T&) = nullptr) const;
+  OCTARRAY_API Array<T> transpose (void) const;
+  OCTARRAY_API Array<T> hermitian (T (*fcn) (const T&) = nullptr) const;
 
   const T * data (void) const { return slice_data; }
 
   const T * fortran_vec (void) const { return data (); }
 
-  T * fortran_vec (void);
+  OCTARRAY_API T * fortran_vec (void);
 
   bool is_shared (void) { return rep->count > 1; }
 
@@ -590,27 +593,27 @@
 
   //@{
   //! Indexing without resizing.
-  Array<T> index (const idx_vector& i) const;
+  OCTARRAY_API Array<T> index (const octave::idx_vector& i) const;
 
-  Array<T> index (const idx_vector& i, const idx_vector& j) const;
+  OCTARRAY_API Array<T> index (const octave::idx_vector& i, const octave::idx_vector& j) const;
 
-  Array<T> index (const Array<idx_vector>& ia) const;
+  OCTARRAY_API Array<T> index (const Array<octave::idx_vector>& ia) const;
   //@}
 
-  virtual T resize_fill_value (void) const;
+  virtual OCTARRAY_API T resize_fill_value (void) const;
 
   //@{
   //! Resizing (with fill).
-  void resize2 (octave_idx_type nr, octave_idx_type nc, const T& rfv);
+  OCTARRAY_API void resize2 (octave_idx_type nr, octave_idx_type nc, const T& rfv);
   void resize2 (octave_idx_type nr, octave_idx_type nc)
   {
     resize2 (nr, nc, resize_fill_value ());
   }
 
-  void resize1 (octave_idx_type n, const T& rfv);
+  OCTARRAY_API void resize1 (octave_idx_type n, const T& rfv);
   void resize1 (octave_idx_type n) { resize1 (n, resize_fill_value ()); }
 
-  void resize (const dim_vector& dv, const T& rfv);
+  OCTARRAY_API void resize (const dim_vector& dv, const T& rfv);
   void resize (const dim_vector& dv) { resize (dv, resize_fill_value ()); }
   //@}
 
@@ -620,23 +623,23 @@
   // FIXME: this is really a corner case, that should better be
   // handled directly in liboctinterp.
 
-  Array<T> index (const idx_vector& i, bool resize_ok, const T& rfv) const;
-  Array<T> index (const idx_vector& i, bool resize_ok) const
+  OCTARRAY_API Array<T> index (const octave::idx_vector& i, bool resize_ok, const T& rfv) const;
+  Array<T> index (const octave::idx_vector& i, bool resize_ok) const
   {
     return index (i, resize_ok, resize_fill_value ());
   }
 
-  Array<T> index (const idx_vector& i, const idx_vector& j, bool resize_ok,
+  OCTARRAY_API Array<T> index (const octave::idx_vector& i, const octave::idx_vector& j, bool resize_ok,
                   const T& rfv) const;
-  Array<T> index (const idx_vector& i, const idx_vector& j,
+  Array<T> index (const octave::idx_vector& i, const octave::idx_vector& j,
                   bool resize_ok) const
   {
     return index (i, j, resize_ok, resize_fill_value ());
   }
 
-  Array<T> index (const Array<idx_vector>& ia, bool resize_ok,
+  OCTARRAY_API Array<T> index (const Array<octave::idx_vector>& ia, bool resize_ok,
                   const T& rfv) const;
-  Array<T> index (const Array<idx_vector>& ia, bool resize_ok) const
+  Array<T> index (const Array<octave::idx_vector>& ia, bool resize_ok) const
   {
     return index (ia, resize_ok, resize_fill_value ());
   }
@@ -644,21 +647,21 @@
 
   //@{
   //! Indexed assignment (always with resize & fill).
-  void assign (const idx_vector& i, const Array<T>& rhs, const T& rfv);
-  void assign (const idx_vector& i, const Array<T>& rhs)
+  OCTARRAY_API void assign (const octave::idx_vector& i, const Array<T>& rhs, const T& rfv);
+  void assign (const octave::idx_vector& i, const Array<T>& rhs)
   {
     assign (i, rhs, resize_fill_value ());
   }
 
-  void assign (const idx_vector& i, const idx_vector& j, const Array<T>& rhs,
+  OCTARRAY_API void assign (const octave::idx_vector& i, const octave::idx_vector& j, const Array<T>& rhs,
                const T& rfv);
-  void assign (const idx_vector& i, const idx_vector& j, const Array<T>& rhs)
+  void assign (const octave::idx_vector& i, const octave::idx_vector& j, const Array<T>& rhs)
   {
     assign (i, j, rhs, resize_fill_value ());
   }
 
-  void assign (const Array<idx_vector>& ia, const Array<T>& rhs, const T& rfv);
-  void assign (const Array<idx_vector>& ia, const Array<T>& rhs)
+  OCTARRAY_API void assign (const Array<octave::idx_vector>& ia, const Array<T>& rhs, const T& rfv);
+  void assign (const Array<octave::idx_vector>& ia, const Array<T>& rhs)
   {
     assign (ia, rhs, resize_fill_value ());
   }
@@ -668,23 +671,23 @@
   //! Deleting elements.
 
   //! A(I) = [] (with a single subscript)
-  void delete_elements (const idx_vector& i);
+  OCTARRAY_API void delete_elements (const octave::idx_vector& i);
 
   //! A(:,...,I,...,:) = [] (>= 2 subscripts, one of them is non-colon)
-  void delete_elements (int dim, const idx_vector& i);
+  OCTARRAY_API void delete_elements (int dim, const octave::idx_vector& i);
 
   //! Dispatcher to the above two.
-  void delete_elements (const Array<idx_vector>& ia);
+  OCTARRAY_API void delete_elements (const Array<octave::idx_vector>& ia);
   //@}
 
   //! Insert an array into another at a specified position.  If
   //! size (a) is [d1 d2 ... dN] and idx is [i1 i2 ... iN], this
   //! method is equivalent to x(i1:i1+d1-1, i2:i2+d2-1, ... ,
   //! iN:iN+dN-1) = a.
-  Array<T>& insert (const Array<T>& a, const Array<octave_idx_type>& idx);
+  OCTARRAY_API Array<T>& insert (const Array<T>& a, const Array<octave_idx_type>& idx);
 
   //! This is just a special case for idx = [r c 0 ...]
-  Array<T>& insert (const Array<T>& a, octave_idx_type r, octave_idx_type c);
+  OCTARRAY_API Array<T>& insert (const Array<T>& a, octave_idx_type r, octave_idx_type c);
 
   void maybe_economize (void)
   {
@@ -697,59 +700,59 @@
       }
   }
 
-  void print_info (std::ostream& os, const std::string& prefix) const;
+  OCTARRAY_API void print_info (std::ostream& os, const std::string& prefix) const;
 
   //! Give a pointer to the data in mex format.  Unsafe.  This function
   //! exists to support the MEX interface.  You should not use it
   //! anywhere else.
   void * mex_get_data (void) const { return const_cast<T *> (data ()); }
 
-  Array<T> sort (int dim = 0, sortmode mode = ASCENDING) const;
-  Array<T> sort (Array<octave_idx_type> &sidx, int dim = 0,
+  OCTARRAY_API Array<T> sort (int dim = 0, sortmode mode = ASCENDING) const;
+  OCTARRAY_API Array<T> sort (Array<octave_idx_type> &sidx, int dim = 0,
                  sortmode mode = ASCENDING) const;
 
   //! Ordering is auto-detected or can be specified.
-  sortmode issorted (sortmode mode = UNSORTED) const;
+  OCTARRAY_API sortmode issorted (sortmode mode = UNSORTED) const;
 
   //! Sort by rows returns only indices.
-  Array<octave_idx_type> sort_rows_idx (sortmode mode = ASCENDING) const;
+  OCTARRAY_API Array<octave_idx_type> sort_rows_idx (sortmode mode = ASCENDING) const;
 
   //! Ordering is auto-detected or can be specified.
-  sortmode is_sorted_rows (sortmode mode = UNSORTED) const;
+  OCTARRAY_API sortmode is_sorted_rows (sortmode mode = UNSORTED) const;
 
   //! Do a binary lookup in a sorted array.  Must not contain NaNs.
   //! Mode can be specified or is auto-detected by comparing 1st and last element.
-  octave_idx_type lookup (const T& value, sortmode mode = UNSORTED) const;
+  OCTARRAY_API octave_idx_type lookup (const T& value, sortmode mode = UNSORTED) const;
 
   //! Ditto, but for an array of values, specializing on the case when values
   //! are sorted.  NaNs get the value N.
-  Array<octave_idx_type> lookup (const Array<T>& values,
+  OCTARRAY_API Array<octave_idx_type> lookup (const Array<T>& values,
                                  sortmode mode = UNSORTED) const;
 
   //! Count nonzero elements.
-  octave_idx_type nnz (void) const;
+  OCTARRAY_API octave_idx_type nnz (void) const;
 
   //! Find indices of (at most n) nonzero elements.  If n is specified,
   //! backward specifies search from backward.
-  Array<octave_idx_type> find (octave_idx_type n = -1,
+  OCTARRAY_API Array<octave_idx_type> find (octave_idx_type n = -1,
                                bool backward = false) const;
 
   //! Returns the n-th element in increasing order, using the same
   //! ordering as used for sort.  n can either be a scalar index or a
   //! contiguous range.
-  Array<T> nth_element (const idx_vector& n, int dim = 0) const;
+  OCTARRAY_API Array<T> nth_element (const octave::idx_vector& n, int dim = 0) const;
 
   //! Get the kth super or subdiagonal.  The zeroth diagonal is the
   //! ordinary diagonal.
-  Array<T> diag (octave_idx_type k = 0) const;
+  OCTARRAY_API Array<T> diag (octave_idx_type k = 0) const;
 
-  Array<T> diag (octave_idx_type m, octave_idx_type n) const;
+  OCTARRAY_API Array<T> diag (octave_idx_type m, octave_idx_type n) const;
 
   //! Concatenation along a specified (0-based) dimension, equivalent
   //! to cat().  dim = -1 corresponds to dim = 0 and dim = -2
   //! corresponds to dim = 1, but apply the looser matching rules of
   //! vertcat/horzcat.
-  static Array<T>
+  static OCTARRAY_API Array<T>
   cat (int dim, octave_idx_type n, const Array<T> *array_list);
 
   //! Apply function fcn to each element of the Array<T>.  This function
@@ -835,7 +838,7 @@
   //! Returns true if this->dims () == dv, and if so, replaces this->dimensions
   //! by a shallow copy of dv.  This is useful for maintaining several arrays
   //! with supposedly equal dimensions (e.g. structs in the interpreter).
-  bool optimize_dimensions (const dim_vector& dv);
+  OCTARRAY_API bool optimize_dimensions (const dim_vector& dv);
 
   //@{
   //! WARNING: Only call these functions from jit
@@ -850,7 +853,7 @@
   //@}
 
 private:
-  static void instantiation_guard ();
+  OCTARRAY_API static void instantiation_guard ();
 };
 
 // We use a variadic template for template template parameter so that
@@ -879,7 +882,7 @@
 }
 
 template <typename T>
-std::ostream&
+OCTARRAY_API std::ostream&
 operator << (std::ostream& os, const Array<T>& a);
 
 #endif
--- a/liboctave/array/CColVector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CColVector.h	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
   ComplexColumnVector (const Array<Complex>& a)
     : MArray<Complex> (a.as_column ()) { }
 
-  explicit ComplexColumnVector (const ColumnVector& a);
+  explicit OCTAVE_API ComplexColumnVector (const ColumnVector& a);
 
   ComplexColumnVector& operator = (const ComplexColumnVector& a)
   {
@@ -67,39 +67,43 @@
     return *this;
   }
 
-  bool operator == (const ComplexColumnVector& a) const;
-  bool operator != (const ComplexColumnVector& a) const;
+  OCTAVE_API bool operator == (const ComplexColumnVector& a) const;
+  OCTAVE_API bool operator != (const ComplexColumnVector& a) const;
 
   // destructive insert/delete/reorder operations
 
-  ComplexColumnVector& insert (const ColumnVector& a, octave_idx_type r);
-  ComplexColumnVector& insert (const ComplexColumnVector& a, octave_idx_type r);
+  OCTAVE_API ComplexColumnVector&
+  insert (const ColumnVector& a, octave_idx_type r);
+  OCTAVE_API ComplexColumnVector&
+  insert (const ComplexColumnVector& a, octave_idx_type r);
 
-  ComplexColumnVector& fill (double val);
-  ComplexColumnVector& fill (const Complex& val);
-  ComplexColumnVector& fill (double val,
-                             octave_idx_type r1, octave_idx_type r2);
-  ComplexColumnVector& fill (const Complex& val,
-                             octave_idx_type r1, octave_idx_type r2);
+  OCTAVE_API ComplexColumnVector& fill (double val);
+  OCTAVE_API ComplexColumnVector& fill (const Complex& val);
+  OCTAVE_API ComplexColumnVector&
+  fill (double val, octave_idx_type r1, octave_idx_type r2);
+  OCTAVE_API ComplexColumnVector&
+  fill (const Complex& val, octave_idx_type r1, octave_idx_type r2);
 
-  ComplexColumnVector stack (const ColumnVector& a) const;
-  ComplexColumnVector stack (const ComplexColumnVector& a) const;
+  OCTAVE_API ComplexColumnVector stack (const ColumnVector& a) const;
+  OCTAVE_API ComplexColumnVector stack (const ComplexColumnVector& a) const;
 
-  ComplexRowVector hermitian (void) const;
-  ComplexRowVector transpose (void) const;
+  OCTAVE_API ComplexRowVector hermitian (void) const;
+  OCTAVE_API ComplexRowVector transpose (void) const;
 
   friend OCTAVE_API ComplexColumnVector conj (const ComplexColumnVector& a);
 
   // resize is the destructive equivalent for this one
 
-  ComplexColumnVector extract (octave_idx_type r1, octave_idx_type r2) const;
+  OCTAVE_API ComplexColumnVector
+  extract (octave_idx_type r1, octave_idx_type r2) const;
 
-  ComplexColumnVector extract_n (octave_idx_type r1, octave_idx_type n) const;
+  OCTAVE_API ComplexColumnVector
+  extract_n (octave_idx_type r1, octave_idx_type n) const;
 
   // column vector by column vector -> column vector operations
 
-  ComplexColumnVector& operator += (const ColumnVector& a);
-  ComplexColumnVector& operator -= (const ColumnVector& a);
+  OCTAVE_API ComplexColumnVector& operator += (const ColumnVector& a);
+  OCTAVE_API ComplexColumnVector& operator -= (const ColumnVector& a);
 
   // matrix by column vector -> column vector operations
 
@@ -127,10 +131,10 @@
 
   // other operations
 
-  Complex min (void) const;
-  Complex max (void) const;
+  OCTAVE_API Complex min (void) const;
+  OCTAVE_API Complex max (void) const;
 
-  ColumnVector abs (void) const;
+  OCTAVE_API ColumnVector abs (void) const;
 
   // i/o
 
--- a/liboctave/array/CDiagMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CDiagMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -72,7 +72,7 @@
                      octave_idx_type c)
     : MDiagArray2<Complex> (a, r, c) { }
 
-  explicit ComplexDiagMatrix (const DiagMatrix& a);
+  explicit OCTAVE_API ComplexDiagMatrix (const DiagMatrix& a);
 
   ComplexDiagMatrix (const MDiagArray2<Complex>& a)
     : MDiagArray2<Complex> (a) { }
@@ -81,23 +81,26 @@
   ComplexDiagMatrix (const DiagArray2<U>& a)
     : MDiagArray2<Complex> (a) { }
 
-  bool operator == (const ComplexDiagMatrix& a) const;
-  bool operator != (const ComplexDiagMatrix& a) const;
+  OCTAVE_API bool operator == (const ComplexDiagMatrix& a) const;
+  OCTAVE_API bool operator != (const ComplexDiagMatrix& a) const;
 
-  ComplexDiagMatrix& fill (double val);
-  ComplexDiagMatrix& fill (const Complex& val);
-  ComplexDiagMatrix& fill (double val,
-                           octave_idx_type beg, octave_idx_type end);
-  ComplexDiagMatrix& fill (const Complex& val,
-                           octave_idx_type beg, octave_idx_type end);
-  ComplexDiagMatrix& fill (const ColumnVector& a);
-  ComplexDiagMatrix& fill (const ComplexColumnVector& a);
-  ComplexDiagMatrix& fill (const RowVector& a);
-  ComplexDiagMatrix& fill (const ComplexRowVector& a);
-  ComplexDiagMatrix& fill (const ColumnVector& a, octave_idx_type beg);
-  ComplexDiagMatrix& fill (const ComplexColumnVector& a, octave_idx_type beg);
-  ComplexDiagMatrix& fill (const RowVector& a, octave_idx_type beg);
-  ComplexDiagMatrix& fill (const ComplexRowVector& a, octave_idx_type beg);
+  OCTAVE_API ComplexDiagMatrix& fill (double val);
+  OCTAVE_API ComplexDiagMatrix& fill (const Complex& val);
+  OCTAVE_API ComplexDiagMatrix&
+  fill (double val, octave_idx_type beg, octave_idx_type end);
+  OCTAVE_API ComplexDiagMatrix&
+  fill (const Complex& val, octave_idx_type beg, octave_idx_type end);
+  OCTAVE_API ComplexDiagMatrix& fill (const ColumnVector& a);
+  OCTAVE_API ComplexDiagMatrix& fill (const ComplexColumnVector& a);
+  OCTAVE_API ComplexDiagMatrix& fill (const RowVector& a);
+  OCTAVE_API ComplexDiagMatrix& fill (const ComplexRowVector& a);
+  OCTAVE_API ComplexDiagMatrix&
+  fill (const ColumnVector& a, octave_idx_type beg);
+  OCTAVE_API ComplexDiagMatrix&
+  fill (const ComplexColumnVector& a, octave_idx_type beg);
+  OCTAVE_API ComplexDiagMatrix& fill (const RowVector& a, octave_idx_type beg);
+  OCTAVE_API ComplexDiagMatrix&
+  fill (const ComplexRowVector& a, octave_idx_type beg);
 
   ComplexDiagMatrix hermitian (void) const
   { return MDiagArray2<Complex>::hermitian (std::conj); }
@@ -109,40 +112,41 @@
 
   // resize is the destructive analog for this one
 
-  ComplexMatrix extract (octave_idx_type r1, octave_idx_type c1,
-                         octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API ComplexMatrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
   // extract row or column i
 
-  ComplexRowVector row (octave_idx_type i) const;
-  ComplexRowVector row (char *s) const;
+  OCTAVE_API ComplexRowVector row (octave_idx_type i) const;
+  OCTAVE_API ComplexRowVector row (char *s) const;
 
-  ComplexColumnVector column (octave_idx_type i) const;
-  ComplexColumnVector column (char *s) const;
+  OCTAVE_API ComplexColumnVector column (octave_idx_type i) const;
+  OCTAVE_API ComplexColumnVector column (char *s) const;
 
-  ComplexDiagMatrix inverse (octave_idx_type& info) const;
-  ComplexDiagMatrix inverse (void) const;
-  ComplexDiagMatrix pseudo_inverse (double tol = 0.0) const;
+  OCTAVE_API ComplexDiagMatrix inverse (octave_idx_type& info) const;
+  OCTAVE_API ComplexDiagMatrix inverse (void) const;
+  OCTAVE_API ComplexDiagMatrix pseudo_inverse (double tol = 0.0) const;
 
-  bool all_elements_are_real (void) const;
+  OCTAVE_API bool all_elements_are_real (void) const;
 
   // diagonal matrix by diagonal matrix -> diagonal matrix operations
 
-  ComplexDiagMatrix& operator += (const DiagMatrix& a);
-  ComplexDiagMatrix& operator -= (const DiagMatrix& a);
+  OCTAVE_API ComplexDiagMatrix& operator += (const DiagMatrix& a);
+  OCTAVE_API ComplexDiagMatrix& operator -= (const DiagMatrix& a);
 
   // other operations
 
   ComplexColumnVector extract_diag (octave_idx_type k = 0) const
   { return MDiagArray2<Complex>::extract_diag (k); }
 
-  ComplexDET determinant (void) const;
-  double rcond (void) const;
+  OCTAVE_API ComplexDET determinant (void) const;
+  OCTAVE_API double rcond (void) const;
 
   // i/o
 
-  friend std::ostream& operator << (std::ostream& os,
-                                    const ComplexDiagMatrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const ComplexDiagMatrix& a);
 
 };
 
--- a/liboctave/array/CMatrix.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CMatrix.cc	Sun May 16 09:44:35 2021 +0200
@@ -686,14 +686,14 @@
   if (r1 > r2) { std::swap (r1, r2); }
   if (c1 > c2) { std::swap (c1, c2); }
 
-  return index (idx_vector (r1, r2+1), idx_vector (c1, c2+1));
+  return index (octave::idx_vector (r1, r2+1), octave::idx_vector (c1, c2+1));
 }
 
 ComplexMatrix
 ComplexMatrix::extract_n (octave_idx_type r1, octave_idx_type c1,
                           octave_idx_type nr, octave_idx_type nc) const
 {
-  return index (idx_vector (r1, r1 + nr), idx_vector (c1, c1 + nc));
+  return index (octave::idx_vector (r1, r1 + nr), octave::idx_vector (c1, c1 + nc));
 }
 
 // extract row or column i.
@@ -701,13 +701,13 @@
 ComplexRowVector
 ComplexMatrix::row (octave_idx_type i) const
 {
-  return index (idx_vector (i), idx_vector::colon);
+  return index (octave::idx_vector (i), octave::idx_vector::colon);
 }
 
 ComplexColumnVector
 ComplexMatrix::column (octave_idx_type i) const
 {
-  return index (idx_vector::colon, idx_vector (i));
+  return index (octave::idx_vector::colon, octave::idx_vector (i));
 }
 
 // Local function to calculate the 1-norm.
@@ -3168,7 +3168,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_complex (os, a.elem (i, j));
+          octave::write_value<Complex> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -3187,7 +3187,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<Complex> (is);
+            tmp = octave::read_value<Complex> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/CMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -85,86 +85,87 @@
   template <typename U>
   ComplexMatrix (const Array<U>& a) : ComplexNDArray (a.as_matrix ()) { }
 
-  ComplexMatrix (const Matrix& re, const Matrix& im);
+  OCTAVE_API ComplexMatrix (const Matrix& re, const Matrix& im);
 
-  explicit ComplexMatrix (const Matrix& a);
+  explicit OCTAVE_API ComplexMatrix (const Matrix& a);
 
-  explicit ComplexMatrix (const RowVector& rv);
+  explicit OCTAVE_API ComplexMatrix (const RowVector& rv);
 
-  explicit ComplexMatrix (const ColumnVector& cv);
+  explicit OCTAVE_API ComplexMatrix (const ColumnVector& cv);
 
-  explicit ComplexMatrix (const DiagMatrix& a);
+  explicit OCTAVE_API ComplexMatrix (const DiagMatrix& a);
 
-  explicit ComplexMatrix (const MDiagArray2<double>& a);
+  explicit OCTAVE_API ComplexMatrix (const MDiagArray2<double>& a);
 
-  explicit ComplexMatrix (const DiagArray2<double>& a);
+  explicit OCTAVE_API ComplexMatrix (const DiagArray2<double>& a);
 
-  explicit ComplexMatrix (const ComplexRowVector& rv);
+  explicit OCTAVE_API ComplexMatrix (const ComplexRowVector& rv);
 
-  explicit ComplexMatrix (const ComplexColumnVector& cv);
+  explicit OCTAVE_API ComplexMatrix (const ComplexColumnVector& cv);
 
-  explicit ComplexMatrix (const ComplexDiagMatrix& a);
+  explicit OCTAVE_API ComplexMatrix (const ComplexDiagMatrix& a);
 
-  explicit ComplexMatrix (const MDiagArray2<Complex>& a);
+  explicit OCTAVE_API ComplexMatrix (const MDiagArray2<Complex>& a);
 
-  explicit ComplexMatrix (const DiagArray2<Complex>& a);
+  explicit OCTAVE_API ComplexMatrix (const DiagArray2<Complex>& a);
 
-  explicit ComplexMatrix (const boolMatrix& a);
+  explicit OCTAVE_API ComplexMatrix (const boolMatrix& a);
 
-  explicit ComplexMatrix (const charMatrix& a);
+  explicit OCTAVE_API ComplexMatrix (const charMatrix& a);
 
-  bool operator == (const ComplexMatrix& a) const;
-  bool operator != (const ComplexMatrix& a) const;
+  OCTAVE_API bool operator == (const ComplexMatrix& a) const;
+  OCTAVE_API bool operator != (const ComplexMatrix& a) const;
 
-  bool ishermitian (void) const;
+  OCTAVE_API bool ishermitian (void) const;
 
   // destructive insert/delete/reorder operations
 
-  ComplexMatrix& insert (const Matrix& a, octave_idx_type r, octave_idx_type c);
-  ComplexMatrix& insert (const RowVector& a,
-                         octave_idx_type r, octave_idx_type c);
-  ComplexMatrix& insert (const ColumnVector& a,
-                         octave_idx_type r, octave_idx_type c);
-  ComplexMatrix& insert (const DiagMatrix& a,
-                         octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexMatrix&
+  insert (const Matrix& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexMatrix&
+  insert (const RowVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexMatrix&
+  insert (const ColumnVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexMatrix&
+  insert (const DiagMatrix& a, octave_idx_type r, octave_idx_type c);
 
-  ComplexMatrix& insert (const ComplexMatrix& a,
-                         octave_idx_type r, octave_idx_type c);
-  ComplexMatrix& insert (const ComplexRowVector& a,
-                         octave_idx_type r, octave_idx_type c);
-  ComplexMatrix& insert (const ComplexColumnVector& a,
-                         octave_idx_type r, octave_idx_type c);
-  ComplexMatrix& insert (const ComplexDiagMatrix& a,
-                         octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexMatrix&
+  insert (const ComplexMatrix& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexMatrix&
+  insert (const ComplexRowVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexMatrix&
+  insert (const ComplexColumnVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexMatrix&
+  insert (const ComplexDiagMatrix& a, octave_idx_type r, octave_idx_type c);
 
-  ComplexMatrix& fill (double val);
-  ComplexMatrix& fill (const Complex& val);
-  ComplexMatrix& fill (double val,
-                       octave_idx_type r1, octave_idx_type c1,
-                       octave_idx_type r2, octave_idx_type c2);
-  ComplexMatrix& fill (const Complex& val,
-                       octave_idx_type r1, octave_idx_type c1,
-                       octave_idx_type r2, octave_idx_type c2);
+  OCTAVE_API ComplexMatrix& fill (double val);
+  OCTAVE_API ComplexMatrix& fill (const Complex& val);
+  OCTAVE_API ComplexMatrix&
+  fill (double val, octave_idx_type r1, octave_idx_type c1,
+        octave_idx_type r2, octave_idx_type c2);
+  OCTAVE_API ComplexMatrix&
+  fill (const Complex& val, octave_idx_type r1, octave_idx_type c1,
+        octave_idx_type r2, octave_idx_type c2);
 
-  ComplexMatrix append (const Matrix& a) const;
-  ComplexMatrix append (const RowVector& a) const;
-  ComplexMatrix append (const ColumnVector& a) const;
-  ComplexMatrix append (const DiagMatrix& a) const;
+  OCTAVE_API ComplexMatrix append (const Matrix& a) const;
+  OCTAVE_API ComplexMatrix append (const RowVector& a) const;
+  OCTAVE_API ComplexMatrix append (const ColumnVector& a) const;
+  OCTAVE_API ComplexMatrix append (const DiagMatrix& a) const;
 
-  ComplexMatrix append (const ComplexMatrix& a) const;
-  ComplexMatrix append (const ComplexRowVector& a) const;
-  ComplexMatrix append (const ComplexColumnVector& a) const;
-  ComplexMatrix append (const ComplexDiagMatrix& a) const;
+  OCTAVE_API ComplexMatrix append (const ComplexMatrix& a) const;
+  OCTAVE_API ComplexMatrix append (const ComplexRowVector& a) const;
+  OCTAVE_API ComplexMatrix append (const ComplexColumnVector& a) const;
+  OCTAVE_API ComplexMatrix append (const ComplexDiagMatrix& a) const;
 
-  ComplexMatrix stack (const Matrix& a) const;
-  ComplexMatrix stack (const RowVector& a) const;
-  ComplexMatrix stack (const ColumnVector& a) const;
-  ComplexMatrix stack (const DiagMatrix& a) const;
+  OCTAVE_API ComplexMatrix stack (const Matrix& a) const;
+  OCTAVE_API ComplexMatrix stack (const RowVector& a) const;
+  OCTAVE_API ComplexMatrix stack (const ColumnVector& a) const;
+  OCTAVE_API ComplexMatrix stack (const DiagMatrix& a) const;
 
-  ComplexMatrix stack (const ComplexMatrix& a) const;
-  ComplexMatrix stack (const ComplexRowVector& a) const;
-  ComplexMatrix stack (const ComplexColumnVector& a) const;
-  ComplexMatrix stack (const ComplexDiagMatrix& a) const;
+  OCTAVE_API ComplexMatrix stack (const ComplexMatrix& a) const;
+  OCTAVE_API ComplexMatrix stack (const ComplexRowVector& a) const;
+  OCTAVE_API ComplexMatrix stack (const ComplexColumnVector& a) const;
+  OCTAVE_API ComplexMatrix stack (const ComplexDiagMatrix& a) const;
 
   ComplexMatrix hermitian (void) const
   { return MArray<Complex>::hermitian (std::conj); }
@@ -175,17 +176,19 @@
 
   // resize is the destructive equivalent for this one
 
-  ComplexMatrix extract (octave_idx_type r1, octave_idx_type c1,
-                         octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API ComplexMatrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
-  ComplexMatrix extract_n (octave_idx_type r1, octave_idx_type c1,
-                           octave_idx_type nr, octave_idx_type nc) const;
+  OCTAVE_API ComplexMatrix
+  extract_n (octave_idx_type r1, octave_idx_type c1,
+             octave_idx_type nr, octave_idx_type nc) const;
 
   // extract row or column i.
 
-  ComplexRowVector row (octave_idx_type i) const;
+  OCTAVE_API ComplexRowVector row (octave_idx_type i) const;
 
-  ComplexColumnVector column (octave_idx_type i) const;
+  OCTAVE_API ComplexColumnVector column (octave_idx_type i) const;
 
   void resize (octave_idx_type nr, octave_idx_type nc,
                const Complex& rfv = Complex (0))
@@ -201,34 +204,38 @@
                           double& rcon, bool force, bool calc_cond) const;
 
 public:
-  ComplexMatrix inverse (void) const;
-  ComplexMatrix inverse (octave_idx_type& info) const;
-  ComplexMatrix inverse (octave_idx_type& info, double& rcon,
-                         bool force = false, bool calc_cond = true) const;
+  OCTAVE_API ComplexMatrix inverse (void) const;
+  OCTAVE_API ComplexMatrix inverse (octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  inverse (octave_idx_type& info, double& rcon,
+           bool force = false, bool calc_cond = true) const;
 
-  ComplexMatrix inverse (MatrixType& mattype) const;
-  ComplexMatrix inverse (MatrixType& mattype, octave_idx_type& info) const;
-  ComplexMatrix inverse (MatrixType& mattype, octave_idx_type& info,
-                         double& rcon, bool force = false,
-                         bool calc_cond = true) const;
+  OCTAVE_API ComplexMatrix inverse (MatrixType& mattype) const;
+  OCTAVE_API ComplexMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info, double& rcon,
+           bool force = false, bool calc_cond = true) const;
 
-  ComplexMatrix pseudo_inverse (double tol = 0.0) const;
+  OCTAVE_API ComplexMatrix pseudo_inverse (double tol = 0.0) const;
 
-  ComplexMatrix fourier (void) const;
-  ComplexMatrix ifourier (void) const;
+  OCTAVE_API ComplexMatrix fourier (void) const;
+  OCTAVE_API ComplexMatrix ifourier (void) const;
 
-  ComplexMatrix fourier2d (void) const;
-  ComplexMatrix ifourier2d (void) const;
+  OCTAVE_API ComplexMatrix fourier2d (void) const;
+  OCTAVE_API ComplexMatrix ifourier2d (void) const;
 
-  ComplexDET determinant (void) const;
-  ComplexDET determinant (octave_idx_type& info) const;
-  ComplexDET determinant (octave_idx_type& info, double& rcon,
-                          bool calc_cond = true) const;
-  ComplexDET determinant (MatrixType& mattype, octave_idx_type& info,
-                          double& rcon, bool calc_cond = true) const;
+  OCTAVE_API ComplexDET determinant (void) const;
+  OCTAVE_API ComplexDET determinant (octave_idx_type& info) const;
+  OCTAVE_API ComplexDET
+  determinant (octave_idx_type& info, double& rcon,
+               bool calc_cond = true) const;
+  OCTAVE_API ComplexDET
+  determinant (MatrixType& mattype, octave_idx_type& info, double& rcon,
+               bool calc_cond = true) const;
 
-  double rcond (void) const;
-  double rcond (MatrixType& mattype) const;
+  OCTAVE_API double rcond (void) const;
+  OCTAVE_API double rcond (MatrixType& mattype) const;
 
 private:
   // Upper triangular matrix solvers
@@ -253,170 +260,192 @@
 
 public:
   // Generic interface to solver with no probing of type
-  ComplexMatrix solve (MatrixType& mattype, const Matrix& b) const;
-  ComplexMatrix solve (MatrixType& mattype, const Matrix& b,
-                       octave_idx_type& info) const;
-  ComplexMatrix solve (MatrixType& mattype, const Matrix& b,
-                       octave_idx_type& info, double& rcon) const;
-  ComplexMatrix solve (MatrixType& mattype, const Matrix& b,
-                       octave_idx_type& info, double& rcon,
-                       solve_singularity_handler sing_handler,
-                       bool singular_fallback = true,
-                       blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexMatrix solve (MatrixType& mattype, const Matrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
+         double& rcon) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
+         double& rcon, solve_singularity_handler sing_handler,
+         bool singular_fallback = true,
+         blas_trans_type transt = blas_no_trans) const;
+
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b, octave_idx_type& info,
+         double& rcon) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b, octave_idx_type& info,
+         double& rcon, solve_singularity_handler sing_handler,
+         bool singular_fallback = true,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info, double& rcon) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info, double& rcon,
-                       solve_singularity_handler sing_handler,
-                       bool singular_fallback = true,
-                       blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b,
+         octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b, octave_idx_type& info,
+         double& rcon, solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexColumnVector solve (MatrixType& mattype, const ColumnVector& b) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                             octave_idx_type& info, double& rcon) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                             octave_idx_type& info, double& rcon,
-                             solve_singularity_handler sing_handler,
-                             blas_trans_type transt = blas_no_trans) const;
-
-  ComplexColumnVector solve (MatrixType& mattype,
-                             const ComplexColumnVector& b) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcon) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcon,
-                             solve_singularity_handler sing_handler,
-                             blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
   // Generic interface to solver with probing of type
-  ComplexMatrix solve (const Matrix& b) const;
-  ComplexMatrix solve (const Matrix& b, octave_idx_type& info) const;
-  ComplexMatrix solve (const Matrix& b, octave_idx_type& info,
-                       double& rcon) const;
-  ComplexMatrix solve (const Matrix& b, octave_idx_type& info, double& rcon,
-                       solve_singularity_handler sing_handler,
-                       blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexMatrix solve (const Matrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (const Matrix& b, octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ComplexMatrix
+  solve (const Matrix& b, octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexMatrix solve (const ComplexMatrix& b) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info,
-                       double& rcon) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info,
-                       double& rcon,
-                       solve_singularity_handler sing_handler,
-                       blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexMatrix solve (const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexColumnVector solve (const ColumnVector& b) const;
-  ComplexColumnVector solve (const ColumnVector& b, octave_idx_type& info) const;
-  ComplexColumnVector solve (const ColumnVector& b, octave_idx_type& info,
-                             double& rcon) const;
-  ComplexColumnVector solve (const ColumnVector& b, octave_idx_type& info,
-                             double& rcon,
-                             solve_singularity_handler sing_handler,
-                             blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexColumnVector solve (const ColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexColumnVector solve (const ComplexColumnVector& b) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info,
-                             double& rcon) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info,
-                             double& rcon,
-                             solve_singularity_handler sing_handler,
-                             blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexColumnVector solve (const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info,
+         double& rcon) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexMatrix lssolve (const Matrix& b) const;
-  ComplexMatrix lssolve (const Matrix& b, octave_idx_type& info) const;
-  ComplexMatrix lssolve (const Matrix& b, octave_idx_type& info,
-                         octave_idx_type& rank) const;
-  ComplexMatrix lssolve (const Matrix& b, octave_idx_type& info,
-                         octave_idx_type& rank, double& rcon) const;
+  OCTAVE_API ComplexMatrix lssolve (const Matrix& b) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const Matrix& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const Matrix& b, octave_idx_type& info,
+           octave_idx_type& rank, double& rcon) const;
 
-  ComplexMatrix lssolve (const ComplexMatrix& b) const;
-  ComplexMatrix lssolve (const ComplexMatrix& b, octave_idx_type& info) const;
-  ComplexMatrix lssolve (const ComplexMatrix& b, octave_idx_type& info,
-                         octave_idx_type& rank) const;
-  ComplexMatrix lssolve (const ComplexMatrix& b, octave_idx_type& info,
-                         octave_idx_type& rank, double& rcon) const;
+  OCTAVE_API ComplexMatrix lssolve (const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const ComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const ComplexMatrix& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const ComplexMatrix& b, octave_idx_type& info,
+           octave_idx_type& rank, double& rcon) const;
 
-  ComplexColumnVector lssolve (const ColumnVector& b) const;
-  ComplexColumnVector lssolve (const ColumnVector& b,
-                               octave_idx_type& info) const;
-  ComplexColumnVector lssolve (const ColumnVector& b, octave_idx_type& info,
-                               octave_idx_type& rank) const;
-  ComplexColumnVector lssolve (const ColumnVector& b, octave_idx_type& info,
-                               octave_idx_type& rank, double& rcon) const;
+  OCTAVE_API ComplexColumnVector lssolve (const ColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank, double& rcon) const;
 
-  ComplexColumnVector lssolve (const ComplexColumnVector& b) const;
-  ComplexColumnVector lssolve (const ComplexColumnVector& b,
-                               octave_idx_type& info) const;
-  ComplexColumnVector lssolve (const ComplexColumnVector& b,
-                               octave_idx_type& info,
-                               octave_idx_type& rank) const;
-  ComplexColumnVector lssolve (const ComplexColumnVector& b,
-                               octave_idx_type& info,
-                               octave_idx_type& rank, double& rcon) const;
+  OCTAVE_API ComplexColumnVector lssolve (const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ComplexColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ComplexColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank, double& rcon) const;
 
   // matrix by diagonal matrix -> matrix operations
 
-  ComplexMatrix& operator += (const DiagMatrix& a);
-  ComplexMatrix& operator -= (const DiagMatrix& a);
+  OCTAVE_API ComplexMatrix& operator += (const DiagMatrix& a);
+  OCTAVE_API ComplexMatrix& operator -= (const DiagMatrix& a);
 
-  ComplexMatrix& operator += (const ComplexDiagMatrix& a);
-  ComplexMatrix& operator -= (const ComplexDiagMatrix& a);
+  OCTAVE_API ComplexMatrix& operator += (const ComplexDiagMatrix& a);
+  OCTAVE_API ComplexMatrix& operator -= (const ComplexDiagMatrix& a);
 
   // matrix by matrix -> matrix operations
 
-  ComplexMatrix& operator += (const Matrix& a);
-  ComplexMatrix& operator -= (const Matrix& a);
+  OCTAVE_API ComplexMatrix& operator += (const Matrix& a);
+  OCTAVE_API ComplexMatrix& operator -= (const Matrix& a);
 
   // other operations
 
-  boolMatrix all (int dim = -1) const;
-  boolMatrix any (int dim = -1) const;
+  OCTAVE_API boolMatrix all (int dim = -1) const;
+  OCTAVE_API boolMatrix any (int dim = -1) const;
 
-  ComplexMatrix cumprod (int dim = -1) const;
-  ComplexMatrix cumsum (int dim = -1) const;
-  ComplexMatrix prod (int dim = -1) const;
-  ComplexMatrix sum (int dim = -1) const;
-  ComplexMatrix sumsq (int dim = -1) const;
-  Matrix abs (void) const;
+  OCTAVE_API ComplexMatrix cumprod (int dim = -1) const;
+  OCTAVE_API ComplexMatrix cumsum (int dim = -1) const;
+  OCTAVE_API ComplexMatrix prod (int dim = -1) const;
+  OCTAVE_API ComplexMatrix sum (int dim = -1) const;
+  OCTAVE_API ComplexMatrix sumsq (int dim = -1) const;
+  OCTAVE_API Matrix abs (void) const;
 
-  ComplexMatrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API ComplexMatrix diag (octave_idx_type k = 0) const;
 
-  ComplexDiagMatrix diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API ComplexDiagMatrix
+  diag (octave_idx_type m, octave_idx_type n) const;
 
-  bool row_is_real_only (octave_idx_type) const;
-  bool column_is_real_only (octave_idx_type) const;
+  OCTAVE_API bool row_is_real_only (octave_idx_type) const;
+  OCTAVE_API bool column_is_real_only (octave_idx_type) const;
 
-  ComplexColumnVector row_min (void) const;
-  ComplexColumnVector row_max (void) const;
+  OCTAVE_API ComplexColumnVector row_min (void) const;
+  OCTAVE_API ComplexColumnVector row_max (void) const;
 
-  ComplexColumnVector row_min (Array<octave_idx_type>& index) const;
-  ComplexColumnVector row_max (Array<octave_idx_type>& index) const;
+  OCTAVE_API ComplexColumnVector row_min (Array<octave_idx_type>& index) const;
+  OCTAVE_API ComplexColumnVector row_max (Array<octave_idx_type>& index) const;
 
-  ComplexRowVector column_min (void) const;
-  ComplexRowVector column_max (void) const;
+  OCTAVE_API ComplexRowVector column_min (void) const;
+  OCTAVE_API ComplexRowVector column_max (void) const;
 
-  ComplexRowVector column_min (Array<octave_idx_type>& index) const;
-  ComplexRowVector column_max (Array<octave_idx_type>& index) const;
+  OCTAVE_API ComplexRowVector column_min (Array<octave_idx_type>& index) const;
+  OCTAVE_API ComplexRowVector column_max (Array<octave_idx_type>& index) const;
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const ComplexMatrix& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is,
-                                               ComplexMatrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const ComplexMatrix& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, ComplexMatrix& a);
 };
 
 extern OCTAVE_API ComplexMatrix conj (const ComplexMatrix& a);
--- a/liboctave/array/CNDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CNDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -601,7 +601,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_complex (os, a.elem (i));
+      octave::write_value<Complex> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -617,7 +617,7 @@
       Complex tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<Complex> (is);
+          tmp = octave::read_value<Complex> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/CNDArray.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CNDArray.h	Sun May 16 09:44:35 2021 +0200
@@ -64,73 +64,80 @@
 
   // unary operations
 
-  boolNDArray operator ! (void) const;
+  OCTAVE_API boolNDArray operator ! (void) const;
 
   // FIXME: this is not quite the right thing.
 
-  bool any_element_is_nan (void) const;
-  bool any_element_is_inf_or_nan (void) const;
-  bool all_elements_are_real (void) const;
-  bool all_integers (double& max_val, double& min_val) const;
-  bool too_large_for_float (void) const;
+  OCTAVE_API bool any_element_is_nan (void) const;
+  OCTAVE_API bool any_element_is_inf_or_nan (void) const;
+  OCTAVE_API bool all_elements_are_real (void) const;
+  OCTAVE_API bool all_integers (double& max_val, double& min_val) const;
+  OCTAVE_API bool too_large_for_float (void) const;
 
-  boolNDArray all (int dim = -1) const;
-  boolNDArray any (int dim = -1) const;
+  OCTAVE_API boolNDArray all (int dim = -1) const;
+  OCTAVE_API boolNDArray any (int dim = -1) const;
 
-  ComplexNDArray cumprod (int dim = -1) const;
-  ComplexNDArray cumsum (int dim = -1) const;
-  ComplexNDArray prod (int dim = -1) const;
-  ComplexNDArray sum (int dim = -1) const;
-  ComplexNDArray xsum (int dim = -1) const;
-  ComplexNDArray sumsq (int dim = -1) const;
-  ComplexNDArray concat (const ComplexNDArray& rb,
-                         const Array<octave_idx_type>& ra_idx);
-  ComplexNDArray concat (const NDArray& rb,
-                         const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API ComplexNDArray cumprod (int dim = -1) const;
+  OCTAVE_API ComplexNDArray cumsum (int dim = -1) const;
+  OCTAVE_API ComplexNDArray prod (int dim = -1) const;
+  OCTAVE_API ComplexNDArray sum (int dim = -1) const;
+  OCTAVE_API ComplexNDArray xsum (int dim = -1) const;
+  OCTAVE_API ComplexNDArray sumsq (int dim = -1) const;
+  OCTAVE_API ComplexNDArray
+  concat (const ComplexNDArray& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API ComplexNDArray
+  concat (const NDArray& rb, const Array<octave_idx_type>& ra_idx);
 
-  ComplexNDArray max (int dim = -1) const;
-  ComplexNDArray max (Array<octave_idx_type>& index, int dim = -1) const;
-  ComplexNDArray min (int dim = -1) const;
-  ComplexNDArray min (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API ComplexNDArray max (int dim = -1) const;
+  OCTAVE_API ComplexNDArray
+  max (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API ComplexNDArray min (int dim = -1) const;
+  OCTAVE_API ComplexNDArray
+  min (Array<octave_idx_type>& index, int dim = -1) const;
 
-  ComplexNDArray cummax (int dim = -1) const;
-  ComplexNDArray cummax (Array<octave_idx_type>& index, int dim = -1) const;
-  ComplexNDArray cummin (int dim = -1) const;
-  ComplexNDArray cummin (Array<octave_idx_type>& index, int dim = -1) const;
-
-  ComplexNDArray diff (octave_idx_type order = 1, int dim = -1) const;
+  OCTAVE_API ComplexNDArray cummax (int dim = -1) const;
+  OCTAVE_API ComplexNDArray
+  cummax (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API ComplexNDArray cummin (int dim = -1) const;
+  OCTAVE_API ComplexNDArray
+  cummin (Array<octave_idx_type>& index, int dim = -1) const;
 
-  ComplexNDArray& insert (const NDArray& a,
-                          octave_idx_type r, octave_idx_type c);
-  ComplexNDArray& insert (const ComplexNDArray& a,
-                          octave_idx_type r, octave_idx_type c);
-  ComplexNDArray& insert (const ComplexNDArray& a,
-                          const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API ComplexNDArray
+  diff (octave_idx_type order = 1, int dim = -1) const;
 
-  NDArray abs (void) const;
-  boolNDArray isnan (void) const;
-  boolNDArray isinf (void) const;
-  boolNDArray isfinite (void) const;
+  OCTAVE_API ComplexNDArray&
+  insert (const NDArray& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexNDArray&
+  insert (const ComplexNDArray& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API ComplexNDArray&
+  insert (const ComplexNDArray& a, const Array<octave_idx_type>& ra_idx);
+
+  OCTAVE_API NDArray abs (void) const;
+  OCTAVE_API boolNDArray isnan (void) const;
+  OCTAVE_API boolNDArray isinf (void) const;
+  OCTAVE_API boolNDArray isfinite (void) const;
 
   friend OCTAVE_API ComplexNDArray conj (const ComplexNDArray& a);
 
-  ComplexNDArray fourier (int dim = 1) const;
-  ComplexNDArray ifourier (int dim = 1) const;
+  OCTAVE_API ComplexNDArray fourier (int dim = 1) const;
+  OCTAVE_API ComplexNDArray ifourier (int dim = 1) const;
 
-  ComplexNDArray fourier2d (void) const;
-  ComplexNDArray ifourier2d (void) const;
+  OCTAVE_API ComplexNDArray fourier2d (void) const;
+  OCTAVE_API ComplexNDArray ifourier2d (void) const;
 
-  ComplexNDArray fourierNd (void) const;
-  ComplexNDArray ifourierNd (void) const;
+  OCTAVE_API ComplexNDArray fourierNd (void) const;
+  OCTAVE_API ComplexNDArray ifourierNd (void) const;
 
   ComplexNDArray squeeze (void) const { return MArray<Complex>::squeeze (); }
 
-  static void increment_index (Array<octave_idx_type>& ra_idx,
-                               const dim_vector& dimensions,
-                               int start_dimension = 0);
+  static OCTAVE_API void
+  increment_index (Array<octave_idx_type>& ra_idx,
+                   const dim_vector& dimensions,
+                   int start_dimension = 0);
 
-  static octave_idx_type compute_index (Array<octave_idx_type>& ra_idx,
-                                        const dim_vector& dimensions);
+  static OCTAVE_API octave_idx_type
+  compute_index (Array<octave_idx_type>& ra_idx,
+                 const dim_vector& dimensions);
 
   // i/o
 
@@ -142,9 +149,9 @@
   //  bool all_elements_are_real (void) const;
   //  bool all_integers (double& max_val, double& min_val) const;
 
-  ComplexNDArray diag (octave_idx_type k = 0) const;
+  OCTAVE_API ComplexNDArray diag (octave_idx_type k = 0) const;
 
-  ComplexNDArray diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API ComplexNDArray diag (octave_idx_type m, octave_idx_type n) const;
 
   ComplexNDArray& changesign (void)
   {
--- a/liboctave/array/CRowVector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CRowVector.h	Sun May 16 09:44:35 2021 +0200
@@ -66,57 +66,63 @@
     return *this;
   }
 
-  bool operator == (const ComplexRowVector& a) const;
-  bool operator != (const ComplexRowVector& a) const;
+  OCTAVE_API bool operator == (const ComplexRowVector& a) const;
+  OCTAVE_API bool operator != (const ComplexRowVector& a) const;
 
   // destructive insert/delete/reorder operations
 
-  ComplexRowVector& insert (const RowVector& a, octave_idx_type c);
-  ComplexRowVector& insert (const ComplexRowVector& a, octave_idx_type c);
+  OCTAVE_API ComplexRowVector&
+  insert (const RowVector& a, octave_idx_type c);
+  OCTAVE_API ComplexRowVector&
+  insert (const ComplexRowVector& a, octave_idx_type c);
 
-  ComplexRowVector& fill (double val);
-  ComplexRowVector& fill (const Complex& val);
-  ComplexRowVector& fill (double val, octave_idx_type c1, octave_idx_type c2);
-  ComplexRowVector& fill (const Complex& val,
-                          octave_idx_type c1, octave_idx_type c2);
+  OCTAVE_API ComplexRowVector& fill (double val);
+  OCTAVE_API ComplexRowVector& fill (const Complex& val);
+  OCTAVE_API ComplexRowVector&
+  fill (double val, octave_idx_type c1, octave_idx_type c2);
+  OCTAVE_API ComplexRowVector&
+  fill (const Complex& val, octave_idx_type c1, octave_idx_type c2);
 
-  ComplexRowVector append (const RowVector& a) const;
-  ComplexRowVector append (const ComplexRowVector& a) const;
+  OCTAVE_API ComplexRowVector append (const RowVector& a) const;
+  OCTAVE_API ComplexRowVector append (const ComplexRowVector& a) const;
 
-  ComplexColumnVector hermitian (void) const;
-  ComplexColumnVector transpose (void) const;
+  OCTAVE_API ComplexColumnVector hermitian (void) const;
+  OCTAVE_API ComplexColumnVector transpose (void) const;
 
-  friend ComplexRowVector conj (const ComplexRowVector& a);
+  friend OCTAVE_API ComplexRowVector conj (const ComplexRowVector& a);
 
   // resize is the destructive equivalent for this one
 
-  ComplexRowVector extract (octave_idx_type c1, octave_idx_type c2) const;
+  OCTAVE_API ComplexRowVector
+  extract (octave_idx_type c1, octave_idx_type c2) const;
 
-  ComplexRowVector extract_n (octave_idx_type c1, octave_idx_type n) const;
+  OCTAVE_API ComplexRowVector
+  extract_n (octave_idx_type c1, octave_idx_type n) const;
 
   // row vector by row vector -> row vector operations
 
-  ComplexRowVector& operator += (const RowVector& a);
-  ComplexRowVector& operator -= (const RowVector& a);
+  OCTAVE_API ComplexRowVector& operator += (const RowVector& a);
+  OCTAVE_API ComplexRowVector& operator -= (const RowVector& a);
 
   // row vector by matrix -> row vector
 
-  friend ComplexRowVector operator * (const ComplexRowVector& a,
-                                      const ComplexMatrix& b);
+  friend OCTAVE_API ComplexRowVector
+  operator * (const ComplexRowVector& a, const ComplexMatrix& b);
 
-  friend ComplexRowVector operator * (const RowVector& a,
-                                      const ComplexMatrix& b);
+  friend OCTAVE_API ComplexRowVector
+  operator * (const RowVector& a, const ComplexMatrix& b);
 
   // other operations
 
-  Complex min (void) const;
-  Complex max (void) const;
+  OCTAVE_API Complex min (void) const;
+  OCTAVE_API Complex max (void) const;
 
   // i/o
 
-  friend std::ostream& operator << (std::ostream& os,
-                                    const ComplexRowVector& a);
-  friend std::istream& operator >> (std::istream& is, ComplexRowVector& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const ComplexRowVector& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, ComplexRowVector& a);
 
   void resize (octave_idx_type n, const Complex& rfv = Complex (0))
   {
@@ -130,10 +136,10 @@
 
 // row vector by column vector -> scalar
 
-Complex OCTAVE_API operator * (const ComplexRowVector& a,
+OCTAVE_API Complex operator * (const ComplexRowVector& a,
                                const ColumnVector& b);
 
-Complex OCTAVE_API operator * (const ComplexRowVector& a,
+OCTAVE_API Complex operator * (const ComplexRowVector& a,
                                const ComplexColumnVector& b);
 
 // other operations
--- a/liboctave/array/CSparse.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CSparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -5756,15 +5756,12 @@
 
           B->x = const_cast<double *>(b.fortran_vec ());
 
-          cholmod_factor *L;
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          L = CHOLMOD_NAME(analyze) (A, cm);
+          cholmod_factor *L = CHOLMOD_NAME(analyze) (A, cm);
           CHOLMOD_NAME(factorize) (A, L, cm);
           if (calc_cond)
             rcond = CHOLMOD_NAME(rcond)(L, cm);
           else
             rcond = 1.;
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           if (rcond == 0.0)
             {
@@ -5791,10 +5788,7 @@
                   return retval;
                 }
 
-              cholmod_dense *X;
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-              X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+              cholmod_dense *X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
 
               retval.resize (b.rows (), b.cols ());
               for (octave_idx_type j = 0; j < b.cols (); j++)
@@ -5804,13 +5798,11 @@
                     retval.xelem (i,j) = static_cast<Complex *>(X->x)[jr + i];
                 }
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CHOLMOD_NAME(free_dense) (&X, cm);
               CHOLMOD_NAME(free_factor) (&L, cm);
               CHOLMOD_NAME(finish) (cm);
               static char blank_name[] = " ";
               CHOLMOD_NAME(print_common) (blank_name, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 #else
           (*current_liboctave_warning_with_id_handler)
@@ -6013,15 +6005,12 @@
 
           B->x = b.data ();
 
-          cholmod_factor *L;
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          L = CHOLMOD_NAME(analyze) (A, cm);
+          cholmod_factor *L = CHOLMOD_NAME(analyze) (A, cm);
           CHOLMOD_NAME(factorize) (A, L, cm);
           if (calc_cond)
             rcond = CHOLMOD_NAME(rcond)(L, cm);
           else
             rcond = 1.;
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           if (rcond == 0.0)
             {
@@ -6048,10 +6037,7 @@
                   return retval;
                 }
 
-              cholmod_sparse *X;
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-              X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+              cholmod_sparse *X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
 
               retval = SparseComplexMatrix
                        (static_cast<octave_idx_type> (X->nrow),
@@ -6067,13 +6053,11 @@
                   retval.xdata (j) = static_cast<Complex *>(X->x)[j];
                 }
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CHOLMOD_NAME(free_sparse) (&X, cm);
               CHOLMOD_NAME(free_factor) (&L, cm);
               CHOLMOD_NAME(finish) (cm);
               static char blank_name[] = " ";
               CHOLMOD_NAME(print_common) (blank_name, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 #else
           (*current_liboctave_warning_with_id_handler)
@@ -6301,15 +6285,12 @@
 
           B->x = const_cast<Complex *>(b.fortran_vec ());
 
-          cholmod_factor *L;
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          L = CHOLMOD_NAME(analyze) (A, cm);
+          cholmod_factor *L = CHOLMOD_NAME(analyze) (A, cm);
           CHOLMOD_NAME(factorize) (A, L, cm);
           if (calc_cond)
             rcond = CHOLMOD_NAME(rcond)(L, cm);
           else
             rcond = 1.;
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           if (rcond == 0.0)
             {
@@ -6336,10 +6317,7 @@
                   return retval;
                 }
 
-              cholmod_dense *X;
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-              X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+              cholmod_dense *X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
 
               retval.resize (b.rows (), b.cols ());
               for (octave_idx_type j = 0; j < b.cols (); j++)
@@ -6349,13 +6327,11 @@
                     retval.xelem (i,j) = static_cast<Complex *>(X->x)[jr + i];
                 }
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CHOLMOD_NAME(free_dense) (&X, cm);
               CHOLMOD_NAME(free_factor) (&L, cm);
               CHOLMOD_NAME(finish) (cm);
               static char blank_name[] = " ";
               CHOLMOD_NAME(print_common) (blank_name, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 #else
           (*current_liboctave_warning_with_id_handler)
@@ -6537,15 +6513,12 @@
 
           B->x = b.data ();
 
-          cholmod_factor *L;
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          L = CHOLMOD_NAME(analyze) (A, cm);
+          cholmod_factor *L = CHOLMOD_NAME(analyze) (A, cm);
           CHOLMOD_NAME(factorize) (A, L, cm);
           if (calc_cond)
             rcond = CHOLMOD_NAME(rcond)(L, cm);
           else
             rcond = 1.;
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           if (rcond == 0.0)
             {
@@ -6572,10 +6545,7 @@
                   return retval;
                 }
 
-              cholmod_sparse *X;
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-              X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+              cholmod_sparse *X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
 
               retval = SparseComplexMatrix
                        (static_cast<octave_idx_type> (X->nrow),
@@ -6591,13 +6561,11 @@
                   retval.xdata (j) = static_cast<Complex *>(X->x)[j];
                 }
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CHOLMOD_NAME(free_sparse) (&X, cm);
               CHOLMOD_NAME(free_factor) (&L, cm);
               CHOLMOD_NAME(finish) (cm);
               static char blank_name[] = " ";
               CHOLMOD_NAME(print_common) (blank_name, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 #else
           (*current_liboctave_warning_with_id_handler)
@@ -7487,7 +7455,7 @@
       for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++)
         {
           os << a.ridx (i) + 1 << ' '  << j + 1 << ' ';
-          octave_write_complex (os, a.data (i));
+          octave::write_value<Complex> (os, a.data (i));
           os << "\n";
         }
     }
@@ -7500,7 +7468,7 @@
 {
   typedef SparseComplexMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<Complex>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<Complex>);
 }
 
 SparseComplexMatrix
--- a/liboctave/array/CSparse.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/CSparse.h	Sun May 16 09:44:35 2021 +0200
@@ -88,17 +88,17 @@
   explicit SparseComplexMatrix (const ComplexNDArray& a)
     : MSparse<Complex> (a) { }
 
-  SparseComplexMatrix (const Array<Complex>& a, const idx_vector& r,
-                       const idx_vector& c, octave_idx_type nr = -1,
+  SparseComplexMatrix (const Array<Complex>& a, const octave::idx_vector& r,
+                       const octave::idx_vector& c, octave_idx_type nr = -1,
                        octave_idx_type nc = -1, bool sum_terms = true,
                        octave_idx_type nzm = -1)
     : MSparse<Complex> (a, r, c, nr, nc, sum_terms, nzm) { }
 
-  explicit SparseComplexMatrix (const SparseMatrix& a);
+  explicit OCTAVE_API SparseComplexMatrix (const SparseMatrix& a);
 
-  explicit SparseComplexMatrix (const SparseBoolMatrix& a);
+  explicit OCTAVE_API SparseComplexMatrix (const SparseBoolMatrix& a);
 
-  explicit SparseComplexMatrix (const ComplexDiagMatrix& a);
+  explicit OCTAVE_API SparseComplexMatrix (const ComplexDiagMatrix& a);
 
   SparseComplexMatrix (octave_idx_type r, octave_idx_type c,
                        octave_idx_type num_nz)
@@ -110,43 +110,45 @@
     return *this;
   }
 
-  bool operator == (const SparseComplexMatrix& a) const;
-  bool operator != (const SparseComplexMatrix& a) const;
+  OCTAVE_API bool operator == (const SparseComplexMatrix& a) const;
+  OCTAVE_API bool operator != (const SparseComplexMatrix& a) const;
 
-  bool ishermitian (void) const;
+  OCTAVE_API bool ishermitian (void) const;
 
-  SparseComplexMatrix max (int dim = -1) const;
-  SparseComplexMatrix max (Array<octave_idx_type>& index, int dim = -1) const;
-  SparseComplexMatrix min (int dim = -1) const;
-  SparseComplexMatrix min (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API SparseComplexMatrix max (int dim = -1) const;
+  OCTAVE_API SparseComplexMatrix
+  max (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API SparseComplexMatrix min (int dim = -1) const;
+  OCTAVE_API SparseComplexMatrix
+  min (Array<octave_idx_type>& index, int dim = -1) const;
 
-  SparseComplexMatrix& insert (const SparseComplexMatrix& a,
-                               octave_idx_type r, octave_idx_type c);
-  SparseComplexMatrix& insert (const SparseMatrix& a,
-                               octave_idx_type r, octave_idx_type c);
-  SparseComplexMatrix& insert (const SparseComplexMatrix& a,
-                               const Array<octave_idx_type>& indx);
-  SparseComplexMatrix& insert (const SparseMatrix& a,
-                               const Array<octave_idx_type>& indx);
+  OCTAVE_API SparseComplexMatrix&
+  insert (const SparseComplexMatrix& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API SparseComplexMatrix&
+  insert (const SparseMatrix& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API SparseComplexMatrix&
+  insert (const SparseComplexMatrix& a, const Array<octave_idx_type>& indx);
+  OCTAVE_API SparseComplexMatrix&
+  insert (const SparseMatrix& a, const Array<octave_idx_type>& indx);
 
-  SparseComplexMatrix concat (const SparseComplexMatrix& rb,
-                              const Array<octave_idx_type>& ra_idx);
-  SparseComplexMatrix concat (const SparseMatrix& rb,
-                              const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API SparseComplexMatrix
+  concat (const SparseComplexMatrix& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API SparseComplexMatrix
+  concat (const SparseMatrix& rb, const Array<octave_idx_type>& ra_idx);
 
-  ComplexMatrix matrix_value (void) const;
+  OCTAVE_API ComplexMatrix matrix_value (void) const;
 
-  SparseComplexMatrix hermitian (void) const;  // complex conjugate transpose
+  OCTAVE_API SparseComplexMatrix hermitian (void) const;  // complex conjugate transpose
   SparseComplexMatrix transpose (void) const
   { return MSparse<Complex>::transpose (); }
 
-  friend SparseComplexMatrix conj (const SparseComplexMatrix& a);
+  friend OCTAVE_API SparseComplexMatrix conj (const SparseComplexMatrix& a);
 
   // extract row or column i.
 
-  ComplexRowVector row (octave_idx_type i) const;
+  OCTAVE_API ComplexRowVector row (octave_idx_type i) const;
 
-  ComplexColumnVector column (octave_idx_type i) const;
+  OCTAVE_API ComplexColumnVector column (octave_idx_type i) const;
 
 private:
   SparseComplexMatrix dinverse (MatrixType& mattype, octave_idx_type& info,
@@ -158,18 +160,19 @@
                                 const bool calccond = true) const;
 
 public:
-  SparseComplexMatrix inverse (void) const;
-  SparseComplexMatrix inverse (MatrixType& mattype) const;
-  SparseComplexMatrix inverse (MatrixType& mattype,
-                               octave_idx_type& info) const;
-  SparseComplexMatrix inverse (MatrixType& mattype, octave_idx_type& info,
-                               double& rcond, bool force = false,
-                               bool calc_cond = true) const;
+  OCTAVE_API SparseComplexMatrix inverse (void) const;
+  OCTAVE_API SparseComplexMatrix inverse (MatrixType& mattype) const;
+  OCTAVE_API SparseComplexMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info) const;
+  OCTAVE_API SparseComplexMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info, double& rcond,
+           bool force = false, bool calc_cond = true) const;
 
-  ComplexDET determinant (void) const;
-  ComplexDET determinant (octave_idx_type& info) const;
-  ComplexDET determinant (octave_idx_type& info, double& rcond,
-                          bool calc_cond = true) const;
+  OCTAVE_API ComplexDET determinant (void) const;
+  OCTAVE_API ComplexDET determinant (octave_idx_type& info) const;
+  OCTAVE_API ComplexDET
+  determinant (octave_idx_type& info, double& rcond,
+               bool calc_cond = true) const;
 
 private:
   // Diagonal matrix solvers
@@ -304,242 +307,266 @@
 
 public:
   // Generic interface to solver with no probing of type
-  ComplexMatrix solve (MatrixType& mattype, const Matrix& b) const;
-  ComplexMatrix solve (MatrixType& mattype, const Matrix& b,
-                       octave_idx_type& info) const;
-  ComplexMatrix solve (MatrixType& mattype, const Matrix& b,
-                       octave_idx_type& info, double& rcond) const;
-  ComplexMatrix solve (MatrixType& mattype, const Matrix& b,
-                       octave_idx_type& info,
-                       double& rcond, solve_singularity_handler sing_handler,
-                       bool singular_fallback = true) const;
+  OCTAVE_API ComplexMatrix solve (MatrixType& mattype, const Matrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
+         double& rcond, solve_singularity_handler sing_handler,
+         bool singular_fallback = true) const;
 
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info, double& rcond) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info, double& rcond,
-                       solve_singularity_handler sing_handler,
-                       bool singular_fallback = true) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b,
+         octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b,
+         octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler,
+         bool singular_fallback = true) const;
 
-  SparseComplexMatrix solve (MatrixType& mattype, const SparseMatrix& b) const;
-  SparseComplexMatrix solve (MatrixType& mattype, const SparseMatrix& b,
-                             octave_idx_type& info) const;
-  SparseComplexMatrix solve (MatrixType& mattype, const SparseMatrix& b,
-                             octave_idx_type& info, double& rcond) const;
-  SparseComplexMatrix solve (MatrixType& mattype, const SparseMatrix& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler,
-                             bool singular_fallback = true) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& mattype, const SparseMatrix& b) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& mattype, const SparseMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& mattype, const SparseMatrix& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& mattype, const SparseMatrix& b, octave_idx_type& info,
+         double& rcond, solve_singularity_handler sing_handler,
+         bool singular_fallback = true) const;
 
-  SparseComplexMatrix solve (MatrixType& mattype,
-                             const SparseComplexMatrix& b) const;
-  SparseComplexMatrix solve (MatrixType& mattype, const SparseComplexMatrix& b,
-                             octave_idx_type& info) const;
-  SparseComplexMatrix solve (MatrixType& mattype, const SparseComplexMatrix& b,
-                             octave_idx_type& info, double& rcond) const;
-  SparseComplexMatrix solve (MatrixType& mattype, const SparseComplexMatrix& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler,
-                             bool singular_fallback = true) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& mattype, const SparseComplexMatrix& b) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& mattype, const SparseComplexMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& mattype, const SparseComplexMatrix& b,
+         octave_idx_type& info, double& rcond) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& mattype, const SparseComplexMatrix& b,
+         octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler,
+         bool singular_fallback = true) const;
 
-  ComplexColumnVector solve (MatrixType& mattype, const ColumnVector& b) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                             octave_idx_type& info, double& rcond) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b,
+         octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b,
+         octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  ComplexColumnVector solve (MatrixType& mattype,
-                             const ComplexColumnVector& b) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcond) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
   // Generic interface to solver with probing of type
-  ComplexMatrix solve (const Matrix& b) const;
-  ComplexMatrix solve (const Matrix& b, octave_idx_type& info) const;
-  ComplexMatrix solve (const Matrix& b, octave_idx_type& info,
-                       double& rcond) const;
-  ComplexMatrix solve (const Matrix& b, octave_idx_type& info, double& rcond,
-                       solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexMatrix solve (const Matrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (const Matrix& b, octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ComplexMatrix
+  solve (const Matrix& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  ComplexMatrix solve (const ComplexMatrix& b) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info,
-                       double& rcond) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info,
-                       double& rcond,
-                       solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexMatrix solve (const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  SparseComplexMatrix solve (const SparseMatrix& b) const;
-  SparseComplexMatrix solve (const SparseMatrix& b,
-                             octave_idx_type& info) const;
-  SparseComplexMatrix solve (const SparseMatrix& b, octave_idx_type& info,
-                             double& rcond) const;
-  SparseComplexMatrix solve (const SparseMatrix& b, octave_idx_type& info,
-                             double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API SparseComplexMatrix solve (const SparseMatrix& b) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseMatrix& b, octave_idx_type& info, double& rcond) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseMatrix& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  SparseComplexMatrix solve (const SparseComplexMatrix& b) const;
-  SparseComplexMatrix solve (const SparseComplexMatrix& b,
-                             octave_idx_type& info) const;
-  SparseComplexMatrix solve (const SparseComplexMatrix& b,
-                             octave_idx_type& info, double& rcond) const;
-  SparseComplexMatrix solve (const SparseComplexMatrix& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API SparseComplexMatrix solve (const SparseComplexMatrix& b) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseComplexMatrix& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseComplexMatrix& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  ComplexColumnVector solve (const ColumnVector& b) const;
-  ComplexColumnVector solve (const ColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (const ColumnVector& b, octave_idx_type& info,
-                             double& rcond) const;
-  ComplexColumnVector solve (const ColumnVector& b, octave_idx_type& info,
-                             double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexColumnVector solve (const ColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  ComplexColumnVector solve (const ComplexColumnVector& b) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcond) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexColumnVector solve (const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  SparseComplexMatrix squeeze (void) const;
+  OCTAVE_API SparseComplexMatrix squeeze (void) const;
 
-  SparseComplexMatrix reshape (const dim_vector& new_dims) const;
+  OCTAVE_API SparseComplexMatrix reshape (const dim_vector& new_dims) const;
 
-  SparseComplexMatrix permute (const Array<octave_idx_type>& vec,
-                               bool inv = false) const;
+  OCTAVE_API SparseComplexMatrix
+  permute (const Array<octave_idx_type>& vec, bool inv = false) const;
 
-  SparseComplexMatrix ipermute (const Array<octave_idx_type>& vec) const;
+  OCTAVE_API SparseComplexMatrix
+  ipermute (const Array<octave_idx_type>& vec) const;
 
-  bool any_element_is_nan (void) const;
-  bool any_element_is_inf_or_nan (void) const;
-  bool all_elements_are_real (void) const;
-  bool all_integers (double& max_val, double& min_val) const;
-  bool too_large_for_float (void) const;
+  OCTAVE_API bool any_element_is_nan (void) const;
+  OCTAVE_API bool any_element_is_inf_or_nan (void) const;
+  OCTAVE_API bool all_elements_are_real (void) const;
+  OCTAVE_API bool all_integers (double& max_val, double& min_val) const;
+  OCTAVE_API bool too_large_for_float (void) const;
 
-  SparseBoolMatrix operator ! (void) const;
+  OCTAVE_API SparseBoolMatrix operator ! (void) const;
 
-  SparseBoolMatrix all (int dim = -1) const;
-  SparseBoolMatrix any (int dim = -1) const;
+  OCTAVE_API SparseBoolMatrix all (int dim = -1) const;
+  OCTAVE_API SparseBoolMatrix any (int dim = -1) const;
 
-  SparseComplexMatrix cumprod (int dim = -1) const;
-  SparseComplexMatrix cumsum (int dim = -1) const;
-  SparseComplexMatrix prod (int dim = -1) const;
-  SparseComplexMatrix sum (int dim = -1) const;
-  SparseComplexMatrix sumsq (int dim = -1) const;
-  SparseMatrix abs (void) const;
+  OCTAVE_API SparseComplexMatrix cumprod (int dim = -1) const;
+  OCTAVE_API SparseComplexMatrix cumsum (int dim = -1) const;
+  OCTAVE_API SparseComplexMatrix prod (int dim = -1) const;
+  OCTAVE_API SparseComplexMatrix sum (int dim = -1) const;
+  OCTAVE_API SparseComplexMatrix sumsq (int dim = -1) const;
+  OCTAVE_API SparseMatrix abs (void) const;
 
-  SparseComplexMatrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API SparseComplexMatrix diag (octave_idx_type k = 0) const;
 
   // i/o
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const SparseComplexMatrix& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is,
-                                               SparseComplexMatrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const SparseComplexMatrix& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, SparseComplexMatrix& a);
 };
 
-extern OCTAVE_API SparseComplexMatrix operator * (const SparseMatrix&,
-                                                  const SparseComplexMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator * (const SparseComplexMatrix&,
-                                                  const SparseMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator * (const SparseComplexMatrix&,
-                                                  const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const SparseMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const SparseComplexMatrix&, const SparseMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const SparseComplexMatrix&, const SparseComplexMatrix&);
 
-extern OCTAVE_API ComplexMatrix operator * (const Matrix&,
-                                            const SparseComplexMatrix&);
-extern OCTAVE_API ComplexMatrix operator * (const ComplexMatrix&,
-                                            const SparseMatrix&);
-extern OCTAVE_API ComplexMatrix operator * (const ComplexMatrix&,
-                                            const SparseComplexMatrix&);
-extern OCTAVE_API ComplexMatrix mul_trans (const ComplexMatrix&,
-                                           const SparseComplexMatrix&);
-extern OCTAVE_API ComplexMatrix mul_herm (const ComplexMatrix&,
-                                          const SparseComplexMatrix&);
+extern OCTAVE_API ComplexMatrix
+operator * (const Matrix&, const SparseComplexMatrix&);
+extern OCTAVE_API ComplexMatrix
+operator * (const ComplexMatrix&, const SparseMatrix&);
+extern OCTAVE_API ComplexMatrix
+operator * (const ComplexMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API ComplexMatrix
+mul_trans (const ComplexMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API ComplexMatrix
+mul_herm (const ComplexMatrix&, const SparseComplexMatrix&);
 
-extern OCTAVE_API ComplexMatrix operator * (const SparseMatrix&,
-                                            const ComplexMatrix&);
-extern OCTAVE_API ComplexMatrix operator * (const SparseComplexMatrix&,
-                                            const Matrix&);
-extern OCTAVE_API ComplexMatrix operator * (const SparseComplexMatrix&,
-                                            const ComplexMatrix&);
-extern OCTAVE_API ComplexMatrix trans_mul (const SparseComplexMatrix&,
-                                           const ComplexMatrix&);
-extern OCTAVE_API ComplexMatrix herm_mul (const SparseComplexMatrix&,
-                                          const ComplexMatrix&);
+extern OCTAVE_API ComplexMatrix
+operator * (const SparseMatrix&, const ComplexMatrix&);
+extern OCTAVE_API ComplexMatrix
+operator * (const SparseComplexMatrix&, const Matrix&);
+extern OCTAVE_API ComplexMatrix
+operator * (const SparseComplexMatrix&, const ComplexMatrix&);
+extern OCTAVE_API ComplexMatrix
+trans_mul (const SparseComplexMatrix&, const ComplexMatrix&);
+extern OCTAVE_API ComplexMatrix
+herm_mul (const SparseComplexMatrix&, const ComplexMatrix&);
 
-extern OCTAVE_API SparseComplexMatrix operator * (const DiagMatrix&,
-                                                  const SparseComplexMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator * (const SparseComplexMatrix&,
-                                                  const DiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const DiagMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const SparseComplexMatrix&, const DiagMatrix&);
 
-extern OCTAVE_API SparseComplexMatrix operator * (const ComplexDiagMatrix&,
-                                                  const SparseMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator * (const SparseMatrix&,
-                                                  const ComplexDiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const ComplexDiagMatrix&, const SparseMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const SparseMatrix&, const ComplexDiagMatrix&);
 
-extern OCTAVE_API SparseComplexMatrix operator * (const ComplexDiagMatrix&,
-                                                  const SparseComplexMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator * (const SparseComplexMatrix&,
-                                                  const ComplexDiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const ComplexDiagMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const SparseComplexMatrix&, const ComplexDiagMatrix&);
 
-extern OCTAVE_API SparseComplexMatrix operator + (const ComplexDiagMatrix&,
-                                                  const SparseMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator + (const DiagMatrix&,
-                                                  const SparseComplexMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator + (const ComplexDiagMatrix&,
-                                                  const SparseComplexMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator + (const SparseMatrix&,
-                                                  const ComplexDiagMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator + (const SparseComplexMatrix&,
-                                                  const DiagMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator + (const SparseComplexMatrix&,
-                                                  const ComplexDiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator + (const ComplexDiagMatrix&, const SparseMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator + (const DiagMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator + (const ComplexDiagMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator + (const SparseMatrix&, const ComplexDiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator + (const SparseComplexMatrix&, const DiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator + (const SparseComplexMatrix&, const ComplexDiagMatrix&);
 
-extern OCTAVE_API SparseComplexMatrix operator - (const ComplexDiagMatrix&,
-                                                  const SparseMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator - (const DiagMatrix&,
-                                                  const SparseComplexMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator - (const ComplexDiagMatrix&,
-                                                  const SparseComplexMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator - (const SparseMatrix&,
-                                                  const ComplexDiagMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator - (const SparseComplexMatrix&,
-                                                  const DiagMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator - (const SparseComplexMatrix&,
-                                                  const ComplexDiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator - (const ComplexDiagMatrix&, const SparseMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator - (const DiagMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator - (const ComplexDiagMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator - (const SparseMatrix&, const ComplexDiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator - (const SparseComplexMatrix&, const DiagMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator - (const SparseComplexMatrix&, const ComplexDiagMatrix&);
 
-extern OCTAVE_API SparseComplexMatrix operator * (const PermMatrix&,
-                                                  const SparseComplexMatrix&);
-extern OCTAVE_API SparseComplexMatrix operator * (const SparseComplexMatrix&,
-                                                  const PermMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const PermMatrix&, const SparseComplexMatrix&);
+extern OCTAVE_API SparseComplexMatrix
+operator * (const SparseComplexMatrix&, const PermMatrix&);
 
-extern OCTAVE_API SparseComplexMatrix min (const Complex& c,
-                                           const SparseComplexMatrix& m);
-extern OCTAVE_API SparseComplexMatrix min (const SparseComplexMatrix& m,
-                                           const Complex& c);
-extern OCTAVE_API SparseComplexMatrix min (const SparseComplexMatrix& a,
-                                           const SparseComplexMatrix& b);
+extern OCTAVE_API SparseComplexMatrix
+min (const Complex& c, const SparseComplexMatrix& m);
+extern OCTAVE_API SparseComplexMatrix
+min (const SparseComplexMatrix& m, const Complex& c);
+extern OCTAVE_API SparseComplexMatrix
+min (const SparseComplexMatrix& a, const SparseComplexMatrix& b);
 
-extern OCTAVE_API SparseComplexMatrix max (const Complex& c,
-                                           const SparseComplexMatrix& m);
-extern OCTAVE_API SparseComplexMatrix max (const SparseComplexMatrix& m,
-                                           const Complex& c);
-extern OCTAVE_API SparseComplexMatrix max (const SparseComplexMatrix& a,
-                                           const SparseComplexMatrix& b);
+extern OCTAVE_API SparseComplexMatrix
+max (const Complex& c, const SparseComplexMatrix& m);
+extern OCTAVE_API SparseComplexMatrix
+max (const SparseComplexMatrix& m, const Complex& c);
+extern OCTAVE_API SparseComplexMatrix
+max (const SparseComplexMatrix& a, const SparseComplexMatrix& b);
 
 SPARSE_SMS_CMP_OP_DECLS (SparseComplexMatrix, Complex, OCTAVE_API)
 SPARSE_SMS_BOOL_OP_DECLS (SparseComplexMatrix, Complex, OCTAVE_API)
--- a/liboctave/array/DiagArray2.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/DiagArray2.h	Sun May 16 09:44:35 2021 +0200
@@ -38,6 +38,7 @@
 
 template <typename T>
 class
+OCTAVE_API
 DiagArray2 : protected Array<T>
 {
 protected:
@@ -103,7 +104,7 @@
 
   int ndims (void) const { return 2; }
 
-  Array<T> extract_diag (octave_idx_type k = 0) const;
+  OCTAVE_API Array<T> extract_diag (octave_idx_type k = 0) const;
 
   DiagArray2<T> build_diag_matrix () const
   {
@@ -118,7 +119,7 @@
     return (r == c) ? Array<T>::elem (r) : T (0);
   }
 
-  T& elem (octave_idx_type r, octave_idx_type c);
+  OCTAVE_API T& elem (octave_idx_type r, octave_idx_type c);
 
   T dgelem (octave_idx_type i) const
   { return Array<T>::elem (i); }
@@ -154,16 +155,16 @@
   T dgxelem (octave_idx_type i) const
   { return Array<T>::xelem (i); }
 
-  void resize (octave_idx_type n, octave_idx_type m, const T& rfv);
+  OCTAVE_API void resize (octave_idx_type n, octave_idx_type m, const T& rfv);
   void resize (octave_idx_type n, octave_idx_type m)
   {
     resize (n, m, Array<T>::resize_fill_value ());
   }
 
-  DiagArray2<T> transpose (void) const;
-  DiagArray2<T> hermitian (T (*fcn) (const T&) = nullptr) const;
+  OCTAVE_API DiagArray2<T> transpose (void) const;
+  OCTAVE_API DiagArray2<T> hermitian (T (*fcn) (const T&) = nullptr) const;
 
-  Array<T> array_value (void) const;
+  OCTAVE_API Array<T> array_value (void) const;
 
   const T * data (void) const { return Array<T>::data (); }
 
--- a/liboctave/array/MArray-C.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MArray-C.cc	Sun May 16 09:44:35 2021 +0200
@@ -34,13 +34,13 @@
 #include "MArray.h"
 #include "MArray.cc"
 
-template class OCTAVE_API MArray<Complex>;
+INSTANTIATE_MARRAY (Complex);
 
 INSTANTIATE_MARRAY_FRIENDS (Complex, OCTAVE_API)
 
 #include "MDiagArray2.h"
 #include "MDiagArray2.cc"
 
-template class OCTAVE_API MDiagArray2<Complex>;
+template class MDiagArray2<Complex>;
 
 INSTANTIATE_MDIAGARRAY2_FRIENDS (Complex, OCTAVE_API)
--- a/liboctave/array/MArray-d.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MArray-d.cc	Sun May 16 09:44:35 2021 +0200
@@ -32,13 +32,13 @@
 #include "MArray.h"
 #include "MArray.cc"
 
-template class OCTAVE_API MArray<double>;
+INSTANTIATE_MARRAY (double);
 
 INSTANTIATE_MARRAY_FRIENDS (double, OCTAVE_API)
 
 #include "MDiagArray2.h"
 #include "MDiagArray2.cc"
 
-template class OCTAVE_API MDiagArray2<double>;
+template class MDiagArray2<double>;
 
 INSTANTIATE_MDIAGARRAY2_FRIENDS (double, OCTAVE_API)
--- a/liboctave/array/MArray-f.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MArray-f.cc	Sun May 16 09:44:35 2021 +0200
@@ -32,13 +32,13 @@
 #include "MArray.h"
 #include "MArray.cc"
 
-template class OCTAVE_API MArray<float>;
+INSTANTIATE_MARRAY (float);
 
 INSTANTIATE_MARRAY_FRIENDS (float, OCTAVE_API)
 
 #include "MDiagArray2.h"
 #include "MDiagArray2.cc"
 
-template class OCTAVE_API MDiagArray2<float>;
+template class MDiagArray2<float>;
 
 INSTANTIATE_MDIAGARRAY2_FRIENDS (float, OCTAVE_API)
--- a/liboctave/array/MArray-fC.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MArray-fC.cc	Sun May 16 09:44:35 2021 +0200
@@ -34,13 +34,13 @@
 #include "MArray.h"
 #include "MArray.cc"
 
-template class OCTAVE_API MArray<FloatComplex>;
+INSTANTIATE_MARRAY (FloatComplex);
 
 INSTANTIATE_MARRAY_FRIENDS (FloatComplex, OCTAVE_API)
 
 #include "MDiagArray2.h"
 #include "MDiagArray2.cc"
 
-template class OCTAVE_API MDiagArray2<FloatComplex>;
+template class MDiagArray2<FloatComplex>;
 
 INSTANTIATE_MDIAGARRAY2_FRIENDS (FloatComplex, OCTAVE_API)
--- a/liboctave/array/MArray-i.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MArray-i.cc	Sun May 16 09:44:35 2021 +0200
@@ -34,9 +34,9 @@
 #include "MArray.h"
 #include "MArray.cc"
 
-template class OCTAVE_API MArray<int>;
+INSTANTIATE_MARRAY (int);
 #if defined (OCTAVE_ENABLE_64)
-template class OCTAVE_API MArray<int64_t>;
+INSTANTIATE_MARRAY (int64_t);
 #endif
 
 INSTANTIATE_MARRAY_FRIENDS (int, OCTAVE_API)
@@ -44,20 +44,20 @@
 INSTANTIATE_MARRAY_FRIENDS (int64_t, OCTAVE_API)
 #endif
 
-template class OCTAVE_API MArray<octave_int8>;
-template class OCTAVE_API MArray<octave_int16>;
-template class OCTAVE_API MArray<octave_int32>;
-template class OCTAVE_API MArray<octave_int64>;
+INSTANTIATE_MARRAY (octave_int8);
+INSTANTIATE_MARRAY (octave_int16);
+INSTANTIATE_MARRAY (octave_int32);
+INSTANTIATE_MARRAY (octave_int64);
 
 INSTANTIATE_MARRAY_FRIENDS (octave_int8, OCTAVE_API)
 INSTANTIATE_MARRAY_FRIENDS (octave_int16, OCTAVE_API)
 INSTANTIATE_MARRAY_FRIENDS (octave_int32, OCTAVE_API)
 INSTANTIATE_MARRAY_FRIENDS (octave_int64, OCTAVE_API)
 
-template class OCTAVE_API MArray<octave_uint8>;
-template class OCTAVE_API MArray<octave_uint16>;
-template class OCTAVE_API MArray<octave_uint32>;
-template class OCTAVE_API MArray<octave_uint64>;
+INSTANTIATE_MARRAY (octave_uint8);
+INSTANTIATE_MARRAY (octave_uint16);
+INSTANTIATE_MARRAY (octave_uint32);
+INSTANTIATE_MARRAY (octave_uint64);
 
 INSTANTIATE_MARRAY_FRIENDS (octave_uint8, OCTAVE_API)
 INSTANTIATE_MARRAY_FRIENDS (octave_uint16, OCTAVE_API)
@@ -67,6 +67,6 @@
 #include "MDiagArray2.h"
 #include "MDiagArray2.cc"
 
-template class OCTAVE_API MDiagArray2<int>;
+template class MDiagArray2<int>;
 
 INSTANTIATE_MDIAGARRAY2_FRIENDS (int, OCTAVE_API)
--- a/liboctave/array/MArray-s.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MArray-s.cc	Sun May 16 09:44:35 2021 +0200
@@ -32,13 +32,13 @@
 #include "MArray.h"
 #include "MArray.cc"
 
-template class OCTAVE_API MArray<short>;
+INSTANTIATE_MARRAY (short);
 
 INSTANTIATE_MARRAY_FRIENDS (short, OCTAVE_API)
 
 #include "MDiagArray2.h"
 #include "MDiagArray2.cc"
 
-template class OCTAVE_API MDiagArray2<short>;
+template class MDiagArray2<short>;
 
 INSTANTIATE_MDIAGARRAY2_FRIENDS (short, OCTAVE_API)
--- a/liboctave/array/MArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -53,7 +53,7 @@
 
 template <typename T>
 void
-MArray<T>::idx_add (const idx_vector& idx, T val)
+MArray<T>::idx_add (const octave::idx_vector& idx, T val)
 {
   octave_idx_type n = this->numel ();
   octave_idx_type ext = idx.extent (n);
@@ -71,7 +71,7 @@
 
 template <typename T>
 void
-MArray<T>::idx_add (const idx_vector& idx, const MArray<T>& vals)
+MArray<T>::idx_add (const octave::idx_vector& idx, const MArray<T>& vals)
 {
   octave_idx_type n = this->numel ();
   octave_idx_type ext = idx.extent (n);
@@ -100,7 +100,7 @@
 
 template <typename T>
 void
-MArray<T>::idx_min (const idx_vector& idx, const MArray<T>& vals)
+MArray<T>::idx_min (const octave::idx_vector& idx, const MArray<T>& vals)
 {
   octave_idx_type n = this->numel ();
   octave_idx_type ext = idx.extent (n);
@@ -119,7 +119,7 @@
 
 template <typename T>
 void
-MArray<T>::idx_max (const idx_vector& idx, const MArray<T>& vals)
+MArray<T>::idx_max (const octave::idx_vector& idx, const MArray<T>& vals)
 {
   octave_idx_type n = this->numel ();
   octave_idx_type ext = idx.extent (n);
@@ -137,8 +137,8 @@
 }
 
 template <typename T>
-void MArray<T>::idx_add_nd (const idx_vector& idx, const MArray<T>& vals,
-                            int dim)
+void MArray<T>::idx_add_nd (const octave::idx_vector& idx,
+                            const MArray<T>& vals, int dim)
 {
   int nd = std::max (this->ndims (), vals.ndims ());
   if (dim < 0)
@@ -359,3 +359,9 @@
 {
   return do_mx_unary_op<T, T> (a, mx_inline_uminus);
 }
+
+#if defined (__clang__)
+#  define INSTANTIATE_MARRAY(T) template class OCTAVE_API MArray<T>
+#else
+#  define INSTANTIATE_MARRAY(T) template class MArray<T>
+#endif
--- a/liboctave/array/MArray.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MArray.h	Sun May 16 09:44:35 2021 +0200
@@ -31,34 +31,36 @@
 #include "Array.h"
 #include "mx-inlines.cc"
 
-template <typename T> class MArray;
+// forward declare template with visibility attribute
+template <typename T> class OCTAVE_API MArray;
 
-template <typename T> MArray<T>& operator += (MArray<T>&, const T&);
-template <typename T> MArray<T>& operator -= (MArray<T>&, const T&);
-template <typename T> MArray<T>& operator *= (MArray<T>&, const T&);
-template <typename T> MArray<T>& operator /= (MArray<T>&, const T&);
-template <typename T> MArray<T>& operator += (MArray<T>&, const MArray<T>&);
-template <typename T> MArray<T>& operator -= (MArray<T>&, const MArray<T>&);
-template <typename T> MArray<T>& product_eq (MArray<T>&, const MArray<T>&);
-template <typename T> MArray<T>& quotient_eq (MArray<T>&, const MArray<T>&);
-template <typename T> MArray<T> operator + (const MArray<T>&);
-template <typename T> MArray<T> operator - (const MArray<T>&);
-template <typename T> MArray<T> operator + (const MArray<T>&, const T&);
-template <typename T> MArray<T> operator - (const MArray<T>&, const T&);
-template <typename T> MArray<T> operator * (const MArray<T>&, const T&);
-template <typename T> MArray<T> operator / (const MArray<T>&, const T&);
-template <typename T> MArray<T> operator + (const T&, const MArray<T>&);
-template <typename T> MArray<T> operator - (const T&, const MArray<T>&);
-template <typename T> MArray<T> operator * (const T&, const MArray<T>&);
-template <typename T> MArray<T> operator / (const T&, const MArray<T>&);
-template <typename T> MArray<T> operator + (const MArray<T>&, const MArray<T>&);
-template <typename T> MArray<T> operator - (const MArray<T>&, const MArray<T>&);
-template <typename T> MArray<T> quotient (const MArray<T>&, const MArray<T>&);
-template <typename T> MArray<T> product (const MArray<T>&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T>& operator += (MArray<T>&, const T&);
+template <typename T> OCTAVE_API MArray<T>& operator -= (MArray<T>&, const T&);
+template <typename T> OCTAVE_API MArray<T>& operator *= (MArray<T>&, const T&);
+template <typename T> OCTAVE_API MArray<T>& operator /= (MArray<T>&, const T&);
+template <typename T> OCTAVE_API MArray<T>& operator += (MArray<T>&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T>& operator -= (MArray<T>&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T>& product_eq (MArray<T>&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T>& quotient_eq (MArray<T>&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> operator + (const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> operator - (const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> operator + (const MArray<T>&, const T&);
+template <typename T> OCTAVE_API MArray<T> operator - (const MArray<T>&, const T&);
+template <typename T> OCTAVE_API MArray<T> operator * (const MArray<T>&, const T&);
+template <typename T> OCTAVE_API MArray<T> operator / (const MArray<T>&, const T&);
+template <typename T> OCTAVE_API MArray<T> operator + (const T&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> operator - (const T&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> operator * (const T&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> operator / (const T&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> operator + (const MArray<T>&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> operator - (const MArray<T>&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> quotient (const MArray<T>&, const MArray<T>&);
+template <typename T> OCTAVE_API MArray<T> product (const MArray<T>&, const MArray<T>&);
 
 //! Template for N-dimensional array classes with like-type math operators.
 template <typename T>
 class
+OCTAVE_API
 MArray : public Array<T>
 {
 protected:
@@ -110,17 +112,22 @@
 
   //! Performs indexed accumulative addition.
   //@{
-  void idx_add (const idx_vector& idx, T val);
-  void idx_add (const idx_vector& idx, const MArray<T>& vals);
+  OCTAVE_API void idx_add (const octave::idx_vector& idx, T val);
+  OCTAVE_API void
+  idx_add (const octave::idx_vector& idx, const MArray<T>& vals);
   //@}
 
-  void idx_min (const idx_vector& idx, const MArray<T>& vals);
+  OCTAVE_API void
+  idx_min (const octave::idx_vector& idx, const MArray<T>& vals);
 
-  void idx_max (const idx_vector& idx, const MArray<T>& vals);
+  OCTAVE_API void
+  idx_max (const octave::idx_vector& idx, const MArray<T>& vals);
 
-  void idx_add_nd (const idx_vector& idx, const MArray<T>& vals, int dim = -1);
+  OCTAVE_API void
+  idx_add_nd (const octave::idx_vector& idx, const MArray<T>& vals,
+              int dim = -1);
 
-  void changesign (void);
+  OCTAVE_API void changesign (void);
 };
 
 // Define all the MArray forwarding functions for return type R and
--- a/liboctave/array/MDiagArray2.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MDiagArray2.h	Sun May 16 09:44:35 2021 +0200
@@ -51,6 +51,7 @@
 //! Template for two dimensional diagonal array with math operators.
 template <typename T>
 class
+OCTAVE_API
 MDiagArray2 : public DiagArray2<T>
 {
 public:
@@ -106,22 +107,25 @@
   MDiagArray2<T> hermitian (T (*fcn) (const T&) = nullptr) const
   { return DiagArray2<T>::hermitian (fcn); }
 
-  bool is_multiple_of_identity (T val) const;
+  OCTAVE_API bool is_multiple_of_identity (T val) const;
 
   // Currently, the OPS functions don't need to be friends, but that
   // may change.
 
-  friend MDiagArray2<T> operator + <> (const MDiagArray2<T>&);
-  friend MDiagArray2<T> operator - <> (const MDiagArray2<T>&);
-  friend MDiagArray2<T> operator * <> (const MDiagArray2<T>&, const T&);
-  friend MDiagArray2<T> operator / <> (const MDiagArray2<T>&, const T&);
-  friend MDiagArray2<T> operator * <> (const T&, const MDiagArray2<T>&);
-  friend MDiagArray2<T> operator + <> (const MDiagArray2<T>&,
-                                       const MDiagArray2<T>&);
-  friend MDiagArray2<T> operator - <> (const MDiagArray2<T>&,
-                                       const MDiagArray2<T>&);
-  friend MDiagArray2<T> product <> (const MDiagArray2<T>&,
-                                    const MDiagArray2<T>&);
+  friend OCTAVE_API MDiagArray2<T> operator + <> (const MDiagArray2<T>&);
+  friend OCTAVE_API MDiagArray2<T> operator - <> (const MDiagArray2<T>&);
+  friend OCTAVE_API MDiagArray2<T>
+  operator * <> (const MDiagArray2<T>&, const T&);
+  friend OCTAVE_API MDiagArray2<T>
+  operator / <> (const MDiagArray2<T>&, const T&);
+  friend OCTAVE_API MDiagArray2<T>
+  operator * <> (const T&, const MDiagArray2<T>&);
+  friend OCTAVE_API MDiagArray2<T>
+  operator + <> (const MDiagArray2<T>&, const MDiagArray2<T>&);
+  friend OCTAVE_API MDiagArray2<T>
+  operator - <> (const MDiagArray2<T>&, const MDiagArray2<T>&);
+  friend OCTAVE_API MDiagArray2<T>
+  product <> (const MDiagArray2<T>&, const MDiagArray2<T>&);
 
 };
 
--- a/liboctave/array/MSparse-C.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MSparse-C.cc	Sun May 16 09:44:35 2021 +0200
@@ -31,6 +31,6 @@
 
 #include "MSparse.h"
 
-template class OCTAVE_API MSparse<Complex>;
+template class MSparse<Complex>;
 
 INSTANTIATE_SPARSE_FRIENDS (Complex, OCTAVE_API);
--- a/liboctave/array/MSparse-d.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MSparse-d.cc	Sun May 16 09:44:35 2021 +0200
@@ -29,6 +29,6 @@
 
 #include "MSparse.h"
 
-template class OCTAVE_API MSparse<double>;
+template class MSparse<double>;
 
 INSTANTIATE_SPARSE_FRIENDS (double, OCTAVE_API);
--- a/liboctave/array/MSparse.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MSparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -366,14 +366,14 @@
 
 template <typename T>
 MSparse<T>
-operator+ (const MSparse<T>& a, const MSparse<T>& b)
+operator + (const MSparse<T>& a, const MSparse<T>& b)
 {
   return plus_or_minus (a, b, std::plus<T> (), "operator +", false);
 }
 
 template <typename T>
 MSparse<T>
-operator- (const MSparse<T>& a, const MSparse<T>& b)
+operator - (const MSparse<T>& a, const MSparse<T>& b)
 {
   return plus_or_minus (a, b, std::minus<T> (), "operator -", true);
 }
--- a/liboctave/array/MSparse.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MSparse.h	Sun May 16 09:44:35 2021 +0200
@@ -35,9 +35,13 @@
 #include "quit.h"
 
 
+// forward declare template with visibility attributes
+template <typename T> class OCTAVE_API MSparse;
+
 // Two dimensional sparse array with math ops.
 template <typename T>
 class
+OCTAVE_API
 MSparse : public Sparse<T>
 {
 public:
@@ -58,7 +62,7 @@
   template <typename U>
   MSparse (const Sparse<U>& a) : Sparse<T> (a) { }
 
-  MSparse (const Array<T>& a, const idx_vector& r, const idx_vector& c,
+  MSparse (const Array<T>& a, const octave::idx_vector& r, const octave::idx_vector& c,
            octave_idx_type nr = -1, octave_idx_type nc = -1,
            bool sum_terms = true, octave_idx_type nzm = -1)
     : Sparse<T> (a, r, c, nr, nc, sum_terms, nzm) { }
@@ -111,12 +115,12 @@
 
   // FIXME: should go away.
   template <typename U>
-  MSparse<U>
+  Sparse<U>
   map (U (&fcn) (T)) const
   { return Sparse<T>::template map<U> (fcn); }
 
   template <typename U>
-  MSparse<U>
+  Sparse<U>
   map (U (&fcn) (const T&)) const
   { return Sparse<T>::template map<U> (fcn); }
 };
--- a/liboctave/array/MatrixType.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MatrixType.cc	Sun May 16 09:44:35 2021 +0200
@@ -116,8 +116,8 @@
         {
           for (octave_idx_type i = 0; i < j; i++)
             {
-              double aij = a.elem (i,j);
-              double aji = a.elem (j,i);
+              T aij = a.elem (i,j);
+              T aji = a.elem (j,i);
               lower = lower && (aij == zero);
               upper = upper && (aji == zero);
               hermitian = hermitian && (aij == aji
--- a/liboctave/array/MatrixType.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/MatrixType.h	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,6 @@
 class SparseComplexMatrix;
 
 class
-OCTAVE_API
 MatrixType
 {
 public:
@@ -60,46 +59,47 @@
     Rectangular
   };
 
-  MatrixType (void);
+  OCTAVE_API MatrixType (void);
 
-  MatrixType (const MatrixType& a);
+  OCTAVE_API MatrixType (const MatrixType& a);
 
-  MatrixType (const Matrix& a);
+  OCTAVE_API MatrixType (const Matrix& a);
 
-  MatrixType (const ComplexMatrix& a);
+  OCTAVE_API MatrixType (const ComplexMatrix& a);
 
-  MatrixType (const FloatMatrix& a);
+  OCTAVE_API MatrixType (const FloatMatrix& a);
 
-  MatrixType (const FloatComplexMatrix& a);
+  OCTAVE_API MatrixType (const FloatComplexMatrix& a);
 
   template <typename T>
+  OCTAVE_API
   MatrixType (const MSparse<T> &a);
 
-  MatrixType (const matrix_type t, bool _full = false);
+  OCTAVE_API MatrixType (const matrix_type t, bool _full = false);
 
-  MatrixType (const matrix_type t, const octave_idx_type np,
+  OCTAVE_API MatrixType (const matrix_type t, const octave_idx_type np,
               const octave_idx_type *p, bool _full = false);
 
-  MatrixType (const matrix_type t, const octave_idx_type ku,
+  OCTAVE_API MatrixType (const matrix_type t, const octave_idx_type ku,
               const octave_idx_type kl, bool _full = false);
 
-  ~MatrixType (void);
+  OCTAVE_API ~MatrixType (void);
 
-  MatrixType& operator = (const MatrixType& a);
+  OCTAVE_API MatrixType& operator = (const MatrixType& a);
 
-  int type (bool quiet = true);
+  OCTAVE_API int type (bool quiet = true);
 
-  int type (const Matrix& a);
+  OCTAVE_API int type (const Matrix& a);
 
-  int type (const ComplexMatrix& a);
+  OCTAVE_API int type (const ComplexMatrix& a);
 
-  int type (const FloatMatrix& a);
+  OCTAVE_API int type (const FloatMatrix& a);
 
-  int type (const FloatComplexMatrix& a);
+  OCTAVE_API int type (const FloatComplexMatrix& a);
 
-  int type (const SparseMatrix& a);
+  OCTAVE_API int type (const SparseMatrix& a);
 
-  int type (const SparseComplexMatrix& a);
+  OCTAVE_API int type (const SparseComplexMatrix& a);
 
   double band_density (void) const { return bandden; }
 
@@ -136,7 +136,7 @@
 
   bool is_unknown (void) const { return (typ == Unknown); }
 
-  void info (void) const;
+  OCTAVE_API void info (void) const;
 
   octave_idx_type * triangular_perm (void) const { return perm; }
 
@@ -163,15 +163,15 @@
 
   void mark_as_not_dense (void) { dense = false; }
 
-  void mark_as_symmetric (void);
+  OCTAVE_API void mark_as_symmetric (void);
 
-  void mark_as_unsymmetric (void);
+  OCTAVE_API void mark_as_unsymmetric (void);
 
-  void mark_as_permuted (const octave_idx_type np, const octave_idx_type *p);
+  OCTAVE_API void mark_as_permuted (const octave_idx_type np, const octave_idx_type *p);
 
-  void mark_as_unpermuted (void);
+  OCTAVE_API void mark_as_unpermuted (void);
 
-  MatrixType transpose (void) const;
+  OCTAVE_API MatrixType transpose (void) const;
 
 private:
   void type (int new_typ) { typ = static_cast<matrix_type> (new_typ); }
--- a/liboctave/array/PermMatrix.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/PermMatrix.cc	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
 {
   if (check)
     {
-      if (! idx_vector (p).is_permutation (p.numel ()))
+      if (! octave::idx_vector (p).is_permutation (p.numel ()))
         err_invalid_permutation ();
     }
 
@@ -59,7 +59,7 @@
 }
 
 void
-PermMatrix::setup (const idx_vector& idx, bool colp, octave_idx_type n)
+PermMatrix::setup (const octave::idx_vector& idx, bool colp, octave_idx_type n)
 {
   octave_idx_type len = idx.length (n);
 
@@ -74,7 +74,7 @@
     *this = this->transpose ();
 }
 
-PermMatrix::PermMatrix (const idx_vector& idx, bool colp, octave_idx_type n)
+PermMatrix::PermMatrix (const octave::idx_vector& idx, bool colp, octave_idx_type n)
   : Array<octave_idx_type> ()
 {
   setup (idx, colp, n);
@@ -220,7 +220,7 @@
   if (n != b.rows ())
     octave::err_nonconformant ("operator *", n, n, b.rows (), b.rows ());
 
-  r = PermMatrix (ia.index (idx_vector (ib)), true, false);
+  r = PermMatrix (ia.index (octave::idx_vector (ib)), true, false);
 
   return r;
 }
--- a/liboctave/array/PermMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/PermMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -46,11 +46,13 @@
 
   ~PermMatrix (void) = default;
 
-  PermMatrix (octave_idx_type n);
+  OCTAVE_API PermMatrix (octave_idx_type n);
 
-  PermMatrix (const Array<octave_idx_type>& p, bool colp, bool check = true);
+  OCTAVE_API PermMatrix (const Array<octave_idx_type>& p, bool colp,
+                         bool check = true);
 
-  PermMatrix (const idx_vector& idx, bool colp, octave_idx_type n = 0);
+  OCTAVE_API PermMatrix (const octave::idx_vector& idx, bool colp,
+                         octave_idx_type n = 0);
 
   octave_idx_type dim1 (void) const
   { return Array<octave_idx_type>::numel (); }
@@ -97,14 +99,14 @@
   }
 
   // These are, in fact, super-fast.
-  PermMatrix transpose (void) const;
-  PermMatrix inverse (void) const;
+  OCTAVE_API PermMatrix transpose (void) const;
+  OCTAVE_API PermMatrix inverse (void) const;
 
   // Determinant, i.e., the sign of permutation.
-  octave_idx_type determinant (void) const;
+  OCTAVE_API octave_idx_type determinant (void) const;
 
   // Efficient integer power of a permutation.
-  PermMatrix power (octave_idx_type n) const;
+  OCTAVE_API PermMatrix power (octave_idx_type n) const;
 
   bool is_col_perm (void) const { return true; }
   bool is_row_perm (void) const { return false; }
@@ -112,7 +114,7 @@
   void print_info (std::ostream& os, const std::string& prefix) const
   { Array<octave_idx_type>::print_info (os, prefix); }
 
-  static PermMatrix eye (octave_idx_type n);
+  static OCTAVE_API PermMatrix eye (octave_idx_type n);
 
 private:
 
@@ -120,12 +122,11 @@
 
   void setup (const Array<octave_idx_type>& p, bool colp, bool check);
 
-  void setup (const idx_vector& idx, bool colp, octave_idx_type n);
+  void setup (const octave::idx_vector& idx, bool colp, octave_idx_type n);
 };
 
 // Multiplying permutations together.
-PermMatrix
-OCTAVE_API
+OCTAVE_API PermMatrix
 operator * (const PermMatrix& a, const PermMatrix& b);
 
 #endif
--- a/liboctave/array/Range.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Range.cc	Sun May 16 09:44:35 2021 +0200
@@ -39,6 +39,317 @@
 #include "lo-mappers.h"
 #include "lo-utils.h"
 
+namespace octave
+{
+  template <typename T>
+  T xtfloor (T x, T ct)
+  {
+    // C---------FLOOR(X) is the largest integer algebraically less than
+    // C         or equal to X; that is, the unfuzzy FLOOR function.
+
+    //  DINT (X) = X - DMOD (X, 1.0);
+    //  FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0);
+
+    // C---------Hagerty's FL5 function follows...
+
+    T q = 1;
+
+    if (x < 0)
+      q = 1 - ct;
+
+    T rmax = q / (2 - ct);
+
+    T t1 = 1 + std::floor (x);
+    t1 = (ct / q) * (t1 < 0 ? -t1 : t1);
+    t1 = (rmax < t1 ? rmax : t1);
+    t1 = (ct > t1 ? ct : t1);
+    t1 = std::floor (x + t1);
+
+    if (x <= 0 || (t1 - x) < rmax)
+      return t1;
+    else
+      return t1 - 1;
+  }
+
+  template <typename T>
+  bool xteq (T u, T v, T ct = 3 * std::numeric_limits<T>::epsilon ())
+  {
+    T tu = std::abs (u);
+    T tv = std::abs (v);
+
+    return std::abs (u - v) < ((tu > tv ? tu : tv) * ct);
+  }
+
+  template <typename T>
+  octave_idx_type xnumel_internal (T base, T limit, T inc)
+  {
+    octave_idx_type retval = -1;
+    if (! math::isfinite (base) || ! math::isfinite (inc)
+        || math::isnan (limit))
+      retval = -2;
+    else if (math::isinf (limit)
+             && ((inc > 0 && limit > 0)
+                 || (inc < 0 && limit < 0)))
+      retval = std::numeric_limits<octave_idx_type>::max () - 1;
+    else if (inc == 0
+             || (limit > base && inc < 0)
+             || (limit < base && inc > 0))
+      {
+        retval = 0;
+      }
+    else
+      {
+        T ct = 3 * std::numeric_limits<T>::epsilon ();
+
+        T tmp = xtfloor ((limit - base + inc) / inc, ct);
+
+        octave_idx_type n_elt
+          = (tmp > 0 ? static_cast<octave_idx_type> (tmp) : 0);
+
+        // If the final element that we would compute for the range is
+        // equal to the limit of the range, or is an adjacent floating
+        // point number, accept it.  Otherwise, try a range with one
+        // fewer element.  If that fails, try again with one more
+        // element.
+        //
+        // I'm not sure this is very good, but it seems to work better
+        // than just using tfloor as above.  For example, without it,
+        // the expression 1.8:0.05:1.9 fails to produce the expected
+        // result of [1.8, 1.85, 1.9].
+
+        if (! xteq (base + (n_elt - 1) * inc, limit))
+          {
+            if (xteq (base + (n_elt - 2) * inc, limit))
+              n_elt--;
+            else if (xteq (base + n_elt * inc, limit))
+              n_elt++;
+          }
+
+        retval = (n_elt < std::numeric_limits<octave_idx_type>::max () - 1
+                  ? n_elt : -1);
+      }
+
+    return retval;
+  }
+
+  template <typename T>
+  bool xall_elements_are_ints (T base, T inc, T final_val, octave_idx_type nel)
+  {
+    // If the range is empty or NaN then there are no elements so there
+    // can be no int elements.
+    if (nel == 0 || math::isnan (final_val))
+      return false;
+
+    // If the base and increment are ints, all elements will be
+    // integers.
+    if (math::nint_big (base) == base && math::nint_big (inc) == inc)
+      return true;
+
+    // If the range has only one element, then the base needs to be an
+    // integer.
+    if (nel == 1 && math::nint_big (base))
+      return true;
+
+    return false;
+  }
+
+  template <typename T>
+  T
+  xfinal_value (T base, T limit, T inc, octave_idx_type nel)
+  {
+    T retval = T (0);
+
+    if (nel <= 1)
+      return base;
+
+    // If increment is 0, then numel should also be zero.
+
+    retval = base + (nel - 1) * inc;
+
+    // On some machines (x86 with extended precision floating point
+    // arithmetic, for example) it is possible that we can overshoot
+    // the limit by approximately the machine precision even though
+    // we were very careful in our calculation of the number of
+    // elements.  Therefore, we clip the result to the limit if it
+    // overshoots.
+
+    // NOTE: The test also includes equality (>= limit) to have
+    // expressions such as -5:1:-0 result in a -0 endpoint.
+
+    if ((inc > T (0) && retval >= limit) || (inc < T (0) && retval <= limit))
+      retval = limit;
+
+    // If all elements are integers, then ensure the final value is.
+    // Note that we pass the preliminary computed final value to
+    // xall_elements_are_ints, but it only checks whether that value is
+    // NaN.
+
+    if (xall_elements_are_ints (base, inc, retval, nel))
+      retval = std::round (retval);
+
+    return retval;
+  }
+
+  template <typename T>
+  void
+  xinit (T base, T limit, T inc, T& final_val, octave_idx_type& nel)
+  {
+    // Catch obvious NaN ranges.
+    if (math::isnan (base) || math::isnan (limit) || math::isnan (inc))
+      {
+        final_val = numeric_limits<T>::NaN ();
+        nel = 1;
+        return;
+      }
+
+    // Catch empty ranges.
+    if (inc == 0
+        || (limit < base && inc > 0)
+        || (limit > base && inc < 0))
+      {
+        nel = 0;
+        return;
+      }
+
+    // The following case also catches Inf values for increment when
+    // there will be only one element.
+
+    if ((limit <= base && base + inc < limit)
+        || (limit >= base && base + inc > limit))
+      {
+        final_val = base;
+        nel = 1;
+        return;
+      }
+
+    // Any other calculations with Inf will give us either a NaN range
+    // or an infinite nember of elements.
+
+    T dnel = (limit - base) / inc;
+    if (math::isnan (dnel))
+      {
+        nel = 1;
+        final_val = numeric_limits<T>::NaN ();
+        return;
+      }
+
+    if (dnel > 0 && math::isinf (dnel))
+      {
+        // FIXME: Should this be an immediate error?
+        nel = std::numeric_limits<octave_idx_type>::max ();
+
+        // FIXME: Will this do the right thing in all cases?
+        final_val = xfinal_value (base, limit, inc, nel);
+
+        return;
+      }
+
+    // Now that we have handled all the special cases, we can compute
+    // the number of elements and the final value in a way that attempts
+    // to avoid rounding errors as much as possible.
+
+    nel = xnumel_internal (base, limit, inc);
+    final_val = xfinal_value (base, limit, inc, nel);
+  }
+
+  template <typename T>
+  bool
+  xis_storable (T base, T limit, octave_idx_type nel)
+  {
+    return ! (nel > 1 && (math::isinf (base) || math::isinf (limit)));
+  }
+
+  template <>
+  bool
+  range<double>::all_elements_are_ints (void) const
+  {
+    return xall_elements_are_ints (m_base, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  bool
+  range<float>::all_elements_are_ints (void) const
+  {
+    return xall_elements_are_ints (m_base, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<double>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  void
+  range<float>::init (void)
+  {
+    return xinit (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  bool
+  range<double>::is_storable (void) const
+  {
+    return xis_storable (m_base, m_limit, m_numel);
+  }
+
+  template <>
+  bool
+  range<float>::is_storable (void) const
+  {
+    return xis_storable (m_base, m_limit, m_numel);
+  }
+
+  template <typename T>
+  octave_idx_type
+  xnnz (T base, T limit, T inc, T final_val, octave_idx_type nel)
+  {
+    // Note that the order of the following checks matters.
+
+    // If there are no elements, there can be no non-zero elements.
+    if (nel == 0)
+      return 0;
+
+    // All elements have the same sign, hence there are no zeros.
+    if ((base > 0 && limit > 0) || (base < 0 && limit < 0))
+      return nel;
+
+    // All elements are equal (inc = 0) but we know from the previous
+    // condition that they are not positive or negative, therefore all
+    // elements are zero.
+    if (inc == 0)
+      return 0;
+
+    // Exactly one zero at beginning or end of range.
+    if (base == 0 || final_val == 0)
+      return nel - 1;
+
+    // Range crosses negative/positive without hitting zero.
+    // FIXME: Is this test sufficiently tolerant or do we need to be
+    // more careful?
+    if (math::mod (-base, inc) != 0)
+      return nel;
+
+    // Range crosses negative/positive and hits zero.
+    return nel - 1;
+  }
+
+  template <>
+  octave_idx_type
+  range<double>::nnz (void) const
+  {
+    return xnnz (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+
+  template <>
+  octave_idx_type
+  range<float>::nnz (void) const
+  {
+    return xnnz (m_base, m_limit, m_increment, m_final, m_numel);
+  }
+}
+
 bool
 Range::all_elements_are_ints (void) const
 {
@@ -46,9 +357,9 @@
   // be an integer, even if the limit is not.  If there is one or fewer
   // elements only the base needs to be an integer.
 
-  return (! (octave::math::isnan (rng_base) || octave::math::isnan (rng_inc))
-          && (octave::math::nint_big (rng_base) == rng_base || rng_numel < 1)
-          && (octave::math::nint_big (rng_inc) == rng_inc || rng_numel <= 1));
+  return (! (octave::math::isnan (m_base) || octave::math::isnan (m_inc))
+          && (octave::math::nint_big (m_base) == m_base || m_numel < 1)
+          && (octave::math::nint_big (m_inc) == m_inc || m_numel <= 1));
 }
 
 octave_idx_type
@@ -58,27 +369,26 @@
 
   if (! isempty ())
     {
-      if ((rng_base > 0.0 && rng_limit > 0.0)
-          || (rng_base < 0.0 && rng_limit < 0.0))
+      if ((m_base > 0.0 && m_limit > 0.0) || (m_base < 0.0 && m_limit < 0.0))
         {
           // All elements have the same sign, hence there are no zeros.
-          retval = rng_numel;
+          retval = m_numel;
         }
-      else if (rng_inc != 0.0)
+      else if (m_inc != 0.0)
         {
-          if (rng_base == 0.0 || rng_limit == 0.0)
+          if (m_base == 0.0 || m_limit == 0.0)
             // Exactly one zero at beginning or end of range.
-            retval = rng_numel - 1;
-          else if ((rng_base / rng_inc) != std::floor (rng_base / rng_inc))
+            retval = m_numel - 1;
+          else if ((m_base / m_inc) != std::floor (m_base / m_inc))
             // Range crosses negative/positive without hitting zero.
-            retval = rng_numel;
+            retval = m_numel;
           else
             // Range crosses negative/positive and hits zero.
-            retval = rng_numel - 1;
+            retval = m_numel - 1;
         }
       else
         {
-          // All elements are equal (rng_inc = 0) but not positive or negative,
+          // All elements are equal (m_inc = 0) but not positive or negative,
           // therefore all elements are zero.
           retval = 0;
         }
@@ -90,37 +400,37 @@
 Matrix
 Range::matrix_value (void) const
 {
-  if (rng_numel > 0 && cache.isempty ())
+  Matrix retval (1, m_numel);
+
+  if (m_numel > 0)
     {
-      cache.resize (1, rng_numel);
-
       // The first element must always be *exactly* the base.
       // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
-      cache(0) = rng_base;
+      retval(0) = m_base;
 
-      double b = rng_base;
-      double increment = rng_inc;
-      for (octave_idx_type i = 1; i < rng_numel - 1; i++)
-        cache.xelem (i) = b + i * increment;
+      double b = m_base;
+      double increment = m_inc;
+      for (octave_idx_type i = 1; i < m_numel - 1; i++)
+        retval.xelem (i) = b + i * increment;
 
-      cache.xelem (rng_numel - 1) = rng_limit;
+      retval.xelem (m_numel - 1) = m_limit;
     }
 
-  return cache;
+  return retval;
 }
 
 double
 Range::checkelem (octave_idx_type i) const
 {
-  if (i < 0 || i >= rng_numel)
-    octave::err_index_out_of_range (2, 2, i+1, rng_numel, dims ());
+  if (i < 0 || i >= m_numel)
+    octave::err_index_out_of_range (2, 2, i+1, m_numel, dims ());
 
   if (i == 0)
-    return rng_base;
-  else if (i < rng_numel - 1)
-    return rng_base + i * rng_inc;
+    return m_base;
+  else if (i < m_numel - 1)
+    return m_base + i * m_inc;
   else
-    return rng_limit;
+    return m_limit;
 }
 
 double
@@ -128,7 +438,7 @@
 {
   // Ranges are *always* row vectors.
   if (i != 0)
-    octave::err_index_out_of_range (1, 1, i+1, rng_numel, dims ());
+    octave::err_index_out_of_range (1, 1, i+1, m_numel, dims ());
 
   return checkelem (j);
 }
@@ -137,11 +447,11 @@
 Range::elem (octave_idx_type i) const
 {
   if (i == 0)
-    return rng_base;
-  else if (i < rng_numel - 1)
-    return rng_base + i * rng_inc;
+    return m_base;
+  else if (i < m_numel - 1)
+    return m_base + i * m_inc;
   else
-    return rng_limit;
+    return m_limit;
 }
 
 // Helper class used solely for idx_vector.loop () function call
@@ -169,15 +479,15 @@
 };
 
 Array<double>
-Range::index (const idx_vector& i) const
+Range::index (const octave::idx_vector& i) const
 {
   Array<double> retval;
 
-  octave_idx_type n = rng_numel;
+  octave_idx_type n = m_numel;
 
   if (i.is_colon ())
     {
-      retval = matrix_value ().reshape (dim_vector (rng_numel, 1));
+      retval = matrix_value ().reshape (dim_vector (m_numel, 1));
     }
   else
     {
@@ -196,7 +506,7 @@
       // idx_vector loop across all values in i,
       // executing __rangeidx_helper (i) for each i
       i.loop (n, __rangeidx_helper (retval.fortran_vec (),
-                                    rng_base, rng_inc, rng_limit, rng_numel));
+                                    m_base, m_inc, m_limit, m_numel));
     }
 
   return retval;
@@ -209,17 +519,17 @@
 Range::min (void) const
 {
   double retval = 0.0;
-  if (rng_numel > 0)
+  if (m_numel > 0)
     {
-      if (rng_inc > 0)
-        retval = rng_base;
+      if (m_inc > 0)
+        retval = m_base;
       else
         {
-          retval = rng_base + (rng_numel - 1) * rng_inc;
+          retval = m_base + (m_numel - 1) * m_inc;
 
           // Require '<=' test.  See note in max ().
-          if (retval <= rng_limit)
-            retval = rng_limit;
+          if (retval <= m_limit)
+            retval = m_limit;
         }
 
     }
@@ -230,24 +540,24 @@
 Range::max (void) const
 {
   double retval = 0.0;
-  if (rng_numel > 0)
+  if (m_numel > 0)
     {
-      if (rng_inc > 0)
+      if (m_inc > 0)
         {
-          retval = rng_base + (rng_numel - 1) * rng_inc;
+          retval = m_base + (m_numel - 1) * m_inc;
 
           // On some machines (x86 with extended precision floating point
           // arithmetic, for example) it is possible that we can overshoot the
           // limit by approximately the machine precision even though we were
           // very careful in our calculation of the number of elements.
           // Therefore, we clip the result to the limit if it overshoots.
-          // The test also includes equality (>= rng_limit) to have expressions
+          // The test also includes equality (>= m_limit) to have expressions
           // such as -5:1:-0 result in a -0 endpoint.
-          if (retval >= rng_limit)
-            retval = rng_limit;
+          if (retval >= m_limit)
+            retval = m_limit;
         }
       else
-        retval = rng_base;
+        retval = m_base;
     }
   return retval;
 }
@@ -255,12 +565,11 @@
 void
 Range::sort_internal (bool ascending)
 {
-  if ((ascending && rng_base > rng_limit && rng_inc < 0.0)
-      || (! ascending && rng_base < rng_limit && rng_inc > 0.0))
+  if ((ascending && m_base > m_limit && m_inc < 0.0)
+      || (! ascending && m_base < m_limit && m_inc > 0.0))
     {
-      std::swap (rng_base, rng_limit);
-      rng_inc = -rng_inc;
-      clear_cache ();
+      std::swap (m_base, m_limit);
+      m_inc = -m_inc;
     }
 }
 
@@ -275,12 +584,11 @@
 
   bool reverse = false;
 
-  if ((ascending && rng_base > rng_limit && rng_inc < 0.0)
-      || (! ascending && rng_base < rng_limit && rng_inc > 0.0))
+  if ((ascending && m_base > m_limit && m_inc < 0.0)
+      || (! ascending && m_base < m_limit && m_inc > 0.0))
     {
-      std::swap (rng_base, rng_limit);
-      rng_inc = -rng_inc;
-      clear_cache ();
+      std::swap (m_base, m_limit);
+      m_inc = -m_inc;
       reverse = true;
     }
 
@@ -337,9 +645,9 @@
 sortmode
 Range::issorted (sortmode mode) const
 {
-  if (rng_numel > 1 && rng_inc > 0)
+  if (m_numel > 1 && m_inc > 0)
     mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
-  else if (rng_numel > 1 && rng_inc < 0)
+  else if (m_numel > 1 && m_inc < 0)
     mode = (mode == ASCENDING) ? UNSORTED : DESCENDING;
   else
     mode = (mode == UNSORTED) ? ASCENDING : mode;
@@ -350,9 +658,9 @@
 void
 Range::set_base (double b)
 {
-  if (rng_base != b)
+  if (m_base != b)
     {
-      rng_base = b;
+      m_base = b;
 
       init ();
     }
@@ -361,9 +669,9 @@
 void
 Range::set_limit (double l)
 {
-  if (rng_limit != l)
+  if (m_limit != l)
     {
-      rng_limit = l;
+      m_limit = l;
 
       init ();
     }
@@ -372,9 +680,9 @@
 void
 Range::set_inc (double i)
 {
-  if (rng_inc != i)
+  if (m_inc != i)
     {
-      rng_inc = i;
+      m_inc = i;
 
       init ();
     }
@@ -384,7 +692,7 @@
 operator << (std::ostream& os, const Range& a)
 {
   double b = a.base ();
-  double increment = a.inc ();
+  double increment = a.increment ();
   octave_idx_type nel = a.numel ();
 
   if (nel > 1)
@@ -396,7 +704,7 @@
     }
 
   // Print out the last element exactly, rather than a calculated last element.
-  os << a.rng_limit << "\n";
+  os << a.m_limit << "\n";
 
   return os;
 }
@@ -404,17 +712,17 @@
 std::istream&
 operator >> (std::istream& is, Range& a)
 {
-  is >> a.rng_base;
+  is >> a.m_base;
   if (is)
     {
-      double tmp_rng_limit;
-      is >> tmp_rng_limit;
+      double tmp_limit;
+      is >> tmp_limit;
 
       if (is)
-        is >> a.rng_inc;
+        is >> a.m_inc;
 
-      // Clip the rng_limit to the true limit, rebuild numel, clear cache
-      a.set_limit (tmp_rng_limit);
+      // Clip the m_limit to the true limit, rebuild numel, clear cache
+      a.set_limit (tmp_limit);
     }
 
   return is;
@@ -423,64 +731,37 @@
 Range
 operator - (const Range& r)
 {
-  return Range (-r.base (), -r.limit (), -r.inc (), r.numel ());
+  return Range (-r.base (), -r.limit (), -r.increment (), r.numel ());
 }
 
 Range operator + (double x, const Range& r)
 {
-  Range result (x + r.base (), x + r.limit (), r.inc (), r.numel ());
-  // Check whether new range was constructed properly.  A non-finite
-  // value (Inf or NaN) requires that the output be of the same size
-  // as the original range with all values set to the non-finite value.
-  if (result.rng_numel < 0)
-    result.cache = x + r.matrix_value ();
-
-  return result;
+  return Range (x + r.base (), x + r.limit (), r.increment (), r.numel ());
 }
 
 Range operator + (const Range& r, double x)
 {
-  Range result (r.base () + x, r.limit () + x, r.inc (), r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = r.matrix_value () + x;
-
-  return result;
+  return Range (r.base () + x, r.limit () + x, r.increment (), r.numel ());
 }
 
 Range operator - (double x, const Range& r)
 {
-  Range result (x - r.base (), x - r.limit (), -r.inc (), r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = x - r.matrix_value ();
-
-  return result;
+  return Range (x - r.base (), x - r.limit (), -r.increment (), r.numel ());
 }
 
 Range operator - (const Range& r, double x)
 {
-  Range result (r.base () - x, r.limit () - x, r.inc (), r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = r.matrix_value () - x;
-
-  return result;
+  return Range (r.base () - x, r.limit () - x, r.increment (), r.numel ());
 }
 
 Range operator * (double x, const Range& r)
 {
-  Range result (x * r.base (), x * r.limit (), x * r.inc (), r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = x * r.matrix_value ();
-
-  return result;
+  return Range (x * r.base (), x * r.limit (), x * r.increment (), r.numel ());
 }
 
 Range operator * (const Range& r, double x)
 {
-  Range result (r.base () * x, r.limit () * x, r.inc () * x, r.numel ());
-  if (result.rng_numel < 0)
-    result.cache = r.matrix_value () * x;
-
-  return result;
+  return Range (r.base () * x, r.limit () * x, r.increment () * x, r.numel ());
 }
 
 // C  See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5.
@@ -560,9 +841,16 @@
 {
   octave_idx_type retval = -1;
 
-  if (rng_inc == 0
-      || (rng_limit > rng_base && rng_inc < 0)
-      || (rng_limit < rng_base && rng_inc > 0))
+  if (! octave::math::isfinite (m_base) || ! octave::math::isfinite (m_inc)
+      || octave::math::isnan (m_limit))
+    retval = -2;
+  else if (octave::math::isinf (m_limit)
+           && ((m_inc > 0 && m_limit > 0)
+               || (m_inc < 0 && m_limit < 0)))
+    retval = std::numeric_limits<octave_idx_type>::max () - 1;
+  else if (m_inc == 0
+           || (m_limit > m_base && m_inc < 0)
+           || (m_limit < m_base && m_inc > 0))
     {
       retval = 0;
     }
@@ -570,10 +858,10 @@
     {
       double ct = 3.0 * std::numeric_limits<double>::epsilon ();
 
-      double tmp = tfloor ((rng_limit - rng_base + rng_inc) / rng_inc, ct);
+      double tmp = tfloor ((m_limit - m_base + m_inc) / m_inc, ct);
 
-      octave_idx_type n_elt = (tmp > 0.0 ? static_cast<octave_idx_type> (tmp)
-                                         : 0);
+      octave_idx_type n_elt = (tmp > 0.0
+                               ? static_cast<octave_idx_type> (tmp) : 0);
 
       // If the final element that we would compute for the range is equal to
       // the limit of the range, or is an adjacent floating point number,
@@ -584,16 +872,16 @@
       // using tfloor as above.  For example, without it, the expression
       // 1.8:0.05:1.9 fails to produce the expected result of [1.8, 1.85, 1.9].
 
-      if (! teq (rng_base + (n_elt - 1) * rng_inc, rng_limit))
+      if (! teq (m_base + (n_elt - 1) * m_inc, m_limit))
         {
-          if (teq (rng_base + (n_elt - 2) * rng_inc, rng_limit))
+          if (teq (m_base + (n_elt - 2) * m_inc, m_limit))
             n_elt--;
-          else if (teq (rng_base + n_elt * rng_inc, rng_limit))
+          else if (teq (m_base + n_elt * m_inc, m_limit))
             n_elt++;
         }
 
-      retval = (n_elt < std::numeric_limits<octave_idx_type>::max () - 1)
-               ? n_elt : -1;
+      retval = ((n_elt < std::numeric_limits<octave_idx_type>::max ())
+                ? n_elt : -1);
     }
 
   return retval;
@@ -602,12 +890,7 @@
 double
 Range::limit_internal (void) const
 {
-  double new_limit;
-
-  if (rng_inc > 0)
-    new_limit = max ();
-  else
-    new_limit = min ();
+  double new_limit = m_inc > 0 ? max () : min ();
 
   // If result must be an integer then force the new_limit to be one.
   if (all_elements_are_ints ())
@@ -619,8 +902,8 @@
 void
 Range::init (void)
 {
-  rng_numel = numel_internal ();
-  rng_limit = limit_internal ();
+  m_numel = numel_internal ();
 
-  clear_cache ();
+  if (! octave::math::isinf (m_limit))
+    m_limit = limit_internal ();
 }
--- a/liboctave/array/Range.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Range.h	Sun May 16 09:44:35 2021 +0200
@@ -32,16 +32,364 @@
 
 #include "dMatrix.h"
 #include "dim-vector.h"
+#include "lo-error.h"
 #include "oct-sort.h"
 
+template <typename T> class Array;
+
+namespace octave
+{
+  // Helper class used solely for idx_vector.loop () function call
+
+  template <typename T>
+  class rangeidx_helper
+  {
+  public:
+
+    rangeidx_helper (T *array, T base, T increment, T final_value,
+                     octave_idx_type numel)
+      : m_array (array), m_base (base), m_increment (increment),
+        m_final (final_value),
+        m_nmax (numel-1)
+    { }
+
+    void operator () (octave_idx_type i)
+    {
+      if (i == 0)
+        // Required for proper NaN handling.
+        *m_array++ = m_nmax == 0 ? m_final : m_base;
+      else if (i < m_nmax)
+        *m_array++ = m_base + T (i) * m_increment;
+      else
+        *m_array++ = m_final;
+    }
+
+  private:
+
+    T *m_array, m_base, m_increment, m_final;
+    octave_idx_type m_nmax;
+
+  };
+
+  template <typename T>
+  class
+  OCTAVE_API
+  range
+  {
+  public:
+
+    range (void)
+      : m_base (0), m_increment (0), m_limit (0), m_final (0), m_numel (0)
+    { }
+
+    // LIMIT is an upper limit and may be outside the range of actual
+    // values.  For floating point ranges, we perform a tolerant check
+    // to attempt to capture limit in the set of values if it is "close"
+    // to the value of base + a multiple of the increment.
+
+    range (const T& base, const T& increment, const T& limit)
+      : m_base (base), m_increment (increment), m_limit (limit),
+        m_final (), m_numel ()
+    {
+      init ();
+    }
+
+    range (const T& base, const T& limit)
+      : m_base (base), m_increment (1), m_limit (limit), m_final (), m_numel ()
+    {
+      init ();
+    }
+
+    // Allow conversion from (presumably) properly constructed Range
+    // objects and to create constant ranges (see the static
+    // make_constant method).  The values of base, limit, increment,
+    // and numel must be consistent.
+
+    // FIXME: Actually check that base, limit, increment, and numel are
+    // consistent.
+
+    // FIXME: Is there a way to limit this to T == double?
+
+    range (const T& base, const T& increment, const T& limit,
+           octave_idx_type numel)
+      : m_base (base), m_increment (increment), m_limit (limit),
+        m_final (limit), m_numel (numel)
+    { }
+
+    range (const T& base, const T& increment, const T& limit,
+           const T& final, octave_idx_type numel)
+      : m_base (base), m_increment (increment), m_limit (limit),
+        m_final (final), m_numel (numel)
+    { }
+
+    // We don't use a constructor for this because it will conflict with
+    // range<T> (base, limit) when T is octave_idx_type.
+
+    static range<T> make_constant (const T& base, octave_idx_type numel)
+    {
+      // We could just make this constructor public, but it allows
+      // inconsistent ranges to be constructed.  And it is probably much
+      // clearer to see "make_constant" instead of puzzling over the
+      // purpose of this strange constructor form.
+
+      return range<T> (base, T (), base, numel);
+    }
+
+    // We don't use a constructor for this because it will conflict with
+    // range<T> (base, limit, increment) when T is octave_idx_type.
+
+    static range<T> make_n_element_range (const T& base, const T& increment,
+                                          octave_idx_type numel)
+    {
+      // We could just make this constructor public, but it allows
+      // inconsistent ranges to be constructed.  And it is probably much
+      // clearer to see "make_constant" instead of puzzling over the
+      // purpose of this strange constructor form.
+
+      T final_val = base + (numel - 1) * increment;
+
+      return range<T> (base, increment, final_val, numel);
+    }
+
+    range (const range<T>&) = default;
+
+    range<T>& operator = (const range<T>&) = default;
+
+    ~range (void) = default;
+
+    T base (void) const { return m_base; }
+    T increment (void) const { return m_increment; }
+    T limit (void) const { return m_limit; }
+
+    T final_value (void) const { return m_final; }
+
+    T min (void) const
+    {
+      return (m_numel > 0
+              ? m_increment > T (0) ? base () : final_value ()
+              : T (0));
+    }
+
+    T max (void) const
+    {
+      return (m_numel > 0
+              ? m_increment > T (0) ? final_value () : base ()
+              : T (0));
+    }
+
+    octave_idx_type numel (void) const { return m_numel; }
+
+    // To support things like "for i = 1:Inf; ...; end" that are
+    // required for Matlab compatibility, creation of a range object
+    // like 1:Inf is allowed with m_numel set to
+    // numeric_limits<octave_idx_type>::max().  However, it is not
+    // possible to store these ranges.  The following function allows
+    // us to easily distinguish ranges with an infinite number of
+    // elements.  There are specializations for double and float.
+
+    bool is_storable (void) const { return true; }
+
+    dim_vector dims (void) const { return dim_vector (1, m_numel); }
+
+    octave_idx_type rows (void) const { return 1; }
+
+    octave_idx_type cols (void) const { return numel (); }
+    octave_idx_type columns (void) const { return numel (); }
+
+    bool isempty (void) const { return numel () == 0; }
+
+    bool all_elements_are_ints (void) const { return true; }
+
+    sortmode issorted (sortmode mode = ASCENDING) const
+    {
+      if (m_numel > 1 && m_increment > T (0))
+        mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
+      else if (m_numel > 1 && m_increment < T (0))
+        mode = (mode == ASCENDING) ? UNSORTED : DESCENDING;
+      else
+        mode = (mode == UNSORTED) ? ASCENDING : mode;
+
+      return mode;
+    }
+
+    OCTAVE_API octave_idx_type nnz (void) const;
+
+    // Support for single-index subscripting, without generating matrix cache.
+
+    T checkelem (octave_idx_type i) const
+    {
+      if (i < 0 || i >= m_numel)
+        err_index_out_of_range (2, 2, i+1, m_numel, dims ());
+
+      if (i == 0)
+        // Required for proper NaN handling.
+        return m_numel == 1 ? final_value () : m_base;
+      else if (i < m_numel - 1)
+        return m_base + T (i) * m_increment;
+      else
+        return final_value ();
+    }
+
+    T checkelem (octave_idx_type i, octave_idx_type j) const
+    {
+      // Ranges are *always* row vectors.
+      if (i != 0)
+        err_index_out_of_range (1, 1, i+1, m_numel, dims ());
+
+      return checkelem (j);
+    }
+
+    T elem (octave_idx_type i) const
+    {
+      if (i == 0)
+        // Required for proper NaN handling.
+        return m_numel == 1 ? final_value () : m_base;
+      else if (i < m_numel - 1)
+        return m_base + T (i) * m_increment;
+      else
+        return final_value ();
+    }
+
+    T elem (octave_idx_type /* i */, octave_idx_type j) const
+    {
+      return elem (j);
+    }
+
+    T operator () (octave_idx_type i) const
+    {
+      return elem (i);
+    }
+
+    T operator () (octave_idx_type i, octave_idx_type j) const
+    {
+      return elem (i, j);
+    }
+
+    Array<T> index (const idx_vector& i) const
+    {
+      Array<T> retval;
+
+      octave_idx_type n = m_numel;
+
+      if (i.is_colon ())
+        {
+          retval = array_value ().reshape (dim_vector (m_numel, 1));
+        }
+      else
+        {
+          if (i.extent (n) != n)
+            err_index_out_of_range (1, 1, i.extent (n), n, dims ());
+
+          dim_vector rd = i.orig_dimensions ();
+          octave_idx_type il = i.length (n);
+
+          // taken from Array.cc.
+          if (n != 1 && rd.isvector ())
+            rd = dim_vector (1, il);
+
+          retval.clear (rd);
+
+          // idx_vector loop across all values in i,
+          // executing __rangeidx_helper (i) for each i
+          i.loop (n, rangeidx_helper<T> (retval.fortran_vec (),
+                                         m_base, m_increment, final_value (),
+                                         m_numel));
+        }
+
+      return retval;
+    }
+
+    Array<T> diag (octave_idx_type k) const
+    {
+      return array_value ().diag (k);
+    }
+
+    Array<T> array_value (void) const
+    {
+      octave_idx_type nel = numel ();
+
+      Array<T> retval (dim_vector (1, nel));
+
+      if (nel == 1)
+        // Required for proper NaN handling.
+        retval(0) = final_value ();
+      else if (nel > 1)
+        {
+          // The first element must always be *exactly* the base.
+          // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
+          retval(0) = m_base;
+
+          for (octave_idx_type i = 1; i < nel - 1; i++)
+            retval.xelem (i) = m_base + i * m_increment;
+
+          retval.xelem (nel - 1) = final_value ();
+        }
+
+      return retval;
+    }
+
+  private:
+
+    T m_base;
+    T m_increment;
+    T m_limit;
+    T m_final;
+    octave_idx_type m_numel;
+
+    // Setting the number of elements to zero when the increment is zero
+    // is intentional and matches the behavior of Matlab's colon
+    // operator.
+
+    // These calculations are appropriate for integer ranges.  There are
+    // specializations for double and float.
+
+    void init (void)
+    {
+      m_numel = ((m_increment == T (0)
+                  || (m_limit > m_base && m_increment < T (0))
+                  || (m_limit < m_base && m_increment > T (0)))
+                 ? T (0)
+                 : (m_limit - m_base + m_increment) / m_increment);
+
+      m_final = m_base + (m_numel - 1) * m_increment;
+    }
+  };
+
+  // Specializations defined externally.
+
+  template <> OCTAVE_API bool range<double>::all_elements_are_ints (void) const;
+  template <> OCTAVE_API bool range<float>::all_elements_are_ints (void) const;
+
+  template <> OCTAVE_API void range<double>::init (void);
+  template <> OCTAVE_API void range<float>::init (void);
+
+  template <> OCTAVE_API bool range<double>::is_storable (void) const;
+  template <> OCTAVE_API bool range<float>::is_storable (void) const;
+
+  template <> OCTAVE_API octave_idx_type range<double>::nnz (void) const;
+  template <> OCTAVE_API octave_idx_type range<float>::nnz (void) const;
+}
+
 class
-OCTAVE_API
 Range
 {
 public:
 
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (void)
-    : rng_base (0), rng_limit (0), rng_inc (0), rng_numel (0), cache (1, 0) { }
+    : m_base (0), m_limit (0), m_inc (0), m_numel (0)
+  { }
+
+  // Assume range is already properly constructed, so just copy internal
+  // values.  However, we set LIMIT to the computed final value because
+  // that mimics the behavior of the other Range class constructors that
+  // reset limit to the computed final value.
+
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
+  Range (const octave::range<double>& r)
+    : m_base (r.base ()), m_limit (r.final_value ()), m_inc (r.increment ()),
+      m_numel (r.numel ())
+  { }
 
   Range (const Range& r) = default;
 
@@ -49,44 +397,60 @@
 
   ~Range (void) = default;
 
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (double b, double l)
-    : rng_base (b), rng_limit (l), rng_inc (1),
-      rng_numel (numel_internal ()), cache ()
+    : m_base (b), m_limit (l), m_inc (1), m_numel (numel_internal ())
   {
-    rng_limit = limit_internal ();
+    if (! octave::math::isinf (m_limit))
+      m_limit = limit_internal ();
   }
 
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (double b, double l, double i)
-    : rng_base (b), rng_limit (l), rng_inc (i),
-      rng_numel (numel_internal ()), cache ()
+    : m_base (b), m_limit (l), m_inc (i), m_numel (numel_internal ())
   {
-    rng_limit = limit_internal ();
+    if (! octave::math::isinf (m_limit))
+      m_limit = limit_internal ();
   }
 
-  // For operators' usage (to preserve element count).
+  // NOTE: The following constructor may be deprecated and removed after
+  // the arithmetic operators are removed.
+
+  // For operators' usage (to preserve element count) and to create
+  // constant row vectors (obsolete usage).
+
+  OCTAVE_DEPRECATED (7, "use the 'octave::range<double>' class instead")
   Range (double b, double i, octave_idx_type n)
-    : rng_base (b), rng_limit (b + (n-1) * i), rng_inc (i),
-      rng_numel (n), cache ()
+    : m_base (b), m_limit (b + (n-1) * i), m_inc (i), m_numel (n)
   {
-    if (! octave::math::isfinite (b) || ! octave::math::isfinite (i)
-        || ! octave::math::isfinite (rng_limit))
-      rng_numel = -2;
-    else
-      {
-        // Code below is only needed if the resulting range must be 100%
-        // correctly constructed.  If the Range object created is only
-        // a temporary one used by operators this may be unnecessary.
-        rng_limit = limit_internal ();
-      }
+    if (! octave::math::isinf (m_limit))
+      m_limit = limit_internal ();
   }
 
-  double base (void) const { return rng_base; }
-  double limit (void) const { return rng_limit; }
-  double inc (void) const { return rng_inc; }
+  // The range has a finite number of elements.
+  bool ok (void) const
+  {
+    return (octave::math::isfinite (m_limit)
+            && (m_numel >= 0 || m_numel == -2));
+  }
+
+  double base (void) const { return m_base; }
+  double limit (void) const { return m_limit; }
+  double inc (void) const { return m_inc; }
+  double increment (void) const { return m_inc; }
 
-  octave_idx_type numel (void) const { return rng_numel; }
+  // We adjust the limit to be the final value, so return that.  We
+  // could introduce a new variable to store the final value separately,
+  // but it seems like that would just add confusion.  If we changed
+  // the meaning of the limit function, we would change the behavior of
+  // programs that expect limit to be the final value instead of the
+  // value of the limit when the range was created.  This problem will
+  // be fixed with the new template range class.
+  double final_value (void) const { return m_limit; }
 
-  dim_vector dims (void) const { return dim_vector (1, rng_numel); }
+  octave_idx_type numel (void) const { return m_numel; }
+
+  dim_vector dims (void) const { return dim_vector (1, m_numel); }
 
   octave_idx_type rows (void) const { return 1; }
 
@@ -95,32 +459,32 @@
 
   bool isempty (void) const { return numel () == 0; }
 
-  bool all_elements_are_ints (void) const;
+  OCTAVE_API bool all_elements_are_ints (void) const;
 
-  Matrix matrix_value (void) const;
+  OCTAVE_API Matrix matrix_value (void) const;
 
-  double min (void) const;
-  double max (void) const;
+  OCTAVE_API double min (void) const;
+  OCTAVE_API double max (void) const;
 
-  void sort_internal (bool ascending = true);
-  void sort_internal (Array<octave_idx_type>& sidx, bool ascending = true);
+  OCTAVE_API void sort_internal (bool ascending = true);
+  OCTAVE_API void sort_internal (Array<octave_idx_type>& sidx, bool ascending = true);
 
-  Matrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API Matrix diag (octave_idx_type k = 0) const;
 
-  Range sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const;
-  Range sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
+  OCTAVE_API Range sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const;
+  OCTAVE_API Range sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
               sortmode mode = ASCENDING) const;
 
-  sortmode issorted (sortmode mode = ASCENDING) const;
+  OCTAVE_API sortmode issorted (sortmode mode = ASCENDING) const;
 
-  octave_idx_type nnz (void) const;
+  OCTAVE_API octave_idx_type nnz (void) const;
 
   // Support for single-index subscripting, without generating matrix cache.
 
-  double checkelem (octave_idx_type i) const;
-  double checkelem (octave_idx_type i, octave_idx_type j) const;
+  OCTAVE_API double checkelem (octave_idx_type i) const;
+  OCTAVE_API double checkelem (octave_idx_type i, octave_idx_type j) const;
 
-  double elem (octave_idx_type i) const;
+  OCTAVE_API double elem (octave_idx_type i) const;
   double elem (octave_idx_type /* i */, octave_idx_type j) const
   { return elem (j); }
 
@@ -128,13 +492,13 @@
   double operator () (octave_idx_type i, octave_idx_type j) const
   { return elem (i, j); }
 
-  Array<double> index (const idx_vector& i) const;
+  OCTAVE_API Array<double> index (const octave::idx_vector& i) const;
 
-  void set_base (double b);
+  OCTAVE_API void set_base (double b);
 
-  void set_limit (double l);
+  OCTAVE_API void set_limit (double l);
 
-  void set_inc (double i);
+  OCTAVE_API void set_inc (double i);
 
   friend OCTAVE_API std::ostream& operator << (std::ostream& os,
                                                const Range& r);
@@ -150,41 +514,48 @@
 
 private:
 
-  double rng_base;
-  double rng_limit;
-  double rng_inc;
+  double m_base;
+  double m_limit;
+  double m_inc;
 
-  octave_idx_type rng_numel;
-
-  mutable Matrix cache;
+  octave_idx_type m_numel;
 
-  octave_idx_type numel_internal (void) const;
-
-  double limit_internal (void) const;
+  OCTAVE_API octave_idx_type numel_internal (void) const;
 
-  void init (void);
+  OCTAVE_API double limit_internal (void) const;
 
-  void clear_cache (void) const { cache.resize (0, 0); }
+  OCTAVE_API void init (void);
 
 protected:
 
+  // NOTE: The following constructor may be removed when the arithmetic
+  // operators are removed.
+
   // For operators' usage (to allow all values to be set directly).
   Range (double b, double l, double i, octave_idx_type n)
-    : rng_base (b), rng_limit (l), rng_inc (i),
-      rng_numel (n), cache ()
-  {
-    if (! octave::math::isfinite (b) || ! octave::math::isfinite (i)
-        || ! octave::math::isfinite (l))
-      rng_numel = -2;
-  }
+    : m_base (b), m_limit (l), m_inc (i), m_numel (n)
+  { }
 };
 
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator - (const Range& r);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator + (double x, const Range& r);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator + (const Range& r, double x);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator - (double x, const Range& r);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator - (const Range& r, double x);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator * (double x, const Range& r);
+
+OCTAVE_DEPRECATED (7, "arithmetic operations on Range objects are unreliable")
 extern OCTAVE_API Range operator * (const Range& r, double x);
 
 #endif
--- a/liboctave/array/Sparse-C.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Sparse-C.cc	Sun May 16 09:44:35 2021 +0200
@@ -44,6 +44,7 @@
 }
 
 template <>
+OCTAVE_API
 bool
 sparse_ascending_compare<Complex> (const Complex& a, const Complex& b)
 {
@@ -52,6 +53,7 @@
 }
 
 template <>
+OCTAVE_API
 bool
 sparse_descending_compare<Complex> (const Complex& a, const Complex& b)
 {
@@ -59,7 +61,7 @@
           || ((xabs (a) == xabs (b)) && (arg (a) > arg (b))));
 }
 
-INSTANTIATE_SPARSE (Complex, OCTAVE_API);
+INSTANTIATE_SPARSE (Complex);
 
 #if 0
 template std::ostream& operator << (std::ostream&, const Sparse<Complex>&);
--- a/liboctave/array/Sparse-b.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Sparse-b.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,13 +33,14 @@
 #include "Sparse.cc"
 
 template <>
+OCTAVE_API
 bool
 Sparse<bool>::SparseRep::any_element_is_nan (void) const
 {
   return false;
 }
 
-INSTANTIATE_SPARSE (bool, OCTAVE_API);
+INSTANTIATE_SPARSE (bool);
 
 #if 0
 template std::ostream& operator << (std::ostream&, const Sparse<bool>&);
--- a/liboctave/array/Sparse-d.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Sparse-d.cc	Sun May 16 09:44:35 2021 +0200
@@ -34,6 +34,7 @@
 #include "Sparse.cc"
 
 template <>
+OCTAVE_API
 bool
 sparse_ascending_compare<double> (double a, double b)
 {
@@ -41,13 +42,14 @@
 }
 
 template <>
+OCTAVE_API
 bool
 sparse_descending_compare<double> (double a, double b)
 {
   return (octave::math::isnan (a) || (a > b));
 }
 
-INSTANTIATE_SPARSE (double, OCTAVE_API);
+INSTANTIATE_SPARSE (double);
 
 #if 0
 template std::ostream& operator << (std::ostream&, const Sparse<double>&);
--- a/liboctave/array/Sparse.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Sparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -54,7 +54,7 @@
 #include "PermMatrix.h"
 
 template <typename T>
-typename Sparse<T>::SparseRep *
+OCTAVE_API typename Sparse<T>::SparseRep *
 Sparse<T>::nil_rep (void)
 {
   static typename Sparse<T>::SparseRep nr;
@@ -62,6 +62,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 T&
 Sparse<T>::SparseRep::elem (octave_idx_type _r, octave_idx_type _c)
 {
@@ -103,6 +104,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 T
 Sparse<T>::SparseRep::celem (octave_idx_type _r, octave_idx_type _c) const
 {
@@ -114,6 +116,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
 Sparse<T>::SparseRep::maybe_compress (bool remove_zeros)
 {
@@ -138,6 +141,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
 Sparse<T>::SparseRep::change_length (octave_idx_type nz)
 {
@@ -171,6 +175,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 bool
 Sparse<T>::SparseRep::indices_ok (void) const
 {
@@ -178,6 +183,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 bool
 Sparse<T>::SparseRep::any_element_is_nan (void) const
 {
@@ -191,6 +197,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>::Sparse (octave_idx_type nr, octave_idx_type nc, T val)
   : rep (nullptr), dimensions (dim_vector (nr, nc))
 {
@@ -219,6 +226,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>::Sparse (const PermMatrix& a)
   : rep (new typename Sparse<T>::SparseRep (a.rows (), a.cols (), a.rows ())),
     dimensions (dim_vector (a.rows (), a.cols ()))
@@ -237,6 +245,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>::Sparse (const dim_vector& dv)
   : rep (nullptr), dimensions (dv)
 {
@@ -248,6 +257,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>::Sparse (const Sparse<T>& a, const dim_vector& dv)
   : rep (nullptr), dimensions (dv)
 {
@@ -290,8 +300,9 @@
 }
 
 template <typename T>
-Sparse<T>::Sparse (const Array<T>& a, const idx_vector& r,
-                   const idx_vector& c, octave_idx_type nr,
+OCTAVE_API
+Sparse<T>::Sparse (const Array<T>& a, const octave::idx_vector& r,
+                   const octave::idx_vector& c, octave_idx_type nr,
                    octave_idx_type nc, bool sum_terms,
                    octave_idx_type nzm)
   : rep (nullptr), dimensions ()
@@ -351,7 +362,7 @@
       else if (cl == 1)
         {
           // Sparse column vector.  Sort row indices.
-          idx_vector rs = r.sorted ();
+          octave::idx_vector rs = r.sorted ();
 
           octave_quit ();
 
@@ -405,8 +416,8 @@
         }
       else
         {
-          idx_vector rr = r;
-          idx_vector cc = c;
+          octave::idx_vector rr = r;
+          octave::idx_vector cc = c;
           const octave_idx_type *rd = rr.raw ();
           const octave_idx_type *cd = cc.raw ();
           OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, ci, nc+1, 0);
@@ -499,7 +510,7 @@
     {
       // Sparse column vector.  Sort row indices.
       Array<octave_idx_type> rsi;
-      idx_vector rs = r.sorted (rsi);
+      octave::idx_vector rs = r.sorted (rsi);
 
       octave_quit ();
 
@@ -552,8 +563,8 @@
     }
   else
     {
-      idx_vector rr = r;
-      idx_vector cc = c;
+      octave::idx_vector rr = r;
+      octave::idx_vector cc = c;
       const octave_idx_type *rd = rr.raw ();
       const octave_idx_type *cd = cc.raw ();
       OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, ci, nc+1, 0);
@@ -651,12 +662,13 @@
 }
 
 /*
-%!assert <51880> (sparse (1:2, 2, 1:2, 2, 2), sparse ([0, 1; 0, 2]))
-%!assert <51880> (sparse (1:2, 1, 1:2, 2, 2), sparse ([1, 0; 2, 0]))
-%!assert <51880> (sparse (1:2, 2, 1:2, 2, 3), sparse ([0, 1, 0; 0, 2, 0]))
+%!assert <*51880> (sparse (1:2, 2, 1:2, 2, 2), sparse ([0, 1; 0, 2]))
+%!assert <*51880> (sparse (1:2, 1, 1:2, 2, 2), sparse ([1, 0; 2, 0]))
+%!assert <*51880> (sparse (1:2, 2, 1:2, 2, 3), sparse ([0, 1, 0; 0, 2, 0]))
 */
 
 template <typename T>
+OCTAVE_API
 Sparse<T>::Sparse (const Array<T>& a)
   : rep (nullptr), dimensions (a.dims ())
 {
@@ -691,6 +703,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>::~Sparse (void)
 {
   if (--rep->count == 0)
@@ -716,6 +729,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 octave_idx_type
 Sparse<T>::compute_index (const Array<octave_idx_type>& ra_idx) const
 {
@@ -739,6 +753,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 T
 Sparse<T>::range_error (const char *fcn, octave_idx_type n) const
 {
@@ -747,6 +762,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 T&
 Sparse<T>::range_error (const char *fcn, octave_idx_type n)
 {
@@ -755,6 +771,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 T
 Sparse<T>::range_error (const char *fcn, octave_idx_type i,
                         octave_idx_type j) const
@@ -765,6 +782,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 T&
 Sparse<T>::range_error (const char *fcn, octave_idx_type i, octave_idx_type j)
 {
@@ -774,6 +792,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 T
 Sparse<T>::range_error (const char *fcn,
                         const Array<octave_idx_type>& ra_idx) const
@@ -798,6 +817,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 T&
 Sparse<T>::range_error (const char *fcn, const Array<octave_idx_type>& ra_idx)
 {
@@ -821,6 +841,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
 Sparse<T>::reshape (const dim_vector& new_dims) const
 {
@@ -900,6 +921,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
 Sparse<T>::permute (const Array<octave_idx_type>& perm_vec, bool) const
 {
@@ -928,6 +950,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
 Sparse<T>::resize1 (octave_idx_type n)
 {
@@ -947,6 +970,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
 Sparse<T>::resize (const dim_vector& dv)
 {
@@ -959,6 +983,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
 Sparse<T>::resize (octave_idx_type r, octave_idx_type c)
 {
@@ -1009,6 +1034,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>&
 Sparse<T>::insert (const Sparse<T>& a, octave_idx_type r, octave_idx_type c)
 {
@@ -1090,6 +1116,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>&
 Sparse<T>::insert (const Sparse<T>& a, const Array<octave_idx_type>& ra_idx)
 {
@@ -1101,6 +1128,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
 Sparse<T>::transpose (void) const
 {
@@ -1140,7 +1168,8 @@
 // Lower bound lookup.  Could also use octave_sort, but that has upper bound
 // semantics, so requires some manipulation to set right.  Uses a plain loop
 // for small columns.
-static octave_idx_type
+static
+octave_idx_type
 lblookup (const octave_idx_type *ridx, octave_idx_type nr,
           octave_idx_type ri)
 {
@@ -1157,8 +1186,9 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
-Sparse<T>::delete_elements (const idx_vector& idx)
+Sparse<T>::delete_elements (const octave::idx_vector& idx)
 {
   Sparse<T> retval;
 
@@ -1201,7 +1231,7 @@
         {
           OCTAVE_LOCAL_BUFFER (octave_idx_type, ridx_new, nz);
           OCTAVE_LOCAL_BUFFER (T, data_new, nz);
-          idx_vector sidx = idx.sorted (true);
+          octave::idx_vector sidx = idx.sorted (true);
           const octave_idx_type *sj = sidx.raw ();
           octave_idx_type sl = sidx.length (nel);
           octave_idx_type nz_new = 0;
@@ -1250,7 +1280,7 @@
         *this = Sparse<T> ();
       else
         {
-          *this = index (idx_vector::colon);
+          *this = index (octave::idx_vector::colon);
           delete_elements (idx);
           *this = transpose (); // We want a row vector.
         }
@@ -1258,8 +1288,9 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
-Sparse<T>::delete_elements (const idx_vector& idx_i, const idx_vector& idx_j)
+Sparse<T>::delete_elements (const octave::idx_vector& idx_i, const octave::idx_vector& idx_j)
 {
   assert (ndims () == 2);
 
@@ -1326,8 +1357,8 @@
           else
             {
               // This is more memory-efficient than the approach below.
-              const Sparse<T> tmpl = index (idx_vector (0, lb), idx_j);
-              const Sparse<T> tmpu = index (idx_vector (ub, nr), idx_j);
+              const Sparse<T> tmpl = index (octave::idx_vector (0, lb), idx_j);
+              const Sparse<T> tmpu = index (octave::idx_vector (ub, nr), idx_j);
               *this = Sparse<T> (nr - (ub - lb), nc,
                                  tmpl.nnz () + tmpu.nnz ());
               for (octave_idx_type j = 0, k = 0; j < nc; j++)
@@ -1377,20 +1408,22 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
-Sparse<T>::delete_elements (int dim, const idx_vector& idx)
+Sparse<T>::delete_elements (int dim, const octave::idx_vector& idx)
 {
   if (dim == 0)
-    delete_elements (idx, idx_vector::colon);
+    delete_elements (idx, octave::idx_vector::colon);
   else if (dim == 1)
-    delete_elements (idx_vector::colon, idx);
+    delete_elements (octave::idx_vector::colon, idx);
   else
     (*current_liboctave_error_handler) ("invalid dimension in delete_elements");
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
-Sparse<T>::index (const idx_vector& idx, bool resize_ok) const
+Sparse<T>::index (const octave::idx_vector& idx, bool resize_ok) const
 {
   Sparse<T> retval;
 
@@ -1577,7 +1610,7 @@
           // I suppose this is rare (and it may easily overflow), so let's take
           // the easy way, and reshape first to column vector, which is already
           // handled above.
-          retval = index (idx_vector::colon).index (idx);
+          retval = index (octave::idx_vector::colon).index (idx);
           // In this case we're supposed to always inherit the shape, but
           // column(row) doesn't do it, so we'll do it instead.
           if (idx_dims(0) == 1 && idx_dims(1) != 1)
@@ -1589,8 +1622,9 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
-Sparse<T>::index (const idx_vector& idx_i, const idx_vector& idx_j,
+Sparse<T>::index (const octave::idx_vector& idx_i, const octave::idx_vector& idx_j,
                   bool resize_ok) const
 {
   Sparse<T> retval;
@@ -1783,7 +1817,7 @@
       else
         {
           // Get inverse permutation.
-          idx_vector idx_iinv = idx_i.inverse_permutation (nr);
+          octave::idx_vector idx_iinv = idx_i.inverse_permutation (nr);
           const octave_idx_type *iinv = idx_iinv.raw ();
 
           // Scatter buffer.
@@ -1819,22 +1853,23 @@
       // so we rely on the efficient transpose to handle this.
       // It may still make sense to optimize some cases here.
       retval = transpose ();
-      retval = retval.index (idx_vector::colon, idx_i);
+      retval = retval.index (octave::idx_vector::colon, idx_i);
       retval = retval.transpose ();
     }
   else
     {
       // A(I, J) is decomposed into A(:, J)(I, :).
-      retval = index (idx_vector::colon, idx_j);
-      retval = retval.index (idx_i, idx_vector::colon);
+      retval = index (octave::idx_vector::colon, idx_j);
+      retval = retval.index (idx_i, octave::idx_vector::colon);
     }
 
   return retval;
 }
 
 template <typename T>
+OCTAVE_API
 void
-Sparse<T>::assign (const idx_vector& idx, const Sparse<T>& rhs)
+Sparse<T>::assign (const octave::idx_vector& idx, const Sparse<T>& rhs)
 {
   Sparse<T> retval;
 
@@ -1926,7 +1961,7 @@
           else if (idx.is_range () && idx.increment () == -1)
             {
               // It's s(u:-1:l) = r.  Reverse the assignment.
-              assign (idx.sorted (), rhs.index (idx_vector (rhl - 1, 0, -1)));
+              assign (idx.sorted (), rhs.index (octave::idx_vector (rhl - 1, 0, -1)));
             }
           else if (idx.is_permutation (n))
             {
@@ -1957,7 +1992,7 @@
               std::copy_n (tmp.data (), nz, new_data.fortran_vec ());
               // ... insert new data (densified) ...
               idx.copy_data (new_ri.fortran_vec () + nz);
-              new_data.assign (idx_vector (nz, new_nz), rhs.array_value ());
+              new_data.assign (octave::idx_vector (nz, new_nz), rhs.array_value ());
               // ... reassembly.
               *this = Sparse<T> (new_data, new_ri,
                                  static_cast<octave_idx_type> (0),
@@ -1967,8 +2002,8 @@
       else
         {
           dim_vector save_dims = dimensions;
-          *this = index (idx_vector::colon);
-          assign (idx, rhs.index (idx_vector::colon));
+          *this = index (octave::idx_vector::colon);
+          assign (idx, rhs.index (octave::idx_vector::colon));
           *this = reshape (save_dims);
         }
     }
@@ -1985,9 +2020,10 @@
 }
 
 template <typename T>
+OCTAVE_API
 void
-Sparse<T>::assign (const idx_vector& idx_i,
-                   const idx_vector& idx_j, const Sparse<T>& rhs)
+Sparse<T>::assign (const octave::idx_vector& idx_i,
+                   const octave::idx_vector& idx_j, const Sparse<T>& rhs)
 {
   Sparse<T> retval;
 
@@ -2120,7 +2156,7 @@
             {
               // It's s(:,u:-1:l) = r.  Reverse the assignment.
               assign (idx_i, idx_j.sorted (),
-                      rhs.index (idx_i, idx_vector (m - 1, 0, -1)));
+                      rhs.index (idx_i, octave::idx_vector (m - 1, 0, -1)));
             }
           else if (idx_j.is_permutation (nc))
             {
@@ -2191,16 +2227,16 @@
               // especially for many small columns.  OTOH, transpose is an
               // efficient O(nr+nc+nnz) operation.
               *this = transpose ();
-              assign (idx_vector::colon, idx_i, rhs.transpose ());
+              assign (octave::idx_vector::colon, idx_i, rhs.transpose ());
               *this = transpose ();
             }
         }
       else
         {
           // Split it into 2 assignments and one indexing.
-          Sparse<T> tmp = index (idx_vector::colon, idx_j);
-          tmp.assign (idx_i, idx_vector::colon, rhs);
-          assign (idx_vector::colon, idx_j, tmp);
+          Sparse<T> tmp = index (octave::idx_vector::colon, idx_j);
+          tmp.assign (idx_i, octave::idx_vector::colon, rhs);
+          assign (octave::idx_vector::colon, idx_j, tmp);
         }
     }
   else if (m == 1 && n == 1)
@@ -2224,6 +2260,7 @@
 // Can't use versions of these in Array.cc due to duplication of the
 // instantiations for Array<double and Sparse<double>, etc
 template <typename T>
+OCTAVE_API
 bool
 sparse_ascending_compare (typename ref_param<T>::type a,
                           typename ref_param<T>::type b)
@@ -2232,6 +2269,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 bool
 sparse_descending_compare (typename ref_param<T>::type a,
                            typename ref_param<T>::type b)
@@ -2240,6 +2278,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
 Sparse<T>::sort (octave_idx_type dim, sortmode mode) const
 {
@@ -2306,6 +2345,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
 Sparse<T>::sort (Array<octave_idx_type> &sidx, octave_idx_type dim,
                  sortmode mode) const
@@ -2413,6 +2453,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
 Sparse<T>::diag (octave_idx_type k) const
 {
@@ -2586,6 +2627,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Sparse<T>
 Sparse<T>::cat (int dim, octave_idx_type n, const Sparse<T> *sparse_list)
 {
@@ -2669,7 +2711,7 @@
               continue;
 
             octave_idx_type u = l + sparse_list[i].columns ();
-            retval.assign (idx_vector::colon, idx_vector (l, u),
+            retval.assign (octave::idx_vector::colon, octave::idx_vector (l, u),
                            sparse_list[i]);
             l = u;
           }
@@ -2684,6 +2726,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 Array<T>
 Sparse<T>::array_value () const
 {
@@ -2708,6 +2751,7 @@
 }
 
 template <typename T>
+OCTAVE_API
 std::istream&
 read_sparse_matrix (std::istream& is, Sparse<T>& a,
                     T (*read_fcn) (std::istream&))
@@ -2969,10 +3013,10 @@
 %!test test_sparse_slice ([2 2], 22, 3);
 %!test test_sparse_slice ([2 2], 22, 4);
 
-%!assert <35570> (speye (3,1)(3:-1:1), sparse ([0; 0; 1]))
+%!assert <*35570> (speye (3,1)(3:-1:1), sparse ([0; 0; 1]))
 
 ## Test removing columns
-%!test <36656>
+%!test <*36656>
 %! s = sparse (magic (5));
 %! s(:,2:4) = [];
 %! assert (s, sparse (magic (5)(:, [1,5])));
@@ -2983,21 +3027,21 @@
 %! assert (s, sparse ([], [], [], 0, 1));
 
 ## Test (bug #37321)
-%!test <37321> a=sparse (0,0); assert (all (a) == sparse ([1]));
-%!test <37321> a=sparse (0,1); assert (all (a) == sparse ([1]));
-%!test <37321> a=sparse (1,0); assert (all (a) == sparse ([1]));
-%!test <37321> a=sparse (1,0); assert (all (a,2) == sparse ([1]));
-%!test <37321> a=sparse (1,0); assert (size (all (a,1)), [1 0]);
-%!test <37321> a=sparse (1,1);
+%!test <*37321> a=sparse (0,0); assert (all (a) == sparse ([1]));
+%!test <*37321> a=sparse (0,1); assert (all (a) == sparse ([1]));
+%!test <*37321> a=sparse (1,0); assert (all (a) == sparse ([1]));
+%!test <*37321> a=sparse (1,0); assert (all (a,2) == sparse ([1]));
+%!test <*37321> a=sparse (1,0); assert (size (all (a,1)), [1 0]);
+%!test <*37321> a=sparse (1,1);
 %! assert (all (a) == sparse ([0]));
 %! assert (size (all (a)), [1 1]);
-%!test <37321> a=sparse (2,1);
+%!test <*37321> a=sparse (2,1);
 %! assert (all (a) == sparse ([0]));
 %! assert (size (all (a)), [1 1]);
-%!test <37321> a=sparse (1,2);
+%!test <*37321> a=sparse (1,2);
 %! assert (all (a) == sparse ([0]));
 %! assert (size (all (a)), [1 1]);
-%!test <37321> a=sparse (2,2); assert (isequal (all (a), sparse ([0 0])));
+%!test <*37321> a=sparse (2,2); assert (isequal (all (a), sparse ([0 0])));
 
 ## Test assigning row to a column slice
 %!test <45589>
@@ -3010,6 +3054,7 @@
 */
 
 template <typename T>
+OCTAVE_API
 void
 Sparse<T>::print_info (std::ostream& os, const std::string& prefix) const
 {
@@ -3023,8 +3068,16 @@
      << prefix << "rep->count:  " << rep->count << "\n";
 }
 
-#define INSTANTIATE_SPARSE(T, API)                                      \
-  template class API Sparse<T>;                                         \
-  template std::istream&                                                \
-  read_sparse_matrix<T> (std::istream& is, Sparse<T>& a,                \
-                         T (*read_fcn) (std::istream&));
+#if defined (__clang__)
+#  define INSTANTIATE_SPARSE(T)                                         \
+     template class OCTAVE_API Sparse<T>;                               \
+     template OCTAVE_API std::istream&                                  \
+     read_sparse_matrix<T> (std::istream& is, Sparse<T>& a,             \
+                            T (*read_fcn) (std::istream&));
+#else
+#  define INSTANTIATE_SPARSE(T)                                         \
+     template class Sparse<T>;                                          \
+     template OCTAVE_API std::istream&                                  \
+     read_sparse_matrix<T> (std::istream& is, Sparse<T>& a,             \
+                            T (*read_fcn) (std::istream&));
+#endif
--- a/liboctave/array/Sparse.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/Sparse.h	Sun May 16 09:44:35 2021 +0200
@@ -37,12 +37,14 @@
 
 #include "Array.h"
 
-class idx_vector;
 class PermMatrix;
 
 // Two dimensional sparse class.  Handles the reference counting for
 // all the derived classes.
 
+// forward declare template with visibility attribute
+template <typename T> class OCTAVE_API Sparse;
+
 template <typename T>
 class
 Sparse
@@ -56,7 +58,7 @@
   // The real representation of all Sparse arrays.
   //--------------------------------------------------------------------
 
-  class OCTAVE_API SparseRep
+  class SparseRep
   {
   public:
 
@@ -104,9 +106,9 @@
 
     octave_idx_type nnz (void) const { return c[ncols]; }
 
-    T& elem (octave_idx_type _r, octave_idx_type _c);
+    OCTAVE_API T& elem (octave_idx_type _r, octave_idx_type _c);
 
-    T celem (octave_idx_type _r, octave_idx_type _c) const;
+    OCTAVE_API T celem (octave_idx_type _r, octave_idx_type _c) const;
 
     T& data (octave_idx_type i) { return d[i]; }
 
@@ -120,19 +122,19 @@
 
     octave_idx_type ccidx (octave_idx_type i) const { return c[i]; }
 
-    void maybe_compress (bool remove_zeros);
+    OCTAVE_API void maybe_compress (bool remove_zeros);
 
-    void change_length (octave_idx_type nz);
+    OCTAVE_API void change_length (octave_idx_type nz);
 
-    bool indices_ok (void) const;
+    OCTAVE_API bool indices_ok (void) const;
 
-    bool any_element_is_nan (void) const;
+    OCTAVE_API bool any_element_is_nan (void) const;
 
   private:
 
     // No assignment!
 
-    SparseRep& operator = (const SparseRep& a);
+    OCTAVE_API SparseRep& operator = (const SparseRep& a);
   };
 
   //--------------------------------------------------------------------
@@ -161,7 +163,7 @@
 
 private:
 
-  static typename Sparse<T>::SparseRep *nil_rep (void);
+  static OCTAVE_API typename Sparse<T>::SparseRep *nil_rep (void);
 
 public:
 
@@ -179,7 +181,7 @@
     : rep (new typename Sparse<T>::SparseRep (nr, nc)),
       dimensions (dim_vector (nr, nc)) { }
 
-  explicit Sparse (octave_idx_type nr, octave_idx_type nc, T val);
+  explicit OCTAVE_API Sparse (octave_idx_type nr, octave_idx_type nc, T val);
 
   Sparse (const dim_vector& dv, octave_idx_type nz)
     : rep (new typename Sparse<T>::SparseRep (dv(0), dv(1), nz)),
@@ -191,7 +193,7 @@
 
   // Both SparseMatrix and SparseBoolMatrix need this ctor, and this
   // is their only common ancestor.
-  explicit Sparse (const PermMatrix& a);
+  explicit OCTAVE_API Sparse (const PermMatrix& a);
 
   // Type conversion case.  Preserves nzmax.
   template <typename U>
@@ -215,20 +217,21 @@
 
 public:
 
-  Sparse (const dim_vector& dv);
+  OCTAVE_API Sparse (const dim_vector& dv);
 
-  Sparse (const Sparse<T>& a, const dim_vector& dv);
+  OCTAVE_API Sparse (const Sparse<T>& a, const dim_vector& dv);
 
-  Sparse (const Array<T>& a, const idx_vector& r, const idx_vector& c,
+  OCTAVE_API
+  Sparse (const Array<T>& a, const octave::idx_vector& r, const octave::idx_vector& c,
           octave_idx_type nr = -1, octave_idx_type nc = -1,
           bool sum_terms = true, octave_idx_type nzm = -1);
 
   // Sparsify a normal matrix
-  Sparse (const Array<T>& a);
+  OCTAVE_API Sparse (const Array<T>& a);
 
   virtual ~Sparse (void);
 
-  Sparse<T>& operator = (const Sparse<T>& a);
+  OCTAVE_API Sparse<T>& operator = (const Sparse<T>& a);
 
   //! Amount of storage for nonzero elements.
   //! This may differ from the actual number of elements, see nnz().
@@ -271,22 +274,23 @@
 
   Sparse<T> squeeze (void) const { return *this; }
 
-  octave_idx_type compute_index (const Array<octave_idx_type>& ra_idx) const;
+  OCTAVE_API octave_idx_type
+  compute_index (const Array<octave_idx_type>& ra_idx) const;
 
-  // FIXME: Functions are marked as NORETURN, but they are used with
-  //        a return statement in following code.  Shouldn't that be fixed?
-  OCTAVE_NORETURN T range_error (const char *fcn, octave_idx_type n) const;
-  OCTAVE_NORETURN T& range_error (const char *fcn, octave_idx_type n);
+  OCTAVE_NORETURN OCTAVE_API T
+  range_error (const char *fcn, octave_idx_type n) const;
+  OCTAVE_NORETURN OCTAVE_API T&
+  range_error (const char *fcn, octave_idx_type n);
 
-  OCTAVE_NORETURN T range_error (const char *fcn,
-                                 octave_idx_type i, octave_idx_type j) const;
-  OCTAVE_NORETURN T& range_error (const char *fcn,
-                                  octave_idx_type i, octave_idx_type j);
+  OCTAVE_NORETURN OCTAVE_API T
+  range_error (const char *fcn, octave_idx_type i, octave_idx_type j) const;
+  OCTAVE_NORETURN OCTAVE_API T&
+  range_error (const char *fcn, octave_idx_type i, octave_idx_type j);
 
-  OCTAVE_NORETURN T range_error (const char *fcn,
-                                 const Array<octave_idx_type>& ra_idx) const;
-  OCTAVE_NORETURN T& range_error (const char *fcn,
-                                  const Array<octave_idx_type>& ra_idx);
+  OCTAVE_NORETURN OCTAVE_API T
+  range_error (const char *fcn, const Array<octave_idx_type>& ra_idx) const;
+  OCTAVE_NORETURN OCTAVE_API T&
+  range_error (const char *fcn, const Array<octave_idx_type>& ra_idx);
 
   // No checking, even for multiple references, ever.
 
@@ -322,8 +326,7 @@
   T& checkelem (octave_idx_type n)
   {
     if (n < 0 || n >= numel ())
-      // FIXME: Why should we "return" when range_error is OCTAVE_NORETURN?
-      return range_error ("T& Sparse<T>::checkelem", n);
+      range_error ("T& Sparse<T>::checkelem", n);
     else
       {
         make_unique ();
@@ -334,7 +337,7 @@
   T& checkelem (octave_idx_type i, octave_idx_type j)
   {
     if (i < 0 || j < 0 || i >= dim1 () || j >= dim2 ())
-      return range_error ("T& Sparse<T>::checkelem", i, j);
+      range_error ("T& Sparse<T>::checkelem", i, j);
     else
       {
         make_unique ();
@@ -347,7 +350,7 @@
     octave_idx_type i = compute_index (ra_idx);
 
     if (i < 0)
-      return range_error ("T& Sparse<T>::checkelem", ra_idx);
+      range_error ("T& Sparse<T>::checkelem", ra_idx);
     else
       return elem (i);
   }
@@ -385,7 +388,7 @@
   T checkelem (octave_idx_type n) const
   {
     if (n < 0 || n >= numel ())
-      return range_error ("T Sparse<T>::checkelem", n);
+      range_error ("T Sparse<T>::checkelem", n);
     else
       return xelem (n);
   }
@@ -393,7 +396,7 @@
   T checkelem (octave_idx_type i, octave_idx_type j) const
   {
     if (i < 0 || j < 0 || i >= dim1 () || j >= dim2 ())
-      return range_error ("T Sparse<T>::checkelem", i, j);
+      range_error ("T Sparse<T>::checkelem", i, j);
     else
       return xelem (i, j);
   }
@@ -403,7 +406,7 @@
     octave_idx_type i = compute_index (ra_idx);
 
     if (i < 0)
-      return range_error ("T Sparse<T>::checkelem", ra_idx);
+      range_error ("T Sparse<T>::checkelem", ra_idx);
     else
       return Sparse<T>::elem (i);
   }
@@ -436,20 +439,21 @@
     return (*this);
   }
 
-  Sparse<T> reshape (const dim_vector& new_dims) const;
+  OCTAVE_API Sparse<T> reshape (const dim_vector& new_dims) const;
 
-  Sparse<T> permute (const Array<octave_idx_type>& vec, bool inv = false) const;
+  OCTAVE_API Sparse<T>
+  permute (const Array<octave_idx_type>& vec, bool inv = false) const;
 
   Sparse<T> ipermute (const Array<octave_idx_type>& vec) const
   {
     return permute (vec, true);
   }
 
-  void resize1 (octave_idx_type n);
+  OCTAVE_API void resize1 (octave_idx_type n);
 
-  void resize (octave_idx_type r, octave_idx_type c);
+  OCTAVE_API void resize (octave_idx_type r, octave_idx_type c);
 
-  void resize (const dim_vector& dv);
+  OCTAVE_API void resize (const dim_vector& dv);
 
   void change_capacity (octave_idx_type nz)
   {
@@ -458,14 +462,16 @@
     rep->change_length (nz);
   }
 
-  Sparse<T>& insert (const Sparse<T>& a, octave_idx_type r, octave_idx_type c);
-  Sparse<T>& insert (const Sparse<T>& a, const Array<octave_idx_type>& idx);
+  OCTAVE_API Sparse<T>&
+  insert (const Sparse<T>& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API Sparse<T>&
+  insert (const Sparse<T>& a, const Array<octave_idx_type>& idx);
 
   bool issquare (void) const { return (dim1 () == dim2 ()); }
 
   bool isempty (void) const { return (rows () < 1 || cols () < 1); }
 
-  Sparse<T> transpose (void) const;
+  OCTAVE_API Sparse<T> transpose (void) const;
 
   T * data (void) { make_unique (); return rep->d; }
   T& data (octave_idx_type i) { make_unique (); return rep->data (i); }
@@ -504,22 +510,26 @@
 
   octave_idx_type ndims (void) const { return dimensions.ndims (); }
 
-  void delete_elements (const idx_vector& i);
+  OCTAVE_API void delete_elements (const octave::idx_vector& i);
 
-  void delete_elements (int dim, const idx_vector& i);
+  OCTAVE_API void delete_elements (int dim, const octave::idx_vector& i);
 
-  void delete_elements (const idx_vector& i, const idx_vector& j);
+  OCTAVE_API void delete_elements (const octave::idx_vector& i, const octave::idx_vector& j);
 
-  Sparse<T> index (const idx_vector& i, bool resize_ok = false) const;
+  OCTAVE_API Sparse<T>
+  index (const octave::idx_vector& i, bool resize_ok = false) const;
 
-  Sparse<T> index (const idx_vector& i, const idx_vector& j,
-                   bool resize_ok = false) const;
+  OCTAVE_API Sparse<T>
+  index (const octave::idx_vector& i, const octave::idx_vector& j,
+         bool resize_ok = false) const;
+
+  OCTAVE_API void assign (const octave::idx_vector& i, const Sparse<T>& rhs);
 
-  void assign (const idx_vector& i, const Sparse<T>& rhs);
+  OCTAVE_API void
+  assign (const octave::idx_vector& i, const octave::idx_vector& j, const Sparse<T>& rhs);
 
-  void assign (const idx_vector& i, const idx_vector& j, const Sparse<T>& rhs);
-
-  void print_info (std::ostream& os, const std::string& prefix) const;
+  OCTAVE_API void
+  print_info (std::ostream& os, const std::string& prefix) const;
 
   // Unsafe.  These functions exist to support the MEX interface.
   // You should not use them anywhere else.
@@ -535,17 +545,19 @@
     return const_cast<octave_idx_type *> (cidx ());
   }
 
-  Sparse<T> sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const;
-  Sparse<T> sort (Array<octave_idx_type> &sidx, octave_idx_type dim = 0,
-                  sortmode mode = ASCENDING) const;
+  OCTAVE_API Sparse<T>
+  sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const;
+  OCTAVE_API Sparse<T>
+  sort (Array<octave_idx_type> &sidx, octave_idx_type dim = 0,
+        sortmode mode = ASCENDING) const;
 
-  Sparse<T> diag (octave_idx_type k = 0) const;
+  OCTAVE_API Sparse<T> diag (octave_idx_type k = 0) const;
 
   // dim = -1 and dim = -2 are special; see Array<T>::cat description.
-  static Sparse<T>
+  static OCTAVE_API Sparse<T>
   cat (int dim, octave_idx_type n, const Sparse<T> *sparse_list);
 
-  Array<T> array_value (void) const;
+  OCTAVE_API Array<T> array_value (void) const;
 
   // Generic any/all test functionality with arbitrary predicate.
   template <typename F, bool zero>
@@ -649,6 +661,7 @@
 };
 
 template <typename T>
+OCTAVE_API
 std::istream&
 read_sparse_matrix (std::istream& is, Sparse<T>& a,
                     T (*read_fcn) (std::istream&));
--- a/liboctave/array/boolMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/boolMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -60,29 +60,30 @@
 
   boolMatrix (const Array<bool>& a) : boolNDArray (a.as_matrix ()) { }
 
-  bool operator == (const boolMatrix& a) const;
-  bool operator != (const boolMatrix& a) const;
+  OCTAVE_API bool operator == (const boolMatrix& a) const;
+  OCTAVE_API bool operator != (const boolMatrix& a) const;
 
   boolMatrix transpose (void) const { return Array<bool>::transpose (); }
 
   // destructive insert/delete/reorder operations
 
-  boolMatrix& insert (const boolMatrix& a,
-                      octave_idx_type r, octave_idx_type c);
+  OCTAVE_API boolMatrix&
+  insert (const boolMatrix& a, octave_idx_type r, octave_idx_type c);
 
   // unary operations
 
-  boolMatrix operator ! (void) const;
+  OCTAVE_API boolMatrix operator ! (void) const;
 
   // other operations
 
-  boolMatrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API boolMatrix diag (octave_idx_type k = 0) const;
 
 #if 0
   // i/o
 
-  friend std::ostream& operator << (std::ostream& os, const Matrix& a);
-  friend std::istream& operator >> (std::istream& is, Matrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const Matrix& a);
+  friend OCTAVE_API std::istream& operator >> (std::istream& is, Matrix& a);
 #endif
 
   void resize (octave_idx_type nr, octave_idx_type nc, bool rfv = false)
--- a/liboctave/array/boolNDArray.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/boolNDArray.h	Sun May 16 09:44:35 2021 +0200
@@ -60,33 +60,34 @@
 
   // unary operations
 
-  boolNDArray operator ! (void) const;
+  OCTAVE_API boolNDArray operator ! (void) const;
 
-  boolNDArray& invert (void);
+  OCTAVE_API boolNDArray& invert (void);
 
   bool any_element_is_nan (void) const { return false; }
 
   // FIXME: this is not quite the right thing.
 
-  boolNDArray all (int dim = -1) const;
-  boolNDArray any (int dim = -1) const;
+  OCTAVE_API boolNDArray all (int dim = -1) const;
+  OCTAVE_API boolNDArray any (int dim = -1) const;
 
-  boolNDArray concat (const boolNDArray& rb,
-                      const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API boolNDArray
+  concat (const boolNDArray& rb, const Array<octave_idx_type>& ra_idx);
 
-  boolNDArray& insert (const boolNDArray& a, octave_idx_type r,
-                       octave_idx_type c);
-  boolNDArray& insert (const boolNDArray& a,
-                       const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API boolNDArray&
+  insert (const boolNDArray& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API boolNDArray&
+  insert (const boolNDArray& a, const Array<octave_idx_type>& ra_idx);
 
   boolNDArray squeeze (void) const { return Array<bool>::squeeze (); }
 
-  static void increment_index (Array<octave_idx_type>& ra_idx,
-                               const dim_vector& dimensions,
-                               int start_dimension = 0);
+  static OCTAVE_API void
+  increment_index (Array<octave_idx_type>& ra_idx,
+                   const dim_vector& dimensions, int start_dimension = 0);
 
-  static octave_idx_type compute_index (Array<octave_idx_type>& ra_idx,
-                                        const dim_vector& dimensions);
+  static OCTAVE_API octave_idx_type
+  compute_index (Array<octave_idx_type>& ra_idx,
+                 const dim_vector& dimensions);
 
   // i/o
 
@@ -96,9 +97,9 @@
   //  bool all_elements_are_real (void) const;
   //  bool all_integers (double& max_val, double& min_val) const;
 
-  boolNDArray diag (octave_idx_type k = 0) const;
+  OCTAVE_API boolNDArray diag (octave_idx_type k = 0) const;
 
-  boolNDArray diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API boolNDArray diag (octave_idx_type m, octave_idx_type n) const;
 };
 
 NDND_BOOL_OP_DECLS (boolNDArray, boolNDArray, OCTAVE_API)
--- a/liboctave/array/boolSparse.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/boolSparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -180,8 +180,8 @@
           Array<octave_idx_type> tmp (dim_vector (nz, 1));
           std::copy_n (ridx (), nz, tmp.fortran_vec ());
           retval = Sparse<bool> (Array<bool> (dim_vector (1, 1), true),
-                                 idx_vector (tmp),
-                                 idx_vector (static_cast<octave_idx_type> (0)),
+                                 octave::idx_vector (tmp),
+                                 octave::idx_vector (static_cast<octave_idx_type> (0)),
                                  nr, 1, false);
         }
     }
@@ -231,8 +231,8 @@
           Array<octave_idx_type> tmp (dim_vector (nz, 1));
           std::copy_n (ridx (), nz, tmp.fortran_vec ());
           retval = Sparse<double> (Array<double> (dim_vector (1, 1), 1.0),
-                                   idx_vector (tmp),
-                                   idx_vector (static_cast<octave_idx_type> (0)),
+                                   octave::idx_vector (tmp),
+                                   octave::idx_vector (static_cast<octave_idx_type> (0)),
                                    nr, 1);
         }
     }
@@ -282,7 +282,7 @@
 {
   typedef SparseBoolMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<bool>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<bool>);
 }
 
 SparseBoolMatrix
@@ -292,13 +292,13 @@
 }
 
 SparseBoolMatrix
-SparseBoolMatrix::index (const idx_vector& i, bool resize_ok) const
+SparseBoolMatrix::index (const octave::idx_vector& i, bool resize_ok) const
 {
   return Sparse<bool>::index (i, resize_ok);
 }
 
 SparseBoolMatrix
-SparseBoolMatrix::index (const idx_vector& i, const idx_vector& j,
+SparseBoolMatrix::index (const octave::idx_vector& i, const octave::idx_vector& j,
                          bool resize_ok) const
 {
   return Sparse<bool>::index (i, j, resize_ok);
--- a/liboctave/array/boolSparse.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/boolSparse.h	Sun May 16 09:44:35 2021 +0200
@@ -28,7 +28,6 @@
 
 #include "octave-config.h"
 
-#include "MSparse.h"
 #include "PermMatrix.h"
 #include "Sparse-op-decls.h"
 #include "Sparse.h"
@@ -70,8 +69,8 @@
 
   explicit SparseBoolMatrix (const PermMatrix& a) : Sparse<bool> (a) { };
 
-  SparseBoolMatrix (const Array<bool>& a, const idx_vector& r,
-                    const idx_vector& c, octave_idx_type nr = -1,
+  SparseBoolMatrix (const Array<bool>& a, const octave::idx_vector& r,
+                    const octave::idx_vector& c, octave_idx_type nr = -1,
                     octave_idx_type nc = -1, bool sum_terms = true,
                     octave_idx_type nzm = -1)
     : Sparse<bool> (a, r, c, nr, nc, sum_terms, nzm) { }
@@ -85,50 +84,53 @@
     return *this;
   }
 
-  bool operator == (const SparseBoolMatrix& a) const;
-  bool operator != (const SparseBoolMatrix& a) const;
+  OCTAVE_API bool operator == (const SparseBoolMatrix& a) const;
+  OCTAVE_API bool operator != (const SparseBoolMatrix& a) const;
 
   SparseBoolMatrix transpose (void) const
   { return Sparse<bool>::transpose (); }
 
   // destructive insert/delete/reorder operations
 
-  SparseBoolMatrix& insert (const SparseBoolMatrix& a,
-                            octave_idx_type r, octave_idx_type c);
+  OCTAVE_API SparseBoolMatrix&
+  insert (const SparseBoolMatrix& a, octave_idx_type r, octave_idx_type c);
 
-  SparseBoolMatrix& insert (const SparseBoolMatrix& a,
-                            const Array<octave_idx_type>& indx);
+  OCTAVE_API SparseBoolMatrix&
+  insert (const SparseBoolMatrix& a, const Array<octave_idx_type>& indx);
 
-  SparseBoolMatrix concat (const SparseBoolMatrix& rb,
-                           const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API SparseBoolMatrix
+  concat (const SparseBoolMatrix& rb, const Array<octave_idx_type>& ra_idx);
 
-  SparseBoolMatrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API SparseBoolMatrix diag (octave_idx_type k = 0) const;
 
-  boolMatrix matrix_value (void) const;
+  OCTAVE_API boolMatrix matrix_value (void) const;
+
+  OCTAVE_API SparseBoolMatrix squeeze (void) const;
 
-  SparseBoolMatrix squeeze (void) const;
+  OCTAVE_API SparseBoolMatrix
+  index (const octave::idx_vector& i, bool resize_ok) const;
 
-  SparseBoolMatrix index (const idx_vector& i, bool resize_ok) const;
-
-  SparseBoolMatrix index (const idx_vector& i, const idx_vector& j,
-                          bool resize_ok) const;
+  OCTAVE_API SparseBoolMatrix
+  index (const octave::idx_vector& i, const octave::idx_vector& j,
+         bool resize_ok) const;
 
-  SparseBoolMatrix reshape (const dim_vector& new_dims) const;
+  OCTAVE_API SparseBoolMatrix reshape (const dim_vector& new_dims) const;
 
-  SparseBoolMatrix permute (const Array<octave_idx_type>& vec,
-                            bool inv = false) const;
+  OCTAVE_API SparseBoolMatrix
+  permute (const Array<octave_idx_type>& vec, bool inv = false) const;
 
-  SparseBoolMatrix ipermute (const Array<octave_idx_type>& vec) const;
+  OCTAVE_API SparseBoolMatrix
+  ipermute (const Array<octave_idx_type>& vec) const;
 
   // unary operations
 
-  SparseBoolMatrix operator ! (void) const;
+  OCTAVE_API SparseBoolMatrix operator ! (void) const;
 
   // other operations
 
-  SparseBoolMatrix all (int dim = -1) const;
-  SparseBoolMatrix any (int dim = -1) const;
-  SparseMatrix sum (int dim = -1) const;
+  OCTAVE_API SparseBoolMatrix all (int dim = -1) const;
+  OCTAVE_API SparseBoolMatrix any (int dim = -1) const;
+  OCTAVE_API SparseMatrix sum (int dim = -1) const;
 
   // i/o
 
--- a/liboctave/array/chMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/chMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -74,23 +74,26 @@
   charMatrix (const string_vector& s, char fill_value = '\0')
     : charNDArray (s, fill_value) { }
 
-  bool operator == (const charMatrix& a) const;
-  bool operator != (const charMatrix& a) const;
+  OCTAVE_API bool operator == (const charMatrix& a) const;
+  OCTAVE_API bool operator != (const charMatrix& a) const;
 
   charMatrix transpose (void) const { return Array<char>::transpose (); }
 
   // destructive insert/delete/reorder operations
 
-  charMatrix& insert (const char *s, octave_idx_type r, octave_idx_type c);
-  charMatrix& insert (const charMatrix& a,
-                      octave_idx_type r, octave_idx_type c);
+  OCTAVE_API charMatrix&
+  insert (const char *s, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API charMatrix&
+  insert (const charMatrix& a, octave_idx_type r, octave_idx_type c);
 
-  std::string row_as_string (octave_idx_type, bool strip_ws = false) const;
+  OCTAVE_API std::string
+  row_as_string (octave_idx_type, bool strip_ws = false) const;
 
   // resize is the destructive equivalent for this one
 
-  charMatrix extract (octave_idx_type r1, octave_idx_type c1,
-                      octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API charMatrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
   void resize (octave_idx_type nr, octave_idx_type nc, char rfv = 0)
   {
@@ -100,8 +103,9 @@
 #if 0
   // i/o
 
-  friend std::ostream& operator << (std::ostream& os, const Matrix& a);
-  friend std::istream& operator >> (std::istream& is, Matrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const Matrix& a);
+  friend OCTAVE_API std::istream& operator >> (std::istream& is, Matrix& a);
 #endif
 };
 
--- a/liboctave/array/chNDArray.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/chNDArray.h	Sun May 16 09:44:35 2021 +0200
@@ -52,13 +52,13 @@
 
   charNDArray (const Array<char>& a) : Array<char> (a) { }
 
-  charNDArray (char c);
+  OCTAVE_API charNDArray (char c);
 
-  charNDArray (const char *s);
+  OCTAVE_API charNDArray (const char *s);
 
-  charNDArray (const std::string& s);
+  OCTAVE_API charNDArray (const std::string& s);
 
-  charNDArray (const string_vector& s, char fill_value = '\0');
+  OCTAVE_API charNDArray (const string_vector& s, char fill_value = '\0');
 
   charNDArray& operator = (const charNDArray& a)
   {
@@ -70,39 +70,44 @@
 
   // FIXME: this is not quite the right thing.
 
-  boolNDArray all (int dim = -1) const;
-  boolNDArray any (int dim = -1) const;
-  charNDArray concat (const charNDArray& rb,
-                      const Array<octave_idx_type>& ra_idx);
-  charNDArray concat (const NDArray& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API boolNDArray all (int dim = -1) const;
+  OCTAVE_API boolNDArray any (int dim = -1) const;
+  OCTAVE_API charNDArray
+  concat (const charNDArray& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API charNDArray
+  concat (const NDArray& rb, const Array<octave_idx_type>& ra_idx);
 
-  charNDArray max (int dim = -1) const;
-  charNDArray max (Array<octave_idx_type>& index, int dim = -1) const;
-  charNDArray min (int dim = -1) const;
-  charNDArray min (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API charNDArray max (int dim = -1) const;
+  OCTAVE_API charNDArray
+  max (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API charNDArray min (int dim = -1) const;
+  OCTAVE_API charNDArray
+  min (Array<octave_idx_type>& index, int dim = -1) const;
 
-  charNDArray& insert (const charNDArray& a,
-                       octave_idx_type r, octave_idx_type c);
-  charNDArray& insert (const charNDArray& a,
-                       const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API charNDArray&
+  insert (const charNDArray& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API charNDArray&
+  insert (const charNDArray& a, const Array<octave_idx_type>& ra_idx);
 
   charNDArray squeeze (void) const { return Array<char>::squeeze (); }
 
-  static void increment_index (Array<octave_idx_type>& ra_idx,
-                               const dim_vector& dimensions,
-                               int start_dimension = 0);
+  static OCTAVE_API void
+  increment_index (Array<octave_idx_type>& ra_idx,
+                   const dim_vector& dimensions, int start_dimension = 0);
 
-  static octave_idx_type compute_index (Array<octave_idx_type>& ra_idx,
-                                        const dim_vector& dimensions);
+  static OCTAVE_API octave_idx_type
+  compute_index (Array<octave_idx_type>& ra_idx, const dim_vector& dimensions);
 
   // i/o
 
-  // friend std::ostream& operator << (std::ostream& os, const charNDArray& a);
-  // friend std::istream& operator >> (std::istream& is, charNDArray& a);
+  // friend OCTAVE_API std::ostream&
+  // operator << (std::ostream& os, const charNDArray& a);
+  // friend OCTAVE_API std::istream&
+  // operator >> (std::istream& is, charNDArray& a);
 
-  charNDArray diag (octave_idx_type k = 0) const;
+  OCTAVE_API charNDArray diag (octave_idx_type k = 0) const;
 
-  charNDArray diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API charNDArray diag (octave_idx_type m, octave_idx_type n) const;
 };
 
 extern OCTAVE_API charNDArray min (char d, const charNDArray& m);
--- a/liboctave/array/dColVector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dColVector.h	Sun May 16 09:44:35 2021 +0200
@@ -59,28 +59,31 @@
     return *this;
   }
 
-  bool operator == (const ColumnVector& a) const;
-  bool operator != (const ColumnVector& a) const;
+  OCTAVE_API bool operator == (const ColumnVector& a) const;
+  OCTAVE_API bool operator != (const ColumnVector& a) const;
 
   // destructive insert/delete/reorder operations
 
-  ColumnVector& insert (const ColumnVector& a, octave_idx_type r);
+  OCTAVE_API ColumnVector& insert (const ColumnVector& a, octave_idx_type r);
 
-  ColumnVector& fill (double val);
-  ColumnVector& fill (double val, octave_idx_type r1, octave_idx_type r2);
+  OCTAVE_API ColumnVector& fill (double val);
+  OCTAVE_API ColumnVector&
+  fill (double val, octave_idx_type r1, octave_idx_type r2);
 
-  ColumnVector stack (const ColumnVector& a) const;
+  OCTAVE_API ColumnVector stack (const ColumnVector& a) const;
 
-  RowVector transpose (void) const;
+  OCTAVE_API RowVector transpose (void) const;
 
   friend OCTAVE_API ColumnVector real (const ComplexColumnVector& a);
   friend OCTAVE_API ColumnVector imag (const ComplexColumnVector& a);
 
   // resize is the destructive equivalent for this one
 
-  ColumnVector extract (octave_idx_type r1, octave_idx_type r2) const;
+  OCTAVE_API ColumnVector
+  extract (octave_idx_type r1, octave_idx_type r2) const;
 
-  ColumnVector extract_n (octave_idx_type r1, octave_idx_type n) const;
+  OCTAVE_API ColumnVector
+  extract_n (octave_idx_type r1, octave_idx_type n) const;
 
   // matrix by column vector -> column vector operations
 
@@ -94,10 +97,10 @@
 
   // other operations
 
-  double min (void) const;
-  double max (void) const;
+  OCTAVE_API double min (void) const;
+  OCTAVE_API double max (void) const;
 
-  ColumnVector abs (void) const;
+  OCTAVE_API ColumnVector abs (void) const;
 
   // i/o
 
--- a/liboctave/array/dDiagMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dDiagMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -66,15 +66,16 @@
   DiagMatrix (const Array<double>& a, octave_idx_type r, octave_idx_type c)
     : MDiagArray2<double> (a, r, c) { }
 
-  bool operator == (const DiagMatrix& a) const;
-  bool operator != (const DiagMatrix& a) const;
+  OCTAVE_API bool operator == (const DiagMatrix& a) const;
+  OCTAVE_API bool operator != (const DiagMatrix& a) const;
 
-  DiagMatrix& fill (double val);
-  DiagMatrix& fill (double val, octave_idx_type beg, octave_idx_type end);
-  DiagMatrix& fill (const ColumnVector& a);
-  DiagMatrix& fill (const RowVector& a);
-  DiagMatrix& fill (const ColumnVector& a, octave_idx_type beg);
-  DiagMatrix& fill (const RowVector& a, octave_idx_type beg);
+  OCTAVE_API DiagMatrix& fill (double val);
+  OCTAVE_API DiagMatrix&
+  fill (double val, octave_idx_type beg, octave_idx_type end);
+  OCTAVE_API DiagMatrix& fill (const ColumnVector& a);
+  OCTAVE_API DiagMatrix& fill (const RowVector& a);
+  OCTAVE_API DiagMatrix& fill (const ColumnVector& a, octave_idx_type beg);
+  OCTAVE_API DiagMatrix& fill (const RowVector& a, octave_idx_type beg);
 
   DiagMatrix transpose (void) const
   { return MDiagArray2<double>::transpose (); }
@@ -85,33 +86,34 @@
 
   // resize is the destructive analog for this one
 
-  Matrix extract (octave_idx_type r1, octave_idx_type c1,
-                  octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API Matrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
   // extract row or column i.
 
-  RowVector row (octave_idx_type i) const;
-  RowVector row (char *s) const;
+  OCTAVE_API RowVector row (octave_idx_type i) const;
+  OCTAVE_API RowVector row (char *s) const;
 
-  ColumnVector column (octave_idx_type i) const;
-  ColumnVector column (char *s) const;
+  OCTAVE_API ColumnVector column (octave_idx_type i) const;
+  OCTAVE_API ColumnVector column (char *s) const;
 
-  DiagMatrix inverse (void) const;
-  DiagMatrix inverse (octave_idx_type& info) const;
-  DiagMatrix pseudo_inverse (double tol = 0.0) const;
+  OCTAVE_API DiagMatrix inverse (void) const;
+  OCTAVE_API DiagMatrix inverse (octave_idx_type& info) const;
+  OCTAVE_API DiagMatrix pseudo_inverse (double tol = 0.0) const;
 
   // other operations
 
   ColumnVector extract_diag (octave_idx_type k = 0) const
   { return MDiagArray2<double>::extract_diag (k); }
 
-  DET determinant (void) const;
-  double rcond (void) const;
+  OCTAVE_API DET determinant (void) const;
+  OCTAVE_API double rcond (void) const;
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const DiagMatrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const DiagMatrix& a);
 
 };
 
--- a/liboctave/array/dMatrix.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dMatrix.cc	Sun May 16 09:44:35 2021 +0200
@@ -400,14 +400,14 @@
   if (r1 > r2) { std::swap (r1, r2); }
   if (c1 > c2) { std::swap (c1, c2); }
 
-  return index (idx_vector (r1, r2+1), idx_vector (c1, c2+1));
+  return index (octave::idx_vector (r1, r2+1), octave::idx_vector (c1, c2+1));
 }
 
 Matrix
 Matrix::extract_n (octave_idx_type r1, octave_idx_type c1, octave_idx_type nr,
                    octave_idx_type nc) const
 {
-  return index (idx_vector (r1, r1 + nr), idx_vector (c1, c1 + nc));
+  return index (octave::idx_vector (r1, r1 + nr), octave::idx_vector (c1, c1 + nc));
 }
 
 // extract row or column i.
@@ -415,13 +415,13 @@
 RowVector
 Matrix::row (octave_idx_type i) const
 {
-  return index (idx_vector (i), idx_vector::colon);
+  return index (octave::idx_vector (i), octave::idx_vector::colon);
 }
 
 ColumnVector
 Matrix::column (octave_idx_type i) const
 {
-  return index (idx_vector::colon, idx_vector (i));
+  return index (octave::idx_vector::colon, octave::idx_vector (i));
 }
 
 // Local function to calculate the 1-norm.
@@ -2637,7 +2637,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_double (os, a.elem (i, j));
+          octave::write_value<double> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -2656,7 +2656,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<double> (is);
+            tmp = octave::read_value<double> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/dMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -84,47 +84,52 @@
   template <typename U>
   Matrix (const Array<U>& a) : NDArray (a.as_matrix ()) { }
 
-  explicit Matrix (const RowVector& rv);
+  explicit OCTAVE_API Matrix (const RowVector& rv);
 
-  explicit Matrix (const ColumnVector& cv);
+  explicit OCTAVE_API Matrix (const ColumnVector& cv);
 
-  explicit Matrix (const DiagMatrix& a);
+  explicit OCTAVE_API Matrix (const DiagMatrix& a);
 
-  explicit Matrix (const MDiagArray2<double>& a);
+  explicit OCTAVE_API Matrix (const MDiagArray2<double>& a);
 
-  explicit Matrix (const DiagArray2<double>& a);
+  explicit OCTAVE_API Matrix (const DiagArray2<double>& a);
 
-  explicit Matrix (const PermMatrix& a);
+  explicit OCTAVE_API Matrix (const PermMatrix& a);
 
-  explicit Matrix (const boolMatrix& a);
+  explicit OCTAVE_API Matrix (const boolMatrix& a);
 
   explicit Matrix (const charMatrix& a);
 
-  bool operator == (const Matrix& a) const;
-  bool operator != (const Matrix& a) const;
+  OCTAVE_API bool operator == (const Matrix& a) const;
+  OCTAVE_API bool operator != (const Matrix& a) const;
 
-  bool issymmetric (void) const;
+  OCTAVE_API bool issymmetric (void) const;
 
   // destructive insert/delete/reorder operations
 
-  Matrix& insert (const Matrix& a, octave_idx_type r, octave_idx_type c);
-  Matrix& insert (const RowVector& a, octave_idx_type r, octave_idx_type c);
-  Matrix& insert (const ColumnVector& a, octave_idx_type r, octave_idx_type c);
-  Matrix& insert (const DiagMatrix& a, octave_idx_type r, octave_idx_type c);
-
-  Matrix& fill (double val);
-  Matrix& fill (double val, octave_idx_type r1, octave_idx_type c1,
-                octave_idx_type r2, octave_idx_type c2);
+  OCTAVE_API Matrix&
+  insert (const Matrix& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API Matrix&
+  insert (const RowVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API Matrix&
+  insert (const ColumnVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API Matrix&
+  insert (const DiagMatrix& a, octave_idx_type r, octave_idx_type c);
 
-  Matrix append (const Matrix& a) const;
-  Matrix append (const RowVector& a) const;
-  Matrix append (const ColumnVector& a) const;
-  Matrix append (const DiagMatrix& a) const;
+  OCTAVE_API Matrix& fill (double val);
+  OCTAVE_API Matrix&
+  fill (double val, octave_idx_type r1, octave_idx_type c1,
+        octave_idx_type r2, octave_idx_type c2);
 
-  Matrix stack (const Matrix& a) const;
-  Matrix stack (const RowVector& a) const;
-  Matrix stack (const ColumnVector& a) const;
-  Matrix stack (const DiagMatrix& a) const;
+  OCTAVE_API Matrix append (const Matrix& a) const;
+  OCTAVE_API Matrix append (const RowVector& a) const;
+  OCTAVE_API Matrix append (const ColumnVector& a) const;
+  OCTAVE_API Matrix append (const DiagMatrix& a) const;
+
+  OCTAVE_API Matrix stack (const Matrix& a) const;
+  OCTAVE_API Matrix stack (const RowVector& a) const;
+  OCTAVE_API Matrix stack (const ColumnVector& a) const;
+  OCTAVE_API Matrix stack (const DiagMatrix& a) const;
 
   friend OCTAVE_API Matrix real (const ComplexMatrix& a);
   friend OCTAVE_API Matrix imag (const ComplexMatrix& a);
@@ -136,17 +141,19 @@
 
   // resize is the destructive equivalent for this one
 
-  Matrix extract (octave_idx_type r1, octave_idx_type c1,
-                  octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API Matrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
-  Matrix extract_n (octave_idx_type r1, octave_idx_type c1,
-                    octave_idx_type nr, octave_idx_type nc) const;
+  OCTAVE_API Matrix
+  extract_n (octave_idx_type r1, octave_idx_type c1,
+             octave_idx_type nr, octave_idx_type nc) const;
 
   // extract row or column i.
 
-  RowVector row (octave_idx_type i) const;
+  OCTAVE_API RowVector row (octave_idx_type i) const;
 
-  ColumnVector column (octave_idx_type i) const;
+  OCTAVE_API ColumnVector column (octave_idx_type i) const;
 
   void resize (octave_idx_type nr, octave_idx_type nc, double rfv = 0)
   {
@@ -161,33 +168,37 @@
                    bool force, bool calc_cond) const;
 
 public:
-  Matrix inverse (void) const;
-  Matrix inverse (octave_idx_type& info) const;
-  Matrix inverse (octave_idx_type& info, double& rcon, bool force = false,
-                  bool calc_cond = true) const;
+  OCTAVE_API Matrix inverse (void) const;
+  OCTAVE_API Matrix inverse (octave_idx_type& info) const;
+  OCTAVE_API Matrix
+  inverse (octave_idx_type& info, double& rcon, bool force = false,
+           bool calc_cond = true) const;
 
-  Matrix inverse (MatrixType& mattype) const;
-  Matrix inverse (MatrixType& mattype, octave_idx_type& info) const;
-  Matrix inverse (MatrixType& mattype, octave_idx_type& info, double& rcon,
-                  bool force = false, bool calc_cond = true) const;
+  OCTAVE_API Matrix inverse (MatrixType& mattype) const;
+  OCTAVE_API Matrix inverse (MatrixType& mattype, octave_idx_type& info) const;
+  OCTAVE_API Matrix
+  inverse (MatrixType& mattype, octave_idx_type& info, double& rcon,
+           bool force = false, bool calc_cond = true) const;
 
-  Matrix pseudo_inverse (double tol = 0.0) const;
+  OCTAVE_API Matrix pseudo_inverse (double tol = 0.0) const;
 
-  ComplexMatrix fourier (void) const;
-  ComplexMatrix ifourier (void) const;
+  OCTAVE_API ComplexMatrix fourier (void) const;
+  OCTAVE_API ComplexMatrix ifourier (void) const;
 
-  ComplexMatrix fourier2d (void) const;
-  ComplexMatrix ifourier2d (void) const;
+  OCTAVE_API ComplexMatrix fourier2d (void) const;
+  OCTAVE_API ComplexMatrix ifourier2d (void) const;
 
-  DET determinant (void) const;
-  DET determinant (octave_idx_type& info) const;
-  DET determinant (octave_idx_type& info, double& rcon,
-                   bool calc_cond = true) const;
-  DET determinant (MatrixType& mattype, octave_idx_type& info,
-                   double& rcon, bool calc_cond = true) const;
+  OCTAVE_API DET determinant (void) const;
+  OCTAVE_API DET determinant (octave_idx_type& info) const;
+  OCTAVE_API DET
+  determinant (octave_idx_type& info, double& rcon,
+               bool calc_cond = true) const;
+  OCTAVE_API DET
+  determinant (MatrixType& mattype, octave_idx_type& info,
+               double& rcon, bool calc_cond = true) const;
 
-  double rcond (void) const;
-  double rcond (MatrixType& mattype) const;
+  OCTAVE_API double rcond (void) const;
+  OCTAVE_API double rcond (MatrixType& mattype) const;
 
 private:
   // Upper triangular matrix solvers
@@ -209,154 +220,181 @@
 
 public:
   // Generic interface to solver with no probing of type
-  Matrix solve (MatrixType& mattype, const Matrix& b) const;
-  Matrix solve (MatrixType& mattype, const Matrix& b,
-                octave_idx_type& info) const;
-  Matrix solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
-                double& rcon) const;
-  Matrix solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
-                double& rcon, solve_singularity_handler sing_handler,
-                bool singular_fallback = true,
-                blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API Matrix solve (MatrixType& mattype, const Matrix& b) const;
+  OCTAVE_API Matrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API Matrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
+         double& rcon) const;
+  OCTAVE_API Matrix
+  solve (MatrixType& mattype, const Matrix& b, octave_idx_type& info,
+         double& rcon, solve_singularity_handler sing_handler,
+         bool singular_fallback = true,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info, double& rcon) const;
-  ComplexMatrix solve (MatrixType& mattype, const ComplexMatrix& b,
-                       octave_idx_type& info, double& rcon,
-                       solve_singularity_handler sing_handler,
-                       bool singular_fallback = true,
-                       blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b,
+         octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& mattype, const ComplexMatrix& b,
+         octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         bool singular_fallback = true,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ColumnVector solve (MatrixType& mattype, const ColumnVector& b) const;
-  ColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                      octave_idx_type& info) const;
-  ColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                      octave_idx_type& info, double& rcon) const;
-  ColumnVector solve (MatrixType& mattype, const ColumnVector& b,
-                      octave_idx_type& info, double& rcon,
-                      solve_singularity_handler sing_handler,
-                      blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b) const;
+  OCTAVE_API ColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b,
+         octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ColumnVector
+  solve (MatrixType& mattype, const ColumnVector& b, octave_idx_type& info,
+         double& rcon, solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexColumnVector solve (MatrixType& mattype,
-                             const ComplexColumnVector& b) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcon) const;
-  ComplexColumnVector solve (MatrixType& mattype, const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcon,
-                             solve_singularity_handler sing_handler,
-                             blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& mattype, const ComplexColumnVector& b,
+         octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
   // Generic interface to solver with probing of type
-  Matrix solve (const Matrix& b) const;
-  Matrix solve (const Matrix& b, octave_idx_type& info) const;
-  Matrix solve (const Matrix& b, octave_idx_type& info, double& rcon) const;
-  Matrix solve (const Matrix& b, octave_idx_type& info, double& rcon,
-                solve_singularity_handler sing_handler,
-                blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API Matrix solve (const Matrix& b) const;
+  OCTAVE_API Matrix solve (const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API Matrix
+  solve (const Matrix& b, octave_idx_type& info, double& rcon) const;
+  OCTAVE_API Matrix
+  solve (const Matrix& b, octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexMatrix solve (const ComplexMatrix& b) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info,
-                       double& rcon) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info,
-                       double& rcon,
-                       solve_singularity_handler sing_handler,
-                       blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexMatrix solve (const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info,
+         double& rcon) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ColumnVector solve (const ColumnVector& b) const;
-  ColumnVector solve (const ColumnVector& b, octave_idx_type& info) const;
-  ColumnVector solve (const ColumnVector& b, octave_idx_type& info,
-                      double& rcon) const;
-  ColumnVector solve (const ColumnVector& b, octave_idx_type& info,
-                      double& rcon,
-                      solve_singularity_handler sing_handler,
-                      blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ColumnVector solve (const ColumnVector& b) const;
+  OCTAVE_API ColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info, double& rcon) const;
+  OCTAVE_API ColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  ComplexColumnVector solve (const ComplexColumnVector& b) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcon) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcon,
-                             solve_singularity_handler sing_handler,
-                             blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API ComplexColumnVector solve (const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info,
+         double& rcon) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info, double& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
   // Singular solvers
-  Matrix lssolve (const Matrix& b) const;
-  Matrix lssolve (const Matrix& b, octave_idx_type& info) const;
-  Matrix lssolve (const Matrix& b, octave_idx_type& info,
-                  octave_idx_type& rank) const;
-  Matrix lssolve (const Matrix& b, octave_idx_type& info,
-                  octave_idx_type& rank, double& rcon) const;
+  OCTAVE_API Matrix lssolve (const Matrix& b) const;
+  OCTAVE_API Matrix lssolve (const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API Matrix
+  lssolve (const Matrix& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API Matrix
+  lssolve (const Matrix& b, octave_idx_type& info, octave_idx_type& rank,
+           double& rcon) const;
 
-  ComplexMatrix lssolve (const ComplexMatrix& b) const;
-  ComplexMatrix lssolve (const ComplexMatrix& b, octave_idx_type& info) const;
-  ComplexMatrix lssolve (const ComplexMatrix& b, octave_idx_type& info,
-                         octave_idx_type& rank) const;
-  ComplexMatrix lssolve (const ComplexMatrix& b, octave_idx_type& info,
-                         octave_idx_type& rank, double& rcon) const;
+  OCTAVE_API ComplexMatrix lssolve (const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const ComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const ComplexMatrix& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API ComplexMatrix
+  lssolve (const ComplexMatrix& b, octave_idx_type& info,
+           octave_idx_type& rank, double& rcon) const;
 
-  ColumnVector lssolve (const ColumnVector& b) const;
-  ColumnVector lssolve (const ColumnVector& b, octave_idx_type& info) const;
-  ColumnVector lssolve (const ColumnVector& b, octave_idx_type& info,
-                        octave_idx_type& rank) const;
-  ColumnVector lssolve (const ColumnVector& b, octave_idx_type& info,
-                        octave_idx_type& rank, double& rcon) const;
+  OCTAVE_API ColumnVector lssolve (const ColumnVector& b) const;
+  OCTAVE_API ColumnVector
+  lssolve (const ColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ColumnVector
+  lssolve (const ColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API ColumnVector
+  lssolve (const ColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank, double& rcon) const;
 
-  ComplexColumnVector lssolve (const ComplexColumnVector& b) const;
-  ComplexColumnVector lssolve (const ComplexColumnVector& b,
-                               octave_idx_type& info) const;
-  ComplexColumnVector lssolve (const ComplexColumnVector& b,
-                               octave_idx_type& info,
-                               octave_idx_type& rank) const;
-  ComplexColumnVector lssolve (const ComplexColumnVector& b,
-                               octave_idx_type& info,
-                               octave_idx_type& rank, double& rcon) const;
+  OCTAVE_API ComplexColumnVector lssolve (const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ComplexColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API ComplexColumnVector
+  lssolve (const ComplexColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank, double& rcon) const;
 
-  Matrix& operator += (const DiagMatrix& a);
-  Matrix& operator -= (const DiagMatrix& a);
+  OCTAVE_API Matrix& operator += (const DiagMatrix& a);
+  OCTAVE_API Matrix& operator -= (const DiagMatrix& a);
 
   // unary operations
 
   // other operations
 
-  boolMatrix all (int dim = -1) const;
-  boolMatrix any (int dim = -1) const;
+  OCTAVE_API boolMatrix all (int dim = -1) const;
+  OCTAVE_API boolMatrix any (int dim = -1) const;
 
-  Matrix cumprod (int dim = -1) const;
-  Matrix cumsum (int dim = -1) const;
-  Matrix prod (int dim = -1) const;
-  Matrix sum (int dim = -1) const;
-  Matrix sumsq (int dim = -1) const;
-  Matrix abs (void) const;
+  OCTAVE_API Matrix cumprod (int dim = -1) const;
+  OCTAVE_API Matrix cumsum (int dim = -1) const;
+  OCTAVE_API Matrix prod (int dim = -1) const;
+  OCTAVE_API Matrix sum (int dim = -1) const;
+  OCTAVE_API Matrix sumsq (int dim = -1) const;
+  OCTAVE_API Matrix abs (void) const;
 
-  Matrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API Matrix diag (octave_idx_type k = 0) const;
 
-  DiagMatrix diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API DiagMatrix diag (octave_idx_type m, octave_idx_type n) const;
 
-  ColumnVector row_min (void) const;
-  ColumnVector row_max (void) const;
+  OCTAVE_API ColumnVector row_min (void) const;
+  OCTAVE_API ColumnVector row_max (void) const;
 
-  ColumnVector row_min (Array<octave_idx_type>& index) const;
-  ColumnVector row_max (Array<octave_idx_type>& index) const;
+  OCTAVE_API ColumnVector row_min (Array<octave_idx_type>& index) const;
+  OCTAVE_API ColumnVector row_max (Array<octave_idx_type>& index) const;
 
-  RowVector column_min (void) const;
-  RowVector column_max (void) const;
+  OCTAVE_API RowVector column_min (void) const;
+  OCTAVE_API RowVector column_max (void) const;
 
-  RowVector column_min (Array<octave_idx_type>& index) const;
-  RowVector column_max (Array<octave_idx_type>& index) const;
+  OCTAVE_API RowVector column_min (Array<octave_idx_type>& index) const;
+  OCTAVE_API RowVector column_max (Array<octave_idx_type>& index) const;
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const Matrix& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is, Matrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const Matrix& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, Matrix& a);
 };
 
 // Publish externally used friend functions.
--- a/liboctave/array/dNDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dNDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -626,7 +626,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_double (os, a.elem (i));
+      octave::write_value<double> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -642,7 +642,7 @@
       double tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<double> (is);
+          tmp = octave::read_value<double> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/dNDArray.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dNDArray.h	Sun May 16 09:44:35 2021 +0200
@@ -77,64 +77,69 @@
 
   // unary operations
 
-  boolNDArray operator ! (void) const;
+  OCTAVE_API boolNDArray operator ! (void) const;
 
-  bool any_element_is_negative (bool = false) const;
-  bool any_element_is_positive (bool = false) const;
-  bool any_element_is_nan (void) const;
-  bool any_element_is_inf_or_nan (void) const;
-  bool any_element_not_one_or_zero (void) const;
-  bool all_elements_are_zero (void) const;
-  bool all_elements_are_int_or_inf_or_nan (void) const;
-  bool all_integers (double& max_val, double& min_val) const;
-  bool all_integers (void) const;
-  bool too_large_for_float (void) const;
+  OCTAVE_API bool any_element_is_negative (bool = false) const;
+  OCTAVE_API bool any_element_is_positive (bool = false) const;
+  OCTAVE_API bool any_element_is_nan (void) const;
+  OCTAVE_API bool any_element_is_inf_or_nan (void) const;
+  OCTAVE_API bool any_element_not_one_or_zero (void) const;
+  OCTAVE_API bool all_elements_are_zero (void) const;
+  OCTAVE_API bool all_elements_are_int_or_inf_or_nan (void) const;
+  OCTAVE_API bool all_integers (double& max_val, double& min_val) const;
+  OCTAVE_API bool all_integers (void) const;
+  OCTAVE_API bool too_large_for_float (void) const;
 
   // FIXME: this is not quite the right thing.
 
-  boolNDArray all (int dim = -1) const;
-  boolNDArray any (int dim = -1) const;
+  OCTAVE_API boolNDArray all (int dim = -1) const;
+  OCTAVE_API boolNDArray any (int dim = -1) const;
 
-  NDArray cumprod (int dim = -1) const;
-  NDArray cumsum (int dim = -1) const;
-  NDArray prod (int dim = -1) const;
-  NDArray sum (int dim = -1) const;
-  NDArray xsum (int dim = -1) const;
-  NDArray sumsq (int dim = -1) const;
-  NDArray concat (const NDArray& rb, const Array<octave_idx_type>& ra_idx);
-  ComplexNDArray concat (const ComplexNDArray& rb,
-                         const Array<octave_idx_type>& ra_idx);
-  charNDArray concat (const charNDArray& rb,
-                      const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API NDArray cumprod (int dim = -1) const;
+  OCTAVE_API NDArray cumsum (int dim = -1) const;
+  OCTAVE_API NDArray prod (int dim = -1) const;
+  OCTAVE_API NDArray sum (int dim = -1) const;
+  OCTAVE_API NDArray xsum (int dim = -1) const;
+  OCTAVE_API NDArray sumsq (int dim = -1) const;
+  OCTAVE_API NDArray
+  concat (const NDArray& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API ComplexNDArray
+  concat (const ComplexNDArray& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API charNDArray
+  concat (const charNDArray& rb, const Array<octave_idx_type>& ra_idx);
 
-  NDArray max (int dim = -1) const;
-  NDArray max (Array<octave_idx_type>& index, int dim = -1) const;
-  NDArray min (int dim = -1) const;
-  NDArray min (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API NDArray max (int dim = -1) const;
+  OCTAVE_API NDArray max (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API NDArray min (int dim = -1) const;
+  OCTAVE_API NDArray min (Array<octave_idx_type>& index, int dim = -1) const;
 
-  NDArray cummax (int dim = -1) const;
-  NDArray cummax (Array<octave_idx_type>& index, int dim = -1) const;
-  NDArray cummin (int dim = -1) const;
-  NDArray cummin (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API NDArray cummax (int dim = -1) const;
+  OCTAVE_API NDArray
+  cummax (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API NDArray cummin (int dim = -1) const;
+  OCTAVE_API NDArray
+  cummin (Array<octave_idx_type>& index, int dim = -1) const;
 
-  NDArray diff (octave_idx_type order = 1, int dim = -1) const;
+  OCTAVE_API NDArray diff (octave_idx_type order = 1, int dim = -1) const;
 
-  NDArray& insert (const NDArray& a, octave_idx_type r, octave_idx_type c);
-  NDArray& insert (const NDArray& a, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API NDArray&
+  insert (const NDArray& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API NDArray&
+  insert (const NDArray& a, const Array<octave_idx_type>& ra_idx);
 
-  NDArray abs (void) const;
-  boolNDArray isnan (void) const;
-  boolNDArray isinf (void) const;
-  boolNDArray isfinite (void) const;
+  OCTAVE_API NDArray abs (void) const;
+  OCTAVE_API boolNDArray isnan (void) const;
+  OCTAVE_API boolNDArray isinf (void) const;
+  OCTAVE_API boolNDArray isfinite (void) const;
 
-  ComplexNDArray fourier (int dim = 1) const;
-  ComplexNDArray ifourier (int dim = 1) const;
+  OCTAVE_API ComplexNDArray fourier (int dim = 1) const;
+  OCTAVE_API ComplexNDArray ifourier (int dim = 1) const;
 
-  ComplexNDArray fourier2d (void) const;
-  ComplexNDArray ifourier2d (void) const;
+  OCTAVE_API ComplexNDArray fourier2d (void) const;
+  OCTAVE_API ComplexNDArray ifourier2d (void) const;
 
-  ComplexNDArray fourierNd (void) const;
-  ComplexNDArray ifourierNd (void) const;
+  OCTAVE_API ComplexNDArray fourierNd (void) const;
+  OCTAVE_API ComplexNDArray ifourierNd (void) const;
 
   friend OCTAVE_API NDArray real (const ComplexNDArray& a);
   friend OCTAVE_API NDArray imag (const ComplexNDArray& a);
@@ -143,22 +148,22 @@
 
   NDArray squeeze (void) const { return MArray<double>::squeeze (); }
 
-  static void increment_index (Array<octave_idx_type>& ra_idx,
-                               const dim_vector& dimensions,
-                               int start_dimension = 0);
+  static OCTAVE_API void
+  increment_index (Array<octave_idx_type>& ra_idx,
+                   const dim_vector& dimensions, int start_dimension = 0);
 
-  static octave_idx_type compute_index (Array<octave_idx_type>& ra_idx,
-                                        const dim_vector& dimensions);
+  static OCTAVE_API octave_idx_type
+  compute_index (Array<octave_idx_type>& ra_idx, const dim_vector& dimensions);
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const NDArray& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const NDArray& a);
   friend OCTAVE_API std::istream& operator >> (std::istream& is, NDArray& a);
 
-  NDArray diag (octave_idx_type k = 0) const;
+  OCTAVE_API NDArray diag (octave_idx_type k = 0) const;
 
-  NDArray diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API NDArray diag (octave_idx_type m, octave_idx_type n) const;
 
   NDArray& changesign (void)
   {
--- a/liboctave/array/dRowVector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dRowVector.h	Sun May 16 09:44:35 2021 +0200
@@ -59,28 +59,28 @@
     return *this;
   }
 
-  bool operator == (const RowVector& a) const;
-  bool operator != (const RowVector& a) const;
+  OCTAVE_API bool operator == (const RowVector& a) const;
+  OCTAVE_API bool operator != (const RowVector& a) const;
 
   // destructive insert/delete/reorder operations
 
-  RowVector& insert (const RowVector& a, octave_idx_type c);
+  OCTAVE_API RowVector& insert (const RowVector& a, octave_idx_type c);
 
-  RowVector& fill (double val);
-  RowVector& fill (double val, octave_idx_type c1, octave_idx_type c2);
+  OCTAVE_API RowVector& fill (double val);
+  OCTAVE_API RowVector& fill (double val, octave_idx_type c1, octave_idx_type c2);
 
-  RowVector append (const RowVector& a) const;
+  OCTAVE_API RowVector append (const RowVector& a) const;
 
-  ColumnVector transpose (void) const;
+  OCTAVE_API ColumnVector transpose (void) const;
 
   friend OCTAVE_API RowVector real (const ComplexRowVector& a);
   friend OCTAVE_API RowVector imag (const ComplexRowVector& a);
 
   // resize is the destructive equivalent for this one
 
-  RowVector extract (octave_idx_type c1, octave_idx_type c2) const;
+  OCTAVE_API RowVector extract (octave_idx_type c1, octave_idx_type c2) const;
 
-  RowVector extract_n (octave_idx_type c1, octave_idx_type n) const;
+  OCTAVE_API RowVector extract_n (octave_idx_type c1, octave_idx_type n) const;
 
   // row vector by matrix -> row vector
 
@@ -88,8 +88,8 @@
 
   // other operations
 
-  double min (void) const;
-  double max (void) const;
+  OCTAVE_API double min (void) const;
+  OCTAVE_API double max (void) const;
 
   // i/o
 
@@ -109,9 +109,9 @@
 
 // row vector by column vector -> scalar
 
-double OCTAVE_API operator * (const RowVector& a, const ColumnVector& b);
+OCTAVE_API double operator * (const RowVector& a, const ColumnVector& b);
 
-Complex OCTAVE_API operator * (const RowVector& a,
+OCTAVE_API Complex operator * (const RowVector& a,
                                const ComplexColumnVector& b);
 
 // other operations
--- a/liboctave/array/dSparse.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dSparse.cc	Sun May 16 09:44:35 2021 +0200
@@ -5798,17 +5798,13 @@
 
           B->x = const_cast<double *>(b.fortran_vec ());
 
-          cholmod_factor *L;
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          L = CHOLMOD_NAME(analyze) (A, cm);
+          cholmod_factor *L = CHOLMOD_NAME(analyze) (A, cm);
           CHOLMOD_NAME(factorize) (A, L, cm);
           if (calc_cond)
             rcond = CHOLMOD_NAME(rcond)(L, cm);
           else
             rcond = 1.0;
 
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-
           if (rcond == 0.0)
             {
               // Either its indefinite or singular.  Try UMFPACK
@@ -5834,10 +5830,7 @@
                   return retval;
                 }
 
-              cholmod_dense *X;
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-              X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+              cholmod_dense *X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
 
               retval.resize (b.rows (), b.cols ());
               for (octave_idx_type j = 0; j < b.cols (); j++)
@@ -5847,13 +5840,11 @@
                     retval.xelem (i,j) = static_cast<double *>(X->x)[jr + i];
                 }
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CHOLMOD_NAME(free_dense) (&X, cm);
               CHOLMOD_NAME(free_factor) (&L, cm);
               CHOLMOD_NAME(finish) (cm);
               static char blank_name[] = " ";
               CHOLMOD_NAME(print_common) (blank_name, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 #else
           (*current_liboctave_warning_with_id_handler)
@@ -6028,15 +6019,12 @@
 
           B->x = b.data ();
 
-          cholmod_factor *L;
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          L = CHOLMOD_NAME(analyze) (A, cm);
+          cholmod_factor *L = CHOLMOD_NAME(analyze) (A, cm);
           CHOLMOD_NAME(factorize) (A, L, cm);
           if (calc_cond)
             rcond = CHOLMOD_NAME(rcond)(L, cm);
           else
             rcond = 1.;
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           if (rcond == 0.0)
             {
@@ -6063,10 +6051,7 @@
                   return retval;
                 }
 
-              cholmod_sparse *X;
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-              X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+              cholmod_sparse *X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
 
               retval = SparseMatrix (static_cast<octave_idx_type> (X->nrow),
                                      static_cast<octave_idx_type> (X->ncol),
@@ -6081,13 +6066,11 @@
                   retval.xdata (j) = static_cast<double *>(X->x)[j];
                 }
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CHOLMOD_NAME(free_sparse) (&X, cm);
               CHOLMOD_NAME(free_factor) (&L, cm);
               CHOLMOD_NAME(finish) (cm);
               static char blank_name[] = " ";
               CHOLMOD_NAME(print_common) (blank_name, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 #else
           (*current_liboctave_warning_with_id_handler)
@@ -6286,15 +6269,12 @@
 
           B->x = const_cast<Complex *>(b.fortran_vec ());
 
-          cholmod_factor *L;
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          L = CHOLMOD_NAME(analyze) (A, cm);
+          cholmod_factor *L = CHOLMOD_NAME(analyze) (A, cm);
           CHOLMOD_NAME(factorize) (A, L, cm);
           if (calc_cond)
             rcond = CHOLMOD_NAME(rcond)(L, cm);
           else
             rcond = 1.0;
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           if (rcond == 0.0)
             {
@@ -6321,10 +6301,7 @@
                   return retval;
                 }
 
-              cholmod_dense *X;
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-              X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+              cholmod_dense *X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm);
 
               retval.resize (b.rows (), b.cols ());
               for (octave_idx_type j = 0; j < b.cols (); j++)
@@ -6334,13 +6311,11 @@
                     retval.xelem (i,j) = static_cast<Complex *>(X->x)[jr + i];
                 }
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CHOLMOD_NAME(free_dense) (&X, cm);
               CHOLMOD_NAME(free_factor) (&L, cm);
               CHOLMOD_NAME(finish) (cm);
               static char blank_name[] = " ";
               CHOLMOD_NAME(print_common) (blank_name, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 #else
           (*current_liboctave_warning_with_id_handler)
@@ -6536,15 +6511,12 @@
 
           B->x = b.data ();
 
-          cholmod_factor *L;
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          L = CHOLMOD_NAME(analyze) (A, cm);
+          cholmod_factor *L = CHOLMOD_NAME(analyze) (A, cm);
           CHOLMOD_NAME(factorize) (A, L, cm);
           if (calc_cond)
             rcond = CHOLMOD_NAME(rcond)(L, cm);
           else
             rcond = 1.0;
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           if (rcond == 0.0)
             {
@@ -6571,10 +6543,7 @@
                   return retval;
                 }
 
-              cholmod_sparse *X;
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-              X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+              cholmod_sparse *X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm);
 
               retval = SparseComplexMatrix
                        (static_cast<octave_idx_type> (X->nrow),
@@ -6590,13 +6559,11 @@
                   retval.xdata (j) = static_cast<Complex *>(X->x)[j];
                 }
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CHOLMOD_NAME(free_sparse) (&X, cm);
               CHOLMOD_NAME(free_factor) (&L, cm);
               CHOLMOD_NAME(finish) (cm);
               static char blank_name[] = " ";
               CHOLMOD_NAME(print_common) (blank_name, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 #else
           (*current_liboctave_warning_with_id_handler)
@@ -7493,7 +7460,7 @@
       for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++)
         {
           os << a.ridx (i) + 1 << ' '  << j + 1 << ' ';
-          octave_write_double (os, a.data (i));
+          octave::write_value<double> (os, a.data (i));
           os << "\n";
         }
     }
@@ -7506,7 +7473,7 @@
 {
   typedef SparseMatrix::element_type elt_type;
 
-  return read_sparse_matrix<elt_type> (is, a, octave_read_value<double>);
+  return read_sparse_matrix<elt_type> (is, a, octave::read_value<double>);
 }
 
 SparseMatrix
--- a/liboctave/array/dSparse.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dSparse.h	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,6 @@
 class SparseBoolMatrix;
 
 class
-OCTAVE_API
 SparseMatrix : public MSparse<double>
 {
 public:
@@ -74,19 +73,19 @@
 
   SparseMatrix (const Sparse<double>& a) : MSparse<double> (a) { }
 
-  explicit SparseMatrix (const SparseBoolMatrix& a);
+  explicit OCTAVE_API SparseMatrix (const SparseBoolMatrix& a);
 
   explicit SparseMatrix (const Matrix& a) : MSparse<double> (a) { }
 
   explicit SparseMatrix (const NDArray& a) : MSparse<double> (a) { }
 
-  SparseMatrix (const Array<double>& a, const idx_vector& r,
-                const idx_vector& c, octave_idx_type nr = -1,
+  SparseMatrix (const Array<double>& a, const octave::idx_vector& r,
+                const octave::idx_vector& c, octave_idx_type nr = -1,
                 octave_idx_type nc = -1, bool sum_terms = true,
                 octave_idx_type nzm = -1)
     : MSparse<double> (a, r, c, nr, nc, sum_terms, nzm) { }
 
-  explicit SparseMatrix (const DiagMatrix& a);
+  explicit OCTAVE_API SparseMatrix (const DiagMatrix& a);
 
   explicit SparseMatrix (const PermMatrix& a) : MSparse<double>(a) { }
 
@@ -99,28 +98,28 @@
     return *this;
   }
 
-  bool operator == (const SparseMatrix& a) const;
-  bool operator != (const SparseMatrix& a) const;
+  OCTAVE_API bool operator == (const SparseMatrix& a) const;
+  OCTAVE_API bool operator != (const SparseMatrix& a) const;
 
-  bool issymmetric (void) const;
+  OCTAVE_API bool issymmetric (void) const;
 
-  SparseMatrix max (int dim = -1) const;
-  SparseMatrix max (Array<octave_idx_type>& index, int dim = -1) const;
-  SparseMatrix min (int dim = -1) const;
-  SparseMatrix min (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API SparseMatrix max (int dim = -1) const;
+  OCTAVE_API SparseMatrix max (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API SparseMatrix min (int dim = -1) const;
+  OCTAVE_API SparseMatrix min (Array<octave_idx_type>& index, int dim = -1) const;
 
   // destructive insert/delete/reorder operations
 
-  SparseMatrix& insert (const SparseMatrix& a, octave_idx_type r,
-                        octave_idx_type c);
+  OCTAVE_API SparseMatrix&
+  insert (const SparseMatrix& a, octave_idx_type r, octave_idx_type c);
 
-  SparseMatrix& insert (const SparseMatrix& a,
-                        const Array<octave_idx_type>& indx);
+  OCTAVE_API SparseMatrix&
+  insert (const SparseMatrix& a, const Array<octave_idx_type>& indx);
 
-  SparseMatrix concat (const SparseMatrix& rb,
-                       const Array<octave_idx_type>& ra_idx);
-  SparseComplexMatrix concat (const SparseComplexMatrix& rb,
-                              const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API SparseMatrix
+  concat (const SparseMatrix& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API SparseComplexMatrix
+  concat (const SparseComplexMatrix& rb, const Array<octave_idx_type>& ra_idx);
 
   friend OCTAVE_API SparseMatrix real (const SparseComplexMatrix& a);
   friend OCTAVE_API SparseMatrix imag (const SparseComplexMatrix& a);
@@ -133,301 +132,329 @@
 
   // extract row or column i.
 
-  RowVector row (octave_idx_type i) const;
+  OCTAVE_API RowVector row (octave_idx_type i) const;
 
-  ColumnVector column (octave_idx_type i) const;
+  OCTAVE_API ColumnVector column (octave_idx_type i) const;
 
 private:
-  SparseMatrix dinverse (MatrixType& mattype, octave_idx_type& info,
-                         double& rcond, const bool force = false,
-                         const bool calccond = true) const;
+  OCTAVE_API SparseMatrix
+  dinverse (MatrixType& mattype, octave_idx_type& info, double& rcond,
+            const bool force = false, const bool calccond = true) const;
 
-  SparseMatrix tinverse (MatrixType& mattype, octave_idx_type& info,
-                         double& rcond, const bool force = false,
-                         const bool calccond = true) const;
+  OCTAVE_API SparseMatrix
+  tinverse (MatrixType& mattype, octave_idx_type& info, double& rcond,
+            const bool force = false, const bool calccond = true) const;
 
 public:
-  SparseMatrix inverse (void) const;
-  SparseMatrix inverse (MatrixType& mattype) const;
-  SparseMatrix inverse (MatrixType& mattype, octave_idx_type& info) const;
-  SparseMatrix inverse (MatrixType& mattype, octave_idx_type& info,
-                        double& rcond, bool force = false,
-                        bool calc_cond = true) const;
+  OCTAVE_API SparseMatrix inverse (void) const;
+  OCTAVE_API SparseMatrix inverse (MatrixType& mattype) const;
+  OCTAVE_API SparseMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info) const;
+  OCTAVE_API SparseMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info, double& rcond,
+           bool force = false, bool calc_cond = true) const;
 
-  DET determinant (void) const;
-  DET determinant (octave_idx_type& info) const;
-  DET determinant (octave_idx_type& info, double& rcond,
-                   bool calc_cond = true) const;
+  OCTAVE_API DET determinant (void) const;
+  OCTAVE_API DET determinant (octave_idx_type& info) const;
+  OCTAVE_API DET determinant (octave_idx_type& info, double& rcond,
+                              bool calc_cond = true) const;
 
 private:
   // Diagonal matrix solvers
-  Matrix dsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
-                 double& rcond, solve_singularity_handler sing_handler,
-                 bool calc_cond = false) const;
+  OCTAVE_API Matrix
+  dsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  ComplexMatrix dsolve (MatrixType& typ, const ComplexMatrix& b,
-                        octave_idx_type& info, double& rcond,
-                        solve_singularity_handler sing_handler,
-                        bool calc_cond = false) const;
+  OCTAVE_API ComplexMatrix
+  dsolve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  SparseMatrix dsolve (MatrixType& typ, const SparseMatrix& b,
-                       octave_idx_type& info, double& rcond,
-                       solve_singularity_handler sing_handler,
-                       bool calc_cond = false) const;
+  OCTAVE_API SparseMatrix
+  dsolve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  SparseComplexMatrix dsolve (MatrixType& typ, const SparseComplexMatrix& b,
-                              octave_idx_type& info, double& rcond,
-                              solve_singularity_handler sing_handler,
-                              bool calc_cond = false) const;
+  OCTAVE_API SparseComplexMatrix
+  dsolve (MatrixType& typ, const SparseComplexMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
   // Upper triangular matrix solvers
-  Matrix utsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
-                  double& rcond, solve_singularity_handler sing_handler,
-                  bool calc_cond = false) const;
+  OCTAVE_API Matrix
+  utsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
+           double& rcond, solve_singularity_handler sing_handler,
+           bool calc_cond = false) const;
 
-  ComplexMatrix utsolve (MatrixType& typ, const ComplexMatrix& b,
-                         octave_idx_type& info, double& rcond,
-                         solve_singularity_handler sing_handler,
-                         bool calc_cond = false) const;
+  OCTAVE_API ComplexMatrix
+  utsolve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info,
+           double& rcond, solve_singularity_handler sing_handler,
+           bool calc_cond = false) const;
 
-  SparseMatrix utsolve (MatrixType& typ, const SparseMatrix& b,
-                        octave_idx_type& info, double& rcond,
-                        solve_singularity_handler sing_handler,
-                        bool calc_cond = false) const;
+  OCTAVE_API SparseMatrix
+  utsolve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info,
+           double& rcond, solve_singularity_handler sing_handler,
+           bool calc_cond = false) const;
 
-  SparseComplexMatrix utsolve (MatrixType& typ, const SparseComplexMatrix& b,
-                               octave_idx_type& info, double& rcond,
-                               solve_singularity_handler sing_handler,
-                               bool calc_cond = false) const;
+  OCTAVE_API SparseComplexMatrix
+  utsolve (MatrixType& typ, const SparseComplexMatrix& b, octave_idx_type& info,
+           double& rcond, solve_singularity_handler sing_handler,
+           bool calc_cond = false) const;
 
   // Lower triangular matrix solvers
-  Matrix ltsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
-                  double& rcond, solve_singularity_handler sing_handler,
-                  bool calc_cond = false) const;
+  OCTAVE_API Matrix
+  ltsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
+           double& rcond, solve_singularity_handler sing_handler,
+           bool calc_cond = false) const;
 
-  ComplexMatrix ltsolve (MatrixType& typ, const ComplexMatrix& b,
-                         octave_idx_type& info, double& rcond,
-                         solve_singularity_handler sing_handler,
-                         bool calc_cond = false) const;
+  OCTAVE_API ComplexMatrix
+  ltsolve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info,
+           double& rcond, solve_singularity_handler sing_handler,
+           bool calc_cond = false) const;
 
-  SparseMatrix ltsolve (MatrixType& typ, const SparseMatrix& b,
-                        octave_idx_type& info, double& rcond,
-                        solve_singularity_handler sing_handler,
-                        bool calc_cond = false) const;
+  OCTAVE_API SparseMatrix
+  ltsolve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info,
+           double& rcond, solve_singularity_handler sing_handler,
+           bool calc_cond = false) const;
 
-  SparseComplexMatrix ltsolve (MatrixType& typ, const SparseComplexMatrix& b,
-                               octave_idx_type& info, double& rcond,
-                               solve_singularity_handler sing_handler,
-                               bool calc_cond = false) const;
+  OCTAVE_API SparseComplexMatrix
+  ltsolve (MatrixType& typ, const SparseComplexMatrix& b, octave_idx_type& info,
+           double& rcond, solve_singularity_handler sing_handler,
+           bool calc_cond = false) const;
 
   // Tridiagonal matrix solvers
-  Matrix trisolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
-                   double& rcond, solve_singularity_handler sing_handler,
-                   bool calc_cond = false) const;
+  OCTAVE_API Matrix
+  trisolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
+            double& rcond, solve_singularity_handler sing_handler,
+            bool calc_cond = false) const;
 
-  ComplexMatrix trisolve (MatrixType& typ, const ComplexMatrix& b,
-                          octave_idx_type& info, double& rcond,
-                          solve_singularity_handler sing_handler,
-                          bool calc_cond = false) const;
+  OCTAVE_API ComplexMatrix
+  trisolve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info,
+            double& rcond, solve_singularity_handler sing_handler,
+            bool calc_cond = false) const;
 
-  SparseMatrix trisolve (MatrixType& typ, const SparseMatrix& b,
-                         octave_idx_type& info, double& rcond,
-                         solve_singularity_handler sing_handler,
-                         bool calc_cond = false) const;
+  OCTAVE_API SparseMatrix
+  trisolve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info,
+            double& rcond, solve_singularity_handler sing_handler,
+            bool calc_cond = false) const;
 
-  SparseComplexMatrix trisolve (MatrixType& typ, const SparseComplexMatrix& b,
-                                octave_idx_type& info, double& rcond,
-                                solve_singularity_handler sing_handler,
-                                bool calc_cond = false) const;
+  OCTAVE_API SparseComplexMatrix
+  trisolve (MatrixType& typ, const SparseComplexMatrix& b, octave_idx_type& info,
+            double& rcond, solve_singularity_handler sing_handler,
+            bool calc_cond = false) const;
 
   // Banded matrix solvers (umfpack/cholesky)
-  Matrix bsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
-                 double& rcond, solve_singularity_handler sing_handler,
-                 bool calc_cond = false) const;
+  OCTAVE_API Matrix
+  bsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  ComplexMatrix bsolve (MatrixType& typ, const ComplexMatrix& b,
-                        octave_idx_type& info, double& rcond,
-                        solve_singularity_handler sing_handler,
-                        bool calc_cond = false) const;
+  OCTAVE_API ComplexMatrix
+  bsolve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  SparseMatrix bsolve (MatrixType& typ, const SparseMatrix& b,
-                       octave_idx_type& info, double& rcond,
-                       solve_singularity_handler sing_handler,
-                       bool calc_cond = false) const;
+  OCTAVE_API SparseMatrix
+  bsolve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  SparseComplexMatrix bsolve (MatrixType& typ, const SparseComplexMatrix& b,
-                              octave_idx_type& info, double& rcond,
-                              solve_singularity_handler sing_handler,
-                              bool calc_cond = false) const;
+  OCTAVE_API SparseComplexMatrix
+  bsolve (MatrixType& typ, const SparseComplexMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
   // Full matrix solvers (umfpack/cholesky)
-  void * factorize (octave_idx_type& err, double& rcond, Matrix& Control,
-                    Matrix& Info, solve_singularity_handler sing_handler,
-                    bool calc_cond = false) const;
+  OCTAVE_API void *
+  factorize (octave_idx_type& err, double& rcond, Matrix& Control,
+             Matrix& Info, solve_singularity_handler sing_handler,
+             bool calc_cond = false) const;
 
-  Matrix fsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
-                 double& rcond, solve_singularity_handler sing_handler,
-                 bool calc_cond = false) const;
+  OCTAVE_API Matrix
+  fsolve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  ComplexMatrix fsolve (MatrixType& typ, const ComplexMatrix& b,
-                        octave_idx_type& info, double& rcond,
-                        solve_singularity_handler sing_handler,
-                        bool calc_cond = false) const;
+  OCTAVE_API ComplexMatrix
+  fsolve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  SparseMatrix fsolve (MatrixType& typ, const SparseMatrix& b,
-                       octave_idx_type& info, double& rcond,
-                       solve_singularity_handler sing_handler,
-                       bool calc_cond = false) const;
+  OCTAVE_API SparseMatrix
+  fsolve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
-  SparseComplexMatrix fsolve (MatrixType& typ, const SparseComplexMatrix& b,
-                              octave_idx_type& info, double& rcond,
-                              solve_singularity_handler sing_handler,
-                              bool calc_cond = false) const;
+  OCTAVE_API SparseComplexMatrix
+  fsolve (MatrixType& typ, const SparseComplexMatrix& b, octave_idx_type& info,
+          double& rcond, solve_singularity_handler sing_handler,
+          bool calc_cond = false) const;
 
 public:
   // Generic interface to solver with no probing of type
-  Matrix solve (MatrixType& typ, const Matrix& b) const;
-  Matrix solve (MatrixType& typ, const Matrix& b, octave_idx_type& info) const;
-  Matrix solve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
-                double& rcond) const;
-  Matrix solve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
-                double& rcond, solve_singularity_handler sing_handler,
-                bool singular_fallback = true) const;
+  OCTAVE_API Matrix solve (MatrixType& typ, const Matrix& b) const;
+  OCTAVE_API Matrix
+  solve (MatrixType& typ, const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API Matrix
+  solve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API Matrix
+  solve (MatrixType& typ, const Matrix& b, octave_idx_type& info,
+         double& rcond, solve_singularity_handler sing_handler,
+         bool singular_fallback = true) const;
 
-  ComplexMatrix solve (MatrixType& typ, const ComplexMatrix& b) const;
-  ComplexMatrix solve (MatrixType& typ, const ComplexMatrix& b,
-                       octave_idx_type& info) const;
-  ComplexMatrix solve (MatrixType& typ, const ComplexMatrix& b,
-                       octave_idx_type& info, double& rcond) const;
-  ComplexMatrix solve (MatrixType& typ, const ComplexMatrix& b,
-                       octave_idx_type& info, double& rcond,
-                       solve_singularity_handler sing_handler,
-                       bool singular_fallback = true) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& typ, const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API ComplexMatrix
+  solve (MatrixType& typ, const ComplexMatrix& b, octave_idx_type& info,
+         double& rcond, solve_singularity_handler sing_handler,
+         bool singular_fallback = true) const;
 
-  SparseMatrix solve (MatrixType& typ, const SparseMatrix& b) const;
-  SparseMatrix solve (MatrixType& typ, const SparseMatrix& b,
-                      octave_idx_type& info) const;
-  SparseMatrix solve (MatrixType& typ, const SparseMatrix& b,
-                      octave_idx_type& info, double& rcond) const;
-  SparseMatrix solve (MatrixType& typ, const SparseMatrix& b,
-                      octave_idx_type& info, double& rcond,
-                      solve_singularity_handler sing_handler,
-                      bool singular_fallback = true) const;
+  OCTAVE_API SparseMatrix solve (MatrixType& typ, const SparseMatrix& b) const;
+  OCTAVE_API SparseMatrix
+  solve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API SparseMatrix
+  solve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API SparseMatrix
+  solve (MatrixType& typ, const SparseMatrix& b, octave_idx_type& info,
+         double& rcond, solve_singularity_handler sing_handler,
+         bool singular_fallback = true) const;
 
-  SparseComplexMatrix solve (MatrixType& typ,
-                             const SparseComplexMatrix& b) const;
-  SparseComplexMatrix solve (MatrixType& typ, const SparseComplexMatrix& b,
-                             octave_idx_type& info) const;
-  SparseComplexMatrix solve (MatrixType& typ, const SparseComplexMatrix& b,
-                             octave_idx_type& info, double& rcond) const;
-  SparseComplexMatrix solve (MatrixType& typ, const SparseComplexMatrix& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler,
-                             bool singular_fallabck = true) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& typ, const SparseComplexMatrix& b) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& typ, const SparseComplexMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& typ, const SparseComplexMatrix& b,
+         octave_idx_type& info, double& rcond) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (MatrixType& typ, const SparseComplexMatrix& b,
+         octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler,
+         bool singular_fallabck = true) const;
 
-  ColumnVector solve (MatrixType& typ, const ColumnVector& b) const;
-  ColumnVector solve (MatrixType& typ, const ColumnVector& b,
-                      octave_idx_type& info) const;
-  ColumnVector solve (MatrixType& typ, const ColumnVector& b,
-                      octave_idx_type& info, double& rcond) const;
-  ColumnVector solve (MatrixType& typ, const ColumnVector& b,
-                      octave_idx_type& info, double& rcond,
-                      solve_singularity_handler sing_handler) const;
+  OCTAVE_API ColumnVector solve (MatrixType& typ, const ColumnVector& b) const;
+  OCTAVE_API ColumnVector
+  solve (MatrixType& typ, const ColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ColumnVector
+  solve (MatrixType& typ, const ColumnVector& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API ColumnVector
+  solve (MatrixType& typ, const ColumnVector& b, octave_idx_type& info,
+         double& rcond, solve_singularity_handler sing_handler) const;
 
-  ComplexColumnVector solve (MatrixType& typ,
-                             const ComplexColumnVector& b) const;
-  ComplexColumnVector solve (MatrixType& typ, const ComplexColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (MatrixType& typ, const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcond) const;
-  ComplexColumnVector solve (MatrixType& typ, const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& typ, const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& typ, const ComplexColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& typ, const ComplexColumnVector& b,
+         octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ComplexColumnVector
+  solve (MatrixType& typ, const ComplexColumnVector& b,
+         octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
   // Generic interface to solver with probing of type
-  Matrix solve (const Matrix& b) const;
-  Matrix solve (const Matrix& b, octave_idx_type& info) const;
-  Matrix solve (const Matrix& b, octave_idx_type& info, double& rcond) const;
-  Matrix solve (const Matrix& b, octave_idx_type& info, double& rcond,
-                solve_singularity_handler sing_handler) const;
+  OCTAVE_API Matrix solve (const Matrix& b) const;
+  OCTAVE_API Matrix solve (const Matrix& b, octave_idx_type& info) const;
+  OCTAVE_API Matrix
+  solve (const Matrix& b, octave_idx_type& info, double& rcond) const;
+  OCTAVE_API Matrix
+  solve (const Matrix& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  ComplexMatrix solve (const ComplexMatrix& b) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info,
-                       double& rcond) const;
-  ComplexMatrix solve (const ComplexMatrix& b, octave_idx_type& info,
-                       double& rcond,
-                       solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexMatrix solve (const ComplexMatrix& b) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ComplexMatrix
+  solve (const ComplexMatrix& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  SparseMatrix solve (const SparseMatrix& b) const;
-  SparseMatrix solve (const SparseMatrix& b, octave_idx_type& info) const;
-  SparseMatrix solve (const SparseMatrix& b, octave_idx_type& info,
-                      double& rcond) const;
-  SparseMatrix solve (const SparseMatrix& b, octave_idx_type& info,
-                      double& rcond,
-                      solve_singularity_handler sing_handler) const;
+  OCTAVE_API SparseMatrix solve (const SparseMatrix& b) const;
+  OCTAVE_API SparseMatrix
+  solve (const SparseMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API SparseMatrix
+  solve (const SparseMatrix& b, octave_idx_type& info, double& rcond) const;
+  OCTAVE_API SparseMatrix
+  solve (const SparseMatrix& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  SparseComplexMatrix solve (const SparseComplexMatrix& b) const;
-  SparseComplexMatrix solve (const SparseComplexMatrix& b,
-                             octave_idx_type& info) const;
-  SparseComplexMatrix solve (const SparseComplexMatrix& b,
-                             octave_idx_type& info, double& rcond) const;
-  SparseComplexMatrix solve (const SparseComplexMatrix& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API SparseComplexMatrix solve (const SparseComplexMatrix& b) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseComplexMatrix& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API SparseComplexMatrix
+  solve (const SparseComplexMatrix& b, octave_idx_type& info,
+         double& rcond, solve_singularity_handler sing_handler) const;
 
-  ColumnVector solve (const ColumnVector& b) const;
-  ColumnVector solve (const ColumnVector& b, octave_idx_type& info) const;
-  ColumnVector solve (const ColumnVector& b, octave_idx_type& info,
-                      double& rcond) const;
-  ColumnVector solve (const ColumnVector& b, octave_idx_type& info,
-                      double& rcond,
-                      solve_singularity_handler sing_handler) const;
+  OCTAVE_API ColumnVector solve (const ColumnVector& b) const;
+  OCTAVE_API ColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info, double& rcond) const;
+  OCTAVE_API ColumnVector
+  solve (const ColumnVector& b, octave_idx_type& info, double& rcond,
+         solve_singularity_handler sing_handler) const;
 
-  ComplexColumnVector solve (const ComplexColumnVector& b) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcond) const;
-  ComplexColumnVector solve (const ComplexColumnVector& b,
-                             octave_idx_type& info, double& rcond,
-                             solve_singularity_handler sing_handler) const;
+  OCTAVE_API ComplexColumnVector solve (const ComplexColumnVector& b) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info,
+         double& rcond) const;
+  OCTAVE_API ComplexColumnVector
+  solve (const ComplexColumnVector& b, octave_idx_type& info,
+         double& rcond, solve_singularity_handler sing_handler) const;
 
   // other operations
 
-  bool any_element_is_negative (bool = false) const;
-  bool any_element_is_nan (void) const;
-  bool any_element_is_inf_or_nan (void) const;
-  bool any_element_not_one_or_zero (void) const;
-  bool all_elements_are_zero (void) const;
-  bool all_elements_are_int_or_inf_or_nan (void) const;
-  bool all_integers (double& max_val, double& min_val) const;
-  bool too_large_for_float (void) const;
+  OCTAVE_API bool any_element_is_negative (bool = false) const;
+  OCTAVE_API bool any_element_is_nan (void) const;
+  OCTAVE_API bool any_element_is_inf_or_nan (void) const;
+  OCTAVE_API bool any_element_not_one_or_zero (void) const;
+  OCTAVE_API bool all_elements_are_zero (void) const;
+  OCTAVE_API bool all_elements_are_int_or_inf_or_nan (void) const;
+  OCTAVE_API bool all_integers (double& max_val, double& min_val) const;
+  OCTAVE_API bool too_large_for_float (void) const;
 
-  SparseBoolMatrix operator ! (void) const;
+  OCTAVE_API SparseBoolMatrix operator ! (void) const;
 
-  SparseBoolMatrix all (int dim = -1) const;
-  SparseBoolMatrix any (int dim = -1) const;
+  OCTAVE_API SparseBoolMatrix all (int dim = -1) const;
+  OCTAVE_API SparseBoolMatrix any (int dim = -1) const;
 
-  SparseMatrix cumprod (int dim = -1) const;
-  SparseMatrix cumsum (int dim = -1) const;
-  SparseMatrix prod (int dim = -1) const;
-  SparseMatrix sum (int dim = -1) const;
-  SparseMatrix sumsq (int dim = -1) const;
-  SparseMatrix abs (void) const;
+  OCTAVE_API SparseMatrix cumprod (int dim = -1) const;
+  OCTAVE_API SparseMatrix cumsum (int dim = -1) const;
+  OCTAVE_API SparseMatrix prod (int dim = -1) const;
+  OCTAVE_API SparseMatrix sum (int dim = -1) const;
+  OCTAVE_API SparseMatrix sumsq (int dim = -1) const;
+  OCTAVE_API SparseMatrix abs (void) const;
 
-  SparseMatrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API SparseMatrix diag (octave_idx_type k = 0) const;
 
-  Matrix matrix_value (void) const;
+  OCTAVE_API Matrix matrix_value (void) const;
 
-  SparseMatrix squeeze (void) const;
+  OCTAVE_API SparseMatrix squeeze (void) const;
 
-  SparseMatrix reshape (const dim_vector& new_dims) const;
+  OCTAVE_API SparseMatrix reshape (const dim_vector& new_dims) const;
 
-  SparseMatrix permute (const Array<octave_idx_type>& vec,
-                        bool inv = false) const;
+  OCTAVE_API SparseMatrix
+  permute (const Array<octave_idx_type>& vec, bool inv = false) const;
 
-  SparseMatrix ipermute (const Array<octave_idx_type>& vec) const;
+  OCTAVE_API SparseMatrix ipermute (const Array<octave_idx_type>& vec) const;
 
   // i/o
 
--- a/liboctave/array/dim-vector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/dim-vector.h	Sun May 16 09:44:35 2021 +0200
@@ -251,7 +251,7 @@
       }
   }
 
-  void chop_all_singletons (void);
+  OCTAVE_API void chop_all_singletons (void);
 
   // WARNING: Only call by jit
   octave_idx_type * to_jit (void) const
@@ -265,7 +265,7 @@
 
 public:
 
-  static octave_idx_type dim_max (void);
+  static OCTAVE_API octave_idx_type dim_max (void);
 
   explicit dim_vector (void) : rep (nil_rep ())
   { increment_count (); }
@@ -361,7 +361,7 @@
       }
   }
 
-  std::string str (char sep = 'x') const;
+  OCTAVE_API std::string str (char sep = 'x') const;
 
   bool all_zero (void) const
   {
@@ -385,7 +385,7 @@
                         [] (octave_idx_type dim) { return dim == 0; });
   }
 
-  int num_ones (void) const;
+  OCTAVE_API int num_ones (void) const;
 
   bool all_ones (void) const
   {
@@ -418,7 +418,7 @@
   //! function that is iterating over an array using octave_idx_type
   //! indices.
 
-  octave_idx_type safe_numel (void) const;
+  OCTAVE_API octave_idx_type safe_numel (void) const;
 
   bool any_neg (void) const
   {
@@ -426,21 +426,21 @@
                         [] (octave_idx_type dim) { return dim < 0; });
   }
 
-  dim_vector squeeze (void) const;
+  OCTAVE_API dim_vector squeeze (void) const;
 
   //! This corresponds to cat().
-  bool concat (const dim_vector& dvb, int dim);
+  OCTAVE_API bool concat (const dim_vector& dvb, int dim);
 
   //! This corresponds to [,] (horzcat, dim = 0) and [;] (vertcat, dim = 1).
   // The rules are more relaxed here.
-  bool hvcat (const dim_vector& dvb, int dim);
+  OCTAVE_API bool hvcat (const dim_vector& dvb, int dim);
 
   //! Force certain dimensionality, preserving numel ().  Missing
   //! dimensions are set to 1, redundant are folded into the trailing
   //! one.  If n = 1, the result is 2d and the second dim is 1
   //! (dim_vectors are always at least 2D).
 
-  dim_vector redim (int n) const;
+  OCTAVE_API dim_vector redim (int n) const;
 
   dim_vector as_column (void) const
   {
@@ -576,9 +576,10 @@
     return k;
   }
 
-  friend bool operator == (const dim_vector& a, const dim_vector& b);
+  friend OCTAVE_API bool
+  operator == (const dim_vector& a, const dim_vector& b);
 
-  Array<octave_idx_type> as_array (void) const;
+  OCTAVE_API Array<octave_idx_type> as_array (void) const;
 };
 
 inline bool
--- a/liboctave/array/fCColVector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fCColVector.h	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
   FloatComplexColumnVector (const Array<FloatComplex>& a)
     : MArray<FloatComplex> (a.as_column ()) { }
 
-  explicit FloatComplexColumnVector (const FloatColumnVector& a);
+  explicit OCTAVE_API FloatComplexColumnVector (const FloatColumnVector& a);
 
   FloatComplexColumnVector& operator = (const FloatComplexColumnVector& a)
   {
@@ -69,44 +69,47 @@
     return *this;
   }
 
-  bool operator == (const FloatComplexColumnVector& a) const;
-  bool operator != (const FloatComplexColumnVector& a) const;
+  OCTAVE_API bool operator == (const FloatComplexColumnVector& a) const;
+  OCTAVE_API bool operator != (const FloatComplexColumnVector& a) const;
 
   // destructive insert/delete/reorder operations
 
-  FloatComplexColumnVector& insert (const FloatColumnVector& a,
-                                    octave_idx_type r);
-  FloatComplexColumnVector& insert (const FloatComplexColumnVector& a,
-                                    octave_idx_type r);
+  OCTAVE_API FloatComplexColumnVector&
+  insert (const FloatColumnVector& a, octave_idx_type r);
+  OCTAVE_API FloatComplexColumnVector&
+  insert (const FloatComplexColumnVector& a, octave_idx_type r);
 
-  FloatComplexColumnVector& fill (float val);
-  FloatComplexColumnVector& fill (const FloatComplex& val);
-  FloatComplexColumnVector& fill (float val,
-                                  octave_idx_type r1, octave_idx_type r2);
-  FloatComplexColumnVector& fill (const FloatComplex& val,
-                                  octave_idx_type r1, octave_idx_type r2);
+  OCTAVE_API FloatComplexColumnVector& fill (float val);
+  OCTAVE_API FloatComplexColumnVector& fill (const FloatComplex& val);
+  OCTAVE_API FloatComplexColumnVector&
+  fill (float val, octave_idx_type r1, octave_idx_type r2);
+  OCTAVE_API FloatComplexColumnVector&
+  fill (const FloatComplex& val, octave_idx_type r1, octave_idx_type r2);
 
-  FloatComplexColumnVector stack (const FloatColumnVector& a) const;
-  FloatComplexColumnVector stack (const FloatComplexColumnVector& a) const;
+  OCTAVE_API FloatComplexColumnVector stack (const FloatColumnVector& a) const;
+  OCTAVE_API FloatComplexColumnVector
+  stack (const FloatComplexColumnVector& a) const;
 
-  FloatComplexRowVector hermitian (void) const;
-  FloatComplexRowVector transpose (void) const;
+  OCTAVE_API FloatComplexRowVector hermitian (void) const;
+  OCTAVE_API FloatComplexRowVector transpose (void) const;
 
   friend OCTAVE_API FloatComplexColumnVector
-  conj (const FloatComplexColumnVector& a);
+  OCTAVE_API conj (const FloatComplexColumnVector& a);
 
   // resize is the destructive equivalent for this one
 
-  FloatComplexColumnVector extract (octave_idx_type r1,
-                                    octave_idx_type r2) const;
+  OCTAVE_API FloatComplexColumnVector
+  extract (octave_idx_type r1, octave_idx_type r2) const;
 
-  FloatComplexColumnVector extract_n (octave_idx_type r1,
-                                      octave_idx_type n) const;
+  OCTAVE_API FloatComplexColumnVector
+  extract_n (octave_idx_type r1, octave_idx_type n) const;
 
   // column vector by column vector -> column vector operations
 
-  FloatComplexColumnVector& operator += (const FloatColumnVector& a);
-  FloatComplexColumnVector& operator -= (const FloatColumnVector& a);
+  OCTAVE_API FloatComplexColumnVector&
+  operator += (const FloatColumnVector& a);
+  OCTAVE_API FloatComplexColumnVector&
+  operator -= (const FloatColumnVector& a);
 
   // matrix by column vector -> column vector operations
 
@@ -134,17 +137,17 @@
 
   // other operations
 
-  FloatComplex min (void) const;
-  FloatComplex max (void) const;
+  OCTAVE_API FloatComplex min (void) const;
+  OCTAVE_API FloatComplex max (void) const;
 
-  FloatColumnVector abs (void) const;
+  OCTAVE_API FloatColumnVector abs (void) const;
 
   // i/o
 
   friend OCTAVE_API std::ostream&
   operator << (std::ostream& os, const FloatComplexColumnVector& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is,
-                                               FloatComplexColumnVector& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, FloatComplexColumnVector& a);
 
   void resize (octave_idx_type n, const FloatComplex& rfv = FloatComplex (0))
   {
--- a/liboctave/array/fCDiagMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fCDiagMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -74,7 +74,7 @@
   explicit FloatComplexDiagMatrix (const Array<float>& a)
     : MDiagArray2<FloatComplex> (Array<FloatComplex> (a)) { }
 
-  explicit FloatComplexDiagMatrix (const FloatDiagMatrix& a);
+  explicit OCTAVE_API FloatComplexDiagMatrix (const FloatDiagMatrix& a);
 
   FloatComplexDiagMatrix (const MDiagArray2<FloatComplex>& a)
     : MDiagArray2<FloatComplex> (a) { }
@@ -83,72 +83,74 @@
   FloatComplexDiagMatrix (const DiagArray2<U>& a)
     : MDiagArray2<FloatComplex> (a) { }
 
-  bool operator == (const FloatComplexDiagMatrix& a) const;
-  bool operator != (const FloatComplexDiagMatrix& a) const;
+  OCTAVE_API bool operator == (const FloatComplexDiagMatrix& a) const;
+  OCTAVE_API bool operator != (const FloatComplexDiagMatrix& a) const;
 
-  FloatComplexDiagMatrix& fill (float val);
-  FloatComplexDiagMatrix& fill (const FloatComplex& val);
-  FloatComplexDiagMatrix& fill (float val,
-                                octave_idx_type beg, octave_idx_type end);
-  FloatComplexDiagMatrix& fill (const FloatComplex& val,
-                                octave_idx_type beg, octave_idx_type end);
-  FloatComplexDiagMatrix& fill (const FloatColumnVector& a);
-  FloatComplexDiagMatrix& fill (const FloatComplexColumnVector& a);
-  FloatComplexDiagMatrix& fill (const FloatRowVector& a);
-  FloatComplexDiagMatrix& fill (const FloatComplexRowVector& a);
-  FloatComplexDiagMatrix& fill (const FloatColumnVector& a,
-                                octave_idx_type beg);
-  FloatComplexDiagMatrix& fill (const FloatComplexColumnVector& a,
-                                octave_idx_type beg);
-  FloatComplexDiagMatrix& fill (const FloatRowVector& a, octave_idx_type beg);
-  FloatComplexDiagMatrix& fill (const FloatComplexRowVector& a,
-                                octave_idx_type beg);
+  OCTAVE_API FloatComplexDiagMatrix& fill (float val);
+  OCTAVE_API FloatComplexDiagMatrix& fill (const FloatComplex& val);
+  OCTAVE_API FloatComplexDiagMatrix&
+  fill (float val, octave_idx_type beg, octave_idx_type end);
+  OCTAVE_API FloatComplexDiagMatrix&
+  fill (const FloatComplex& val, octave_idx_type beg, octave_idx_type end);
+  OCTAVE_API FloatComplexDiagMatrix& fill (const FloatColumnVector& a);
+  OCTAVE_API FloatComplexDiagMatrix& fill (const FloatComplexColumnVector& a);
+  OCTAVE_API FloatComplexDiagMatrix& fill (const FloatRowVector& a);
+  OCTAVE_API FloatComplexDiagMatrix& fill (const FloatComplexRowVector& a);
+  OCTAVE_API FloatComplexDiagMatrix&
+  fill (const FloatColumnVector& a, octave_idx_type beg);
+  OCTAVE_API FloatComplexDiagMatrix&
+  fill (const FloatComplexColumnVector& a, octave_idx_type beg);
+  OCTAVE_API FloatComplexDiagMatrix&
+  fill (const FloatRowVector& a, octave_idx_type beg);
+  OCTAVE_API FloatComplexDiagMatrix&
+  fill (const FloatComplexRowVector& a, octave_idx_type beg);
 
   FloatComplexDiagMatrix hermitian (void) const
   { return MDiagArray2<FloatComplex>::hermitian (std::conj); }
   FloatComplexDiagMatrix transpose (void) const
   { return MDiagArray2<FloatComplex>::transpose (); }
-  FloatDiagMatrix abs (void) const;
+  OCTAVE_API FloatDiagMatrix abs (void) const;
 
   friend OCTAVE_API FloatComplexDiagMatrix
   conj (const FloatComplexDiagMatrix& a);
 
   // resize is the destructive analog for this one
 
-  FloatComplexMatrix extract (octave_idx_type r1, octave_idx_type c1,
-                              octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API FloatComplexMatrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
   // extract row or column i
 
-  FloatComplexRowVector row (octave_idx_type i) const;
-  FloatComplexRowVector row (char *s) const;
+  OCTAVE_API FloatComplexRowVector row (octave_idx_type i) const;
+  OCTAVE_API FloatComplexRowVector row (char *s) const;
 
-  FloatComplexColumnVector column (octave_idx_type i) const;
-  FloatComplexColumnVector column (char *s) const;
+  OCTAVE_API FloatComplexColumnVector column (octave_idx_type i) const;
+  OCTAVE_API FloatComplexColumnVector column (char *s) const;
 
-  FloatComplexDiagMatrix inverse (octave_idx_type& info) const;
-  FloatComplexDiagMatrix inverse (void) const;
-  FloatComplexDiagMatrix pseudo_inverse (float tol = 0.0f) const;
+  OCTAVE_API FloatComplexDiagMatrix inverse (octave_idx_type& info) const;
+  OCTAVE_API FloatComplexDiagMatrix inverse (void) const;
+  OCTAVE_API FloatComplexDiagMatrix pseudo_inverse (float tol = 0.0f) const;
 
-  bool all_elements_are_real (void) const;
+  OCTAVE_API bool all_elements_are_real (void) const;
 
   // diagonal matrix by diagonal matrix -> diagonal matrix operations
 
-  FloatComplexDiagMatrix& operator += (const FloatDiagMatrix& a);
-  FloatComplexDiagMatrix& operator -= (const FloatDiagMatrix& a);
+  OCTAVE_API FloatComplexDiagMatrix& operator += (const FloatDiagMatrix& a);
+  OCTAVE_API FloatComplexDiagMatrix& operator -= (const FloatDiagMatrix& a);
 
   // other operations
 
   FloatComplexColumnVector extract_diag (octave_idx_type k = 0) const
   { return MDiagArray2<FloatComplex>::extract_diag (k); }
 
-  FloatComplexDET determinant (void) const;
-  float rcond (void) const;
+  OCTAVE_API FloatComplexDET determinant (void) const;
+  OCTAVE_API float rcond (void) const;
 
   // i/o
 
-  friend std::ostream& operator << (std::ostream& os,
-                                    const FloatComplexDiagMatrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const FloatComplexDiagMatrix& a);
 
 };
 
--- a/liboctave/array/fCMatrix.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fCMatrix.cc	Sun May 16 09:44:35 2021 +0200
@@ -689,14 +689,14 @@
   if (r1 > r2) { std::swap (r1, r2); }
   if (c1 > c2) { std::swap (c1, c2); }
 
-  return index (idx_vector (r1, r2+1), idx_vector (c1, c2+1));
+  return index (octave::idx_vector (r1, r2+1), octave::idx_vector (c1, c2+1));
 }
 
 FloatComplexMatrix
 FloatComplexMatrix::extract_n (octave_idx_type r1, octave_idx_type c1,
                                octave_idx_type nr, octave_idx_type nc) const
 {
-  return index (idx_vector (r1, r1 + nr), idx_vector (c1, c1 + nc));
+  return index (octave::idx_vector (r1, r1 + nr), octave::idx_vector (c1, c1 + nc));
 }
 
 // extract row or column i.
@@ -704,13 +704,13 @@
 FloatComplexRowVector
 FloatComplexMatrix::row (octave_idx_type i) const
 {
-  return index (idx_vector (i), idx_vector::colon);
+  return index (octave::idx_vector (i), octave::idx_vector::colon);
 }
 
 FloatComplexColumnVector
 FloatComplexMatrix::column (octave_idx_type i) const
 {
-  return index (idx_vector::colon, idx_vector (i));
+  return index (octave::idx_vector::colon, octave::idx_vector (i));
 }
 
 // Local function to calculate the 1-norm.
@@ -3200,7 +3200,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_complex (os, a.elem (i, j));
+          octave::write_value<Complex> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -3219,7 +3219,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<FloatComplex> (is);
+            tmp = octave::read_value<FloatComplex> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/fCMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fCMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -89,86 +89,91 @@
   FloatComplexMatrix (const Array<U>& a)
     : FloatComplexNDArray (a.as_matrix ()) { }
 
-  explicit FloatComplexMatrix (const FloatMatrix& a);
+  explicit OCTAVE_API FloatComplexMatrix (const FloatMatrix& a);
 
-  explicit FloatComplexMatrix (const FloatRowVector& rv);
+  explicit OCTAVE_API FloatComplexMatrix (const FloatRowVector& rv);
 
-  explicit FloatComplexMatrix (const FloatColumnVector& cv);
+  explicit OCTAVE_API FloatComplexMatrix (const FloatColumnVector& cv);
 
-  explicit FloatComplexMatrix (const FloatDiagMatrix& a);
+  explicit OCTAVE_API FloatComplexMatrix (const FloatDiagMatrix& a);
 
-  explicit FloatComplexMatrix (const MDiagArray2<float>& a);
+  explicit OCTAVE_API FloatComplexMatrix (const MDiagArray2<float>& a);
 
-  explicit FloatComplexMatrix (const DiagArray2<float>& a);
+  explicit OCTAVE_API FloatComplexMatrix (const DiagArray2<float>& a);
 
-  explicit FloatComplexMatrix (const FloatComplexRowVector& rv);
+  explicit OCTAVE_API FloatComplexMatrix (const FloatComplexRowVector& rv);
 
-  explicit FloatComplexMatrix (const FloatComplexColumnVector& cv);
+  explicit OCTAVE_API FloatComplexMatrix (const FloatComplexColumnVector& cv);
 
-  explicit FloatComplexMatrix (const FloatComplexDiagMatrix& a);
+  explicit OCTAVE_API FloatComplexMatrix (const FloatComplexDiagMatrix& a);
 
-  explicit FloatComplexMatrix (const MDiagArray2<FloatComplex>& a);
+  explicit OCTAVE_API FloatComplexMatrix (const MDiagArray2<FloatComplex>& a);
 
-  explicit FloatComplexMatrix (const DiagArray2<FloatComplex>& a);
+  explicit OCTAVE_API FloatComplexMatrix (const DiagArray2<FloatComplex>& a);
 
-  explicit FloatComplexMatrix (const boolMatrix& a);
+  explicit OCTAVE_API FloatComplexMatrix (const boolMatrix& a);
 
-  explicit FloatComplexMatrix (const charMatrix& a);
+  explicit OCTAVE_API FloatComplexMatrix (const charMatrix& a);
 
-  FloatComplexMatrix (const FloatMatrix& re, const FloatMatrix& im);
+  OCTAVE_API FloatComplexMatrix (const FloatMatrix& re, const FloatMatrix& im);
 
-  bool operator == (const FloatComplexMatrix& a) const;
-  bool operator != (const FloatComplexMatrix& a) const;
+  OCTAVE_API bool operator == (const FloatComplexMatrix& a) const;
+  OCTAVE_API bool operator != (const FloatComplexMatrix& a) const;
 
-  bool ishermitian (void) const;
+  OCTAVE_API bool ishermitian (void) const;
 
   // destructive insert/delete/reorder operations
 
-  FloatComplexMatrix& insert (const FloatMatrix& a,
-                              octave_idx_type r, octave_idx_type c);
-  FloatComplexMatrix& insert (const FloatRowVector& a,
-                              octave_idx_type r, octave_idx_type c);
-  FloatComplexMatrix& insert (const FloatColumnVector& a,
-                              octave_idx_type r, octave_idx_type c);
-  FloatComplexMatrix& insert (const FloatDiagMatrix& a,
-                              octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatComplexMatrix&
+  insert (const FloatMatrix& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatComplexMatrix&
+  insert (const FloatRowVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatComplexMatrix&
+  insert (const FloatColumnVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatComplexMatrix&
+  insert (const FloatDiagMatrix& a, octave_idx_type r, octave_idx_type c);
 
-  FloatComplexMatrix& insert (const FloatComplexMatrix& a,
-                              octave_idx_type r, octave_idx_type c);
-  FloatComplexMatrix& insert (const FloatComplexRowVector& a,
-                              octave_idx_type r, octave_idx_type c);
-  FloatComplexMatrix& insert (const FloatComplexColumnVector& a,
-                              octave_idx_type r, octave_idx_type c);
-  FloatComplexMatrix& insert (const FloatComplexDiagMatrix& a,
-                              octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatComplexMatrix&
+  insert (const FloatComplexMatrix& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatComplexMatrix&
+  insert (const FloatComplexRowVector& a, octave_idx_type r,
+          octave_idx_type c);
+  OCTAVE_API FloatComplexMatrix&
+  insert (const FloatComplexColumnVector& a, octave_idx_type r,
+          octave_idx_type c);
+  OCTAVE_API FloatComplexMatrix&
+  insert (const FloatComplexDiagMatrix& a, octave_idx_type r,
+          octave_idx_type c);
 
-  FloatComplexMatrix& fill (float val);
-  FloatComplexMatrix& fill (const FloatComplex& val);
-  FloatComplexMatrix& fill (float val, octave_idx_type r1, octave_idx_type c1,
-                            octave_idx_type r2, octave_idx_type c2);
-  FloatComplexMatrix& fill (const FloatComplex& val,
-                            octave_idx_type r1, octave_idx_type c1,
-                            octave_idx_type r2, octave_idx_type c2);
+  OCTAVE_API FloatComplexMatrix& fill (float val);
+  OCTAVE_API FloatComplexMatrix& fill (const FloatComplex& val);
+  OCTAVE_API FloatComplexMatrix&
+  fill (float val, octave_idx_type r1, octave_idx_type c1,
+        octave_idx_type r2, octave_idx_type c2);
+  OCTAVE_API FloatComplexMatrix&
+  fill (const FloatComplex& val, octave_idx_type r1, octave_idx_type c1,
+        octave_idx_type r2, octave_idx_type c2);
 
-  FloatComplexMatrix append (const FloatMatrix& a) const;
-  FloatComplexMatrix append (const FloatRowVector& a) const;
-  FloatComplexMatrix append (const FloatColumnVector& a) const;
-  FloatComplexMatrix append (const FloatDiagMatrix& a) const;
+  OCTAVE_API FloatComplexMatrix append (const FloatMatrix& a) const;
+  OCTAVE_API FloatComplexMatrix append (const FloatRowVector& a) const;
+  OCTAVE_API FloatComplexMatrix append (const FloatColumnVector& a) const;
+  OCTAVE_API FloatComplexMatrix append (const FloatDiagMatrix& a) const;
 
-  FloatComplexMatrix append (const FloatComplexMatrix& a) const;
-  FloatComplexMatrix append (const FloatComplexRowVector& a) const;
-  FloatComplexMatrix append (const FloatComplexColumnVector& a) const;
-  FloatComplexMatrix append (const FloatComplexDiagMatrix& a) const;
+  OCTAVE_API FloatComplexMatrix append (const FloatComplexMatrix& a) const;
+  OCTAVE_API FloatComplexMatrix append (const FloatComplexRowVector& a) const;
+  OCTAVE_API FloatComplexMatrix
+  append (const FloatComplexColumnVector& a) const;
+  OCTAVE_API FloatComplexMatrix append (const FloatComplexDiagMatrix& a) const;
 
-  FloatComplexMatrix stack (const FloatMatrix& a) const;
-  FloatComplexMatrix stack (const FloatRowVector& a) const;
-  FloatComplexMatrix stack (const FloatColumnVector& a) const;
-  FloatComplexMatrix stack (const FloatDiagMatrix& a) const;
+  OCTAVE_API FloatComplexMatrix stack (const FloatMatrix& a) const;
+  OCTAVE_API FloatComplexMatrix stack (const FloatRowVector& a) const;
+  OCTAVE_API FloatComplexMatrix stack (const FloatColumnVector& a) const;
+  OCTAVE_API FloatComplexMatrix stack (const FloatDiagMatrix& a) const;
 
-  FloatComplexMatrix stack (const FloatComplexMatrix& a) const;
-  FloatComplexMatrix stack (const FloatComplexRowVector& a) const;
-  FloatComplexMatrix stack (const FloatComplexColumnVector& a) const;
-  FloatComplexMatrix stack (const FloatComplexDiagMatrix& a) const;
+  OCTAVE_API FloatComplexMatrix stack (const FloatComplexMatrix& a) const;
+  OCTAVE_API FloatComplexMatrix stack (const FloatComplexRowVector& a) const;
+  OCTAVE_API FloatComplexMatrix stack (const FloatComplexColumnVector& a) const;
+  OCTAVE_API FloatComplexMatrix stack (const FloatComplexDiagMatrix& a) const;
 
   FloatComplexMatrix hermitian (void) const
   { return MArray<FloatComplex>::hermitian (std::conj); }
@@ -179,17 +184,19 @@
 
   // resize is the destructive equivalent for this one
 
-  FloatComplexMatrix extract (octave_idx_type r1, octave_idx_type c1,
-                              octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API FloatComplexMatrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
-  FloatComplexMatrix extract_n (octave_idx_type r1, octave_idx_type c1,
-                                octave_idx_type nr, octave_idx_type nc) const;
+  OCTAVE_API FloatComplexMatrix
+  extract_n (octave_idx_type r1, octave_idx_type c1,
+             octave_idx_type nr, octave_idx_type nc) const;
 
   // extract row or column i.
 
-  FloatComplexRowVector row (octave_idx_type i) const;
+  OCTAVE_API FloatComplexRowVector row (octave_idx_type i) const;
 
-  FloatComplexColumnVector column (octave_idx_type i) const;
+  OCTAVE_API FloatComplexColumnVector column (octave_idx_type i) const;
 
   void resize (octave_idx_type nr, octave_idx_type nc,
                const FloatComplex& rfv = FloatComplex (0))
@@ -205,34 +212,38 @@
                                float& rcon, bool force, bool calc_cond) const;
 
 public:
-  FloatComplexMatrix inverse (void) const;
-  FloatComplexMatrix inverse (octave_idx_type& info) const;
-  FloatComplexMatrix inverse (octave_idx_type& info, float& rcon,
-                              bool force = false, bool calc_cond = true) const;
+  OCTAVE_API FloatComplexMatrix inverse (void) const;
+  OCTAVE_API FloatComplexMatrix inverse (octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  inverse (octave_idx_type& info, float& rcon, bool force = false,
+           bool calc_cond = true) const;
 
-  FloatComplexMatrix inverse (MatrixType& mattype) const;
-  FloatComplexMatrix inverse (MatrixType& mattype, octave_idx_type& info) const;
-  FloatComplexMatrix inverse (MatrixType& mattype, octave_idx_type& info,
-                              float& rcon, bool force = false,
-                              bool calc_cond = true) const;
+  OCTAVE_API FloatComplexMatrix inverse (MatrixType& mattype) const;
+  OCTAVE_API FloatComplexMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info, float& rcon,
+           bool force = false, bool calc_cond = true) const;
 
-  FloatComplexMatrix pseudo_inverse (float tol = 0.0) const;
+  OCTAVE_API FloatComplexMatrix pseudo_inverse (float tol = 0.0) const;
 
-  FloatComplexMatrix fourier (void) const;
-  FloatComplexMatrix ifourier (void) const;
+  OCTAVE_API FloatComplexMatrix fourier (void) const;
+  OCTAVE_API FloatComplexMatrix ifourier (void) const;
 
-  FloatComplexMatrix fourier2d (void) const;
-  FloatComplexMatrix ifourier2d (void) const;
+  OCTAVE_API FloatComplexMatrix fourier2d (void) const;
+  OCTAVE_API FloatComplexMatrix ifourier2d (void) const;
 
-  FloatComplexDET determinant (void) const;
-  FloatComplexDET determinant (octave_idx_type& info) const;
-  FloatComplexDET determinant (octave_idx_type& info, float& rcon,
-                               bool calc_cond = true) const;
-  FloatComplexDET determinant (MatrixType& mattype, octave_idx_type& info,
-                               float& rcon, bool calc_cond = true) const;
+  OCTAVE_API FloatComplexDET determinant (void) const;
+  OCTAVE_API FloatComplexDET determinant (octave_idx_type& info) const;
+  OCTAVE_API FloatComplexDET
+  determinant (octave_idx_type& info, float& rcon,
+               bool calc_cond = true) const;
+  OCTAVE_API FloatComplexDET
+  determinant (MatrixType& mattype, octave_idx_type& info,
+               float& rcon, bool calc_cond = true) const;
 
-  float rcond (void) const;
-  float rcond (MatrixType& mattype) const;
+  OCTAVE_API float rcond (void) const;
+  OCTAVE_API float rcond (MatrixType& mattype) const;
 
 private:
   // Upper triangular matrix solvers
@@ -257,187 +268,208 @@
 
 public:
   // Generic interface to solver with no probing of type
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatMatrix& b) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatMatrix& b,
-                            octave_idx_type& info) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatMatrix& b,
-                            octave_idx_type& info, float& rcon) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatMatrix& b,
-                            octave_idx_type& info,
-                            float& rcon, solve_singularity_handler sing_handler,
-                            bool singular_fallback = true,
-                            blas_trans_type transt = blas_no_trans) const;
-
-  FloatComplexMatrix solve (MatrixType& mattype,
-                            const FloatComplexMatrix& b) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatComplexMatrix& b,
-                            octave_idx_type& info) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatComplexMatrix& b,
-                            octave_idx_type& info, float& rcon) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatComplexMatrix& b,
-                            octave_idx_type& info, float& rcon,
-                            solve_singularity_handler sing_handler,
-                            bool singular_fallback = true,
-                            blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatMatrix& b, octave_idx_type& info,
+         float& rcon) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatMatrix& b, octave_idx_type& info,
+         float& rcon, solve_singularity_handler sing_handler,
+         bool singular_fallback = true,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatColumnVector& b) const;
-  FloatComplexColumnVector solve (MatrixType& mattype, const FloatColumnVector& b,
-                                  octave_idx_type& info) const;
-  FloatComplexColumnVector solve (MatrixType& mattype, const FloatColumnVector& b,
-                                  octave_idx_type& info, float& rcon) const;
-  FloatComplexColumnVector solve (MatrixType& mattype, const FloatColumnVector& b,
-                                  octave_idx_type& info, float& rcon,
-                                  solve_singularity_handler sing_handler,
-                                  blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatComplexMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatComplexMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatComplexMatrix& b,
+         octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatComplexMatrix& b,
+         octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         bool singular_fallback = true,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatComplexColumnVector& b) const;
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatComplexColumnVector& b,
-                                  octave_idx_type& info) const;
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatComplexColumnVector& b,
-                                  octave_idx_type& info, float& rcon) const;
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatComplexColumnVector& b,
-                                  octave_idx_type& info, float& rcon,
-                                  solve_singularity_handler sing_handler,
-                                  blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatColumnVector& b,
+         octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatColumnVector& b,
+         octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
+
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatComplexColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatComplexColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatComplexColumnVector& b,
+         octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatComplexColumnVector& b,
+         octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
   // Generic interface to solver with probing of type
-  FloatComplexMatrix solve (const FloatMatrix& b) const;
-  FloatComplexMatrix solve (const FloatMatrix& b, octave_idx_type& info) const;
-  FloatComplexMatrix solve (const FloatMatrix& b, octave_idx_type& info,
-                            float& rcon) const;
-  FloatComplexMatrix solve (const FloatMatrix& b, octave_idx_type& info,
-                            float& rcon,
-                            solve_singularity_handler sing_handler,
-                            blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexMatrix solve (const FloatMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatMatrix& b, octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatMatrix& b, octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexMatrix solve (const FloatComplexMatrix& b) const;
-  FloatComplexMatrix solve (const FloatComplexMatrix& b,
-                            octave_idx_type& info) const;
-  FloatComplexMatrix solve (const FloatComplexMatrix& b, octave_idx_type& info,
-                            float& rcon) const;
-  FloatComplexMatrix solve (const FloatComplexMatrix& b, octave_idx_type& info,
-                            float& rcon,
-                            solve_singularity_handler sing_handler,
-                            blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexMatrix solve (const FloatComplexMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatComplexMatrix& b, octave_idx_type& info,
+         float& rcon) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatComplexMatrix& b, octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexColumnVector solve (const FloatColumnVector& b) const;
-  FloatComplexColumnVector solve (const FloatColumnVector& b,
-                                  octave_idx_type& info) const;
-  FloatComplexColumnVector solve (const FloatColumnVector& b,
-                                  octave_idx_type& info,
-                                  float& rcon) const;
-  FloatComplexColumnVector solve (const FloatColumnVector& b,
-                                  octave_idx_type& info, float& rcon,
-                                  solve_singularity_handler sing_handler,
-                                  blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexColumnVector solve (const FloatColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatColumnVector& b, octave_idx_type& info,
+         float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatColumnVector& b, octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexColumnVector solve (const FloatComplexColumnVector& b) const;
-  FloatComplexColumnVector solve (const FloatComplexColumnVector& b,
-                                  octave_idx_type& info) const;
-  FloatComplexColumnVector solve (const FloatComplexColumnVector& b,
-                                  octave_idx_type& info,
-                                  float& rcon) const;
-  FloatComplexColumnVector solve (const FloatComplexColumnVector& b,
-                                  octave_idx_type& info,
-                                  float& rcon,
-                                  solve_singularity_handler sing_handler,
-                                  blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatComplexColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatComplexColumnVector& b, octave_idx_type& info,
+         float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatComplexColumnVector& b, octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexMatrix lssolve (const FloatMatrix& b) const;
-  FloatComplexMatrix lssolve (const FloatMatrix& b,
-                              octave_idx_type& info) const;
-  FloatComplexMatrix lssolve (const FloatMatrix& b, octave_idx_type& info,
-                              octave_idx_type& rank) const;
-  FloatComplexMatrix lssolve (const FloatMatrix& b, octave_idx_type& info,
-                              octave_idx_type& rank, float& rcon) const;
+  OCTAVE_API FloatComplexMatrix lssolve (const FloatMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  lssolve (const FloatMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  lssolve (const FloatMatrix& b, octave_idx_type& info, octave_idx_type& rank) const;
+  OCTAVE_API FloatComplexMatrix
+  lssolve (const FloatMatrix& b, octave_idx_type& info, octave_idx_type& rank,
+           float& rcon) const;
 
-  FloatComplexMatrix lssolve (const FloatComplexMatrix& b) const;
-  FloatComplexMatrix lssolve (const FloatComplexMatrix& b,
-                              octave_idx_type& info) const;
-  FloatComplexMatrix lssolve (const FloatComplexMatrix& b,
-                              octave_idx_type& info, octave_idx_type& rank) const;
-  FloatComplexMatrix lssolve (const FloatComplexMatrix& b,
-                              octave_idx_type& info, octave_idx_type& rank, float& rcon) const;
+  OCTAVE_API FloatComplexMatrix lssolve (const FloatComplexMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  lssolve (const FloatComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  lssolve (const FloatComplexMatrix& b, octave_idx_type& info,
+  octave_idx_type& rank) const;
+  OCTAVE_API FloatComplexMatrix
+  lssolve (const FloatComplexMatrix& b, octave_idx_type& info,
+           octave_idx_type& rank, float& rcon) const;
 
-  FloatComplexColumnVector lssolve (const FloatColumnVector& b) const;
-  FloatComplexColumnVector lssolve (const FloatColumnVector& b,
-                                    octave_idx_type& info) const;
-  FloatComplexColumnVector lssolve (const FloatColumnVector& b,
-                                    octave_idx_type& info,
-                                    octave_idx_type& rank) const;
-  FloatComplexColumnVector lssolve (const FloatColumnVector& b,
-                                    octave_idx_type& info,
-                                    octave_idx_type& rank, float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank, float& rcon) const;
 
-  FloatComplexColumnVector lssolve (const FloatComplexColumnVector& b) const;
-  FloatComplexColumnVector lssolve (const FloatComplexColumnVector& b,
-                                    octave_idx_type& info) const;
-  FloatComplexColumnVector lssolve (const FloatComplexColumnVector& b,
-                                    octave_idx_type& info,
-                                    octave_idx_type& rank) const;
-  FloatComplexColumnVector lssolve (const FloatComplexColumnVector& b,
-                                    octave_idx_type& info,
-                                    octave_idx_type& rank, float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatComplexColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatComplexColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatComplexColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank, float& rcon) const;
 
   // matrix by diagonal matrix -> matrix operations
 
-  FloatComplexMatrix& operator += (const FloatDiagMatrix& a);
-  FloatComplexMatrix& operator -= (const FloatDiagMatrix& a);
+  OCTAVE_API FloatComplexMatrix& operator += (const FloatDiagMatrix& a);
+  OCTAVE_API FloatComplexMatrix& operator -= (const FloatDiagMatrix& a);
 
-  FloatComplexMatrix& operator += (const FloatComplexDiagMatrix& a);
-  FloatComplexMatrix& operator -= (const FloatComplexDiagMatrix& a);
+  OCTAVE_API FloatComplexMatrix& operator += (const FloatComplexDiagMatrix& a);
+  OCTAVE_API FloatComplexMatrix& operator -= (const FloatComplexDiagMatrix& a);
 
   // matrix by matrix -> matrix operations
 
-  FloatComplexMatrix& operator += (const FloatMatrix& a);
-  FloatComplexMatrix& operator -= (const FloatMatrix& a);
+  OCTAVE_API FloatComplexMatrix& operator += (const FloatMatrix& a);
+  OCTAVE_API FloatComplexMatrix& operator -= (const FloatMatrix& a);
 
   // unary operations
 
-  boolMatrix operator ! (void) const;
+  OCTAVE_API boolMatrix operator ! (void) const;
 
   // other operations
 
-  boolMatrix all (int dim = -1) const;
-  boolMatrix any (int dim = -1) const;
+  OCTAVE_API boolMatrix all (int dim = -1) const;
+  OCTAVE_API boolMatrix any (int dim = -1) const;
 
-  FloatComplexMatrix cumprod (int dim = -1) const;
-  FloatComplexMatrix cumsum (int dim = -1) const;
-  FloatComplexMatrix prod (int dim = -1) const;
-  FloatComplexMatrix sum (int dim = -1) const;
-  FloatComplexMatrix sumsq (int dim = -1) const;
-  FloatMatrix abs (void) const;
+  OCTAVE_API FloatComplexMatrix cumprod (int dim = -1) const;
+  OCTAVE_API FloatComplexMatrix cumsum (int dim = -1) const;
+  OCTAVE_API FloatComplexMatrix prod (int dim = -1) const;
+  OCTAVE_API FloatComplexMatrix sum (int dim = -1) const;
+  OCTAVE_API FloatComplexMatrix sumsq (int dim = -1) const;
+  OCTAVE_API FloatMatrix abs (void) const;
 
-  FloatComplexMatrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API FloatComplexMatrix diag (octave_idx_type k = 0) const;
 
-  FloatComplexDiagMatrix diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API FloatComplexDiagMatrix
+  diag (octave_idx_type m, octave_idx_type n) const;
 
-  bool row_is_real_only (octave_idx_type) const;
-  bool column_is_real_only (octave_idx_type) const;
+  OCTAVE_API bool row_is_real_only (octave_idx_type) const;
+  OCTAVE_API bool column_is_real_only (octave_idx_type) const;
 
-  FloatComplexColumnVector row_min (void) const;
-  FloatComplexColumnVector row_max (void) const;
+  OCTAVE_API FloatComplexColumnVector row_min (void) const;
+  OCTAVE_API FloatComplexColumnVector row_max (void) const;
 
-  FloatComplexColumnVector row_min (Array<octave_idx_type>& index) const;
-  FloatComplexColumnVector row_max (Array<octave_idx_type>& index) const;
+  OCTAVE_API FloatComplexColumnVector
+  row_min (Array<octave_idx_type>& index) const;
+  OCTAVE_API FloatComplexColumnVector
+  row_max (Array<octave_idx_type>& index) const;
 
-  FloatComplexRowVector column_min (void) const;
-  FloatComplexRowVector column_max (void) const;
+  OCTAVE_API FloatComplexRowVector column_min (void) const;
+  OCTAVE_API FloatComplexRowVector column_max (void) const;
 
-  FloatComplexRowVector column_min (Array<octave_idx_type>& index) const;
-  FloatComplexRowVector column_max (Array<octave_idx_type>& index) const;
+  OCTAVE_API FloatComplexRowVector
+  column_min (Array<octave_idx_type>& index) const;
+  OCTAVE_API FloatComplexRowVector
+  column_max (Array<octave_idx_type>& index) const;
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const FloatComplexMatrix& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is,
-                                               FloatComplexMatrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const FloatComplexMatrix& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, FloatComplexMatrix& a);
 };
 
 extern OCTAVE_API FloatComplexMatrix conj (const FloatComplexMatrix& a);
--- a/liboctave/array/fCNDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fCNDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -616,7 +616,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_complex (os, a.elem (i));
+      octave::write_value<Complex> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -632,7 +632,7 @@
       FloatComplex tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<FloatComplex> (is);
+          tmp = octave::read_value<FloatComplex> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/fCNDArray.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fCNDArray.h	Sun May 16 09:44:35 2021 +0200
@@ -55,7 +55,7 @@
   template <typename U>
   FloatComplexNDArray (const Array<U>& a) : MArray<FloatComplex> (a) { }
 
-  FloatComplexNDArray (const charNDArray&);
+  OCTAVE_API FloatComplexNDArray (const charNDArray&);
 
   FloatComplexNDArray& operator = (const FloatComplexNDArray& a)
   {
@@ -65,77 +65,80 @@
 
   // unary operations
 
-  boolNDArray operator ! (void) const;
+  OCTAVE_API boolNDArray operator ! (void) const;
 
   // FIXME: this is not quite the right thing.
 
-  bool any_element_is_nan (void) const;
-  bool any_element_is_inf_or_nan (void) const;
-  bool all_elements_are_real (void) const;
-  bool all_integers (float& max_val, float& min_val) const;
-  bool too_large_for_float (void) const;
+  OCTAVE_API bool any_element_is_nan (void) const;
+  OCTAVE_API bool any_element_is_inf_or_nan (void) const;
+  OCTAVE_API bool all_elements_are_real (void) const;
+  OCTAVE_API bool all_integers (float& max_val, float& min_val) const;
+  OCTAVE_API bool too_large_for_float (void) const;
 
-  boolNDArray all (int dim = -1) const;
-  boolNDArray any (int dim = -1) const;
+  OCTAVE_API boolNDArray all (int dim = -1) const;
+  OCTAVE_API boolNDArray any (int dim = -1) const;
 
-  FloatComplexNDArray cumprod (int dim = -1) const;
-  FloatComplexNDArray cumsum (int dim = -1) const;
-  FloatComplexNDArray prod (int dim = -1) const;
-  ComplexNDArray dprod (int dim = -1) const;
-  FloatComplexNDArray sum (int dim = -1) const;
-  ComplexNDArray dsum (int dim = -1) const;
-  FloatComplexNDArray sumsq (int dim = -1) const;
-  FloatComplexNDArray concat (const FloatComplexNDArray& rb,
-                              const Array<octave_idx_type>& ra_idx);
-  FloatComplexNDArray concat (const FloatNDArray& rb,
-                              const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API FloatComplexNDArray cumprod (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray cumsum (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray prod (int dim = -1) const;
+  OCTAVE_API ComplexNDArray dprod (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray sum (int dim = -1) const;
+  OCTAVE_API ComplexNDArray dsum (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray sumsq (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray
+  concat (const FloatComplexNDArray& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API FloatComplexNDArray
+  concat (const FloatNDArray& rb, const Array<octave_idx_type>& ra_idx);
 
-  FloatComplexNDArray max (int dim = -1) const;
-  FloatComplexNDArray max (Array<octave_idx_type>& index, int dim = -1) const;
-  FloatComplexNDArray min (int dim = -1) const;
-  FloatComplexNDArray min (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray max (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray
+  max (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray min (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray
+  min (Array<octave_idx_type>& index, int dim = -1) const;
 
-  FloatComplexNDArray cummax (int dim = -1) const;
-  FloatComplexNDArray cummax (Array<octave_idx_type>& index,
-                              int dim = -1) const;
-  FloatComplexNDArray cummin (int dim = -1) const;
-  FloatComplexNDArray cummin (Array<octave_idx_type>& index,
-                              int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray cummax (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray
+  cummax (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray cummin (int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray
+  cummin (Array<octave_idx_type>& index, int dim = -1) const;
 
-  FloatComplexNDArray diff (octave_idx_type order = 1, int dim = -1) const;
+  OCTAVE_API FloatComplexNDArray
+  diff (octave_idx_type order = 1, int dim = -1) const;
 
-  FloatComplexNDArray& insert (const NDArray& a,
-                               octave_idx_type r, octave_idx_type c);
-  FloatComplexNDArray& insert (const FloatComplexNDArray& a,
-                               octave_idx_type r, octave_idx_type c);
-  FloatComplexNDArray& insert (const FloatComplexNDArray& a,
-                               const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API FloatComplexNDArray&
+  insert (const NDArray& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatComplexNDArray&
+  insert (const FloatComplexNDArray& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatComplexNDArray&
+  insert (const FloatComplexNDArray& a, const Array<octave_idx_type>& ra_idx);
 
-  FloatNDArray abs (void) const;
-  boolNDArray isnan (void) const;
-  boolNDArray isinf (void) const;
-  boolNDArray isfinite (void) const;
+  OCTAVE_API FloatNDArray abs (void) const;
+  OCTAVE_API boolNDArray isnan (void) const;
+  OCTAVE_API boolNDArray isinf (void) const;
+  OCTAVE_API boolNDArray isfinite (void) const;
 
   friend OCTAVE_API FloatComplexNDArray conj (const FloatComplexNDArray& a);
 
-  FloatComplexNDArray fourier (int dim = 1) const;
-  FloatComplexNDArray ifourier (int dim = 1) const;
+  OCTAVE_API FloatComplexNDArray fourier (int dim = 1) const;
+  OCTAVE_API FloatComplexNDArray ifourier (int dim = 1) const;
 
-  FloatComplexNDArray fourier2d (void) const;
-  FloatComplexNDArray ifourier2d (void) const;
+  OCTAVE_API FloatComplexNDArray fourier2d (void) const;
+  OCTAVE_API FloatComplexNDArray ifourier2d (void) const;
 
-  FloatComplexNDArray fourierNd (void) const;
-  FloatComplexNDArray ifourierNd (void) const;
+  OCTAVE_API FloatComplexNDArray fourierNd (void) const;
+  OCTAVE_API FloatComplexNDArray ifourierNd (void) const;
 
   FloatComplexNDArray squeeze (void) const
   { return MArray<FloatComplex>::squeeze (); }
 
-  static void increment_index (Array<octave_idx_type>& ra_idx,
-                               const dim_vector& dimensions,
-                               int start_dimension = 0);
+  static OCTAVE_API void
+  increment_index (Array<octave_idx_type>& ra_idx,
+                   const dim_vector& dimensions, int start_dimension = 0);
 
-  static octave_idx_type compute_index (Array<octave_idx_type>& ra_idx,
-                                        const dim_vector& dimensions);
+  static OCTAVE_API octave_idx_type
+  compute_index (Array<octave_idx_type>& ra_idx, const dim_vector& dimensions);
 
   // i/o
 
@@ -147,9 +150,10 @@
   //  bool all_elements_are_real (void) const;
   //  bool all_integers (float& max_val, float& min_val) const;
 
-  FloatComplexNDArray diag (octave_idx_type k = 0) const;
+  OCTAVE_API FloatComplexNDArray diag (octave_idx_type k = 0) const;
 
-  FloatComplexNDArray diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API FloatComplexNDArray
+  diag (octave_idx_type m, octave_idx_type n) const;
 
   FloatComplexNDArray& changesign (void)
   {
--- a/liboctave/array/fCRowVector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fCRowVector.h	Sun May 16 09:44:35 2021 +0200
@@ -70,60 +70,65 @@
     return *this;
   }
 
-  bool operator == (const FloatComplexRowVector& a) const;
-  bool operator != (const FloatComplexRowVector& a) const;
+  OCTAVE_API bool operator == (const FloatComplexRowVector& a) const;
+  OCTAVE_API bool operator != (const FloatComplexRowVector& a) const;
 
   // destructive insert/delete/reorder operations
 
-  FloatComplexRowVector& insert (const FloatRowVector& a, octave_idx_type c);
-  FloatComplexRowVector& insert (const FloatComplexRowVector& a,
-                                 octave_idx_type c);
+  OCTAVE_API FloatComplexRowVector&
+  insert (const FloatRowVector& a, octave_idx_type c);
+  OCTAVE_API FloatComplexRowVector&
+  insert (const FloatComplexRowVector& a, octave_idx_type c);
 
-  FloatComplexRowVector& fill (float val);
-  FloatComplexRowVector& fill (const FloatComplex& val);
-  FloatComplexRowVector& fill (float val,
-                               octave_idx_type c1, octave_idx_type c2);
-  FloatComplexRowVector& fill (const FloatComplex& val,
-                               octave_idx_type c1, octave_idx_type c2);
+  OCTAVE_API FloatComplexRowVector& fill (float val);
+  OCTAVE_API FloatComplexRowVector& fill (const FloatComplex& val);
+  OCTAVE_API FloatComplexRowVector&
+  fill (float val, octave_idx_type c1, octave_idx_type c2);
+  OCTAVE_API FloatComplexRowVector&
+  fill (const FloatComplex& val, octave_idx_type c1, octave_idx_type c2);
 
-  FloatComplexRowVector append (const FloatRowVector& a) const;
-  FloatComplexRowVector append (const FloatComplexRowVector& a) const;
+  OCTAVE_API FloatComplexRowVector append (const FloatRowVector& a) const;
+  OCTAVE_API FloatComplexRowVector
+  append (const FloatComplexRowVector& a) const;
 
-  FloatComplexColumnVector hermitian (void) const;
-  FloatComplexColumnVector transpose (void) const;
+  OCTAVE_API FloatComplexColumnVector hermitian (void) const;
+  OCTAVE_API FloatComplexColumnVector transpose (void) const;
 
-  friend FloatComplexRowVector conj (const FloatComplexRowVector& a);
+  friend OCTAVE_API FloatComplexRowVector
+  conj (const FloatComplexRowVector& a);
 
   // resize is the destructive equivalent for this one
 
-  FloatComplexRowVector extract (octave_idx_type c1, octave_idx_type c2) const;
+  OCTAVE_API FloatComplexRowVector
+  extract (octave_idx_type c1, octave_idx_type c2) const;
 
-  FloatComplexRowVector extract_n (octave_idx_type c1, octave_idx_type n) const;
+  OCTAVE_API FloatComplexRowVector
+  extract_n (octave_idx_type c1, octave_idx_type n) const;
 
   // row vector by row vector -> row vector operations
 
-  FloatComplexRowVector& operator += (const FloatRowVector& a);
-  FloatComplexRowVector& operator -= (const FloatRowVector& a);
+  OCTAVE_API FloatComplexRowVector& operator += (const FloatRowVector& a);
+  OCTAVE_API FloatComplexRowVector& operator -= (const FloatRowVector& a);
 
   // row vector by matrix -> row vector
 
-  friend FloatComplexRowVector operator * (const FloatComplexRowVector& a,
-      const FloatComplexMatrix& b);
+  friend OCTAVE_API FloatComplexRowVector
+  operator * (const FloatComplexRowVector& a, const FloatComplexMatrix& b);
 
-  friend FloatComplexRowVector operator * (const FloatRowVector& a,
-      const FloatComplexMatrix& b);
+  friend OCTAVE_API FloatComplexRowVector
+  operator * (const FloatRowVector& a, const FloatComplexMatrix& b);
 
   // other operations
 
-  FloatComplex min (void) const;
-  FloatComplex max (void) const;
+  OCTAVE_API FloatComplex min (void) const;
+  OCTAVE_API FloatComplex max (void) const;
 
   // i/o
 
-  friend std::ostream& operator << (std::ostream& os,
-                                    const FloatComplexRowVector& a);
-  friend std::istream& operator >> (std::istream& is,
-                                    FloatComplexRowVector& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const FloatComplexRowVector& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, FloatComplexRowVector& a);
 
   void resize (octave_idx_type n, const FloatComplex& rfv = FloatComplex (0))
   {
@@ -137,16 +142,16 @@
 
 // row vector by column vector -> scalar
 
-FloatComplex OCTAVE_API operator * (const FloatComplexRowVector& a,
-                                    const ColumnVector& b);
+OCTAVE_API FloatComplex
+operator * (const FloatComplexRowVector& a, const ColumnVector& b);
 
-FloatComplex OCTAVE_API operator * (const FloatComplexRowVector& a,
-                                    const FloatComplexColumnVector& b);
+OCTAVE_API FloatComplex
+operator * (const FloatComplexRowVector& a, const FloatComplexColumnVector& b);
 
 // other operations
 
-OCTAVE_API FloatComplexRowVector linspace (const FloatComplex& x1,
-    const FloatComplex& x2, octave_idx_type n);
+OCTAVE_API FloatComplexRowVector
+linspace (const FloatComplex& x1, const FloatComplex& x2, octave_idx_type n);
 
 MARRAY_FORWARD_DEFS (MArray, FloatComplexRowVector, FloatComplex)
 
--- a/liboctave/array/fColVector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fColVector.h	Sun May 16 09:44:35 2021 +0200
@@ -62,52 +62,56 @@
     return *this;
   }
 
-  bool operator == (const FloatColumnVector& a) const;
-  bool operator != (const FloatColumnVector& a) const;
+  OCTAVE_API bool operator == (const FloatColumnVector& a) const;
+  OCTAVE_API bool operator != (const FloatColumnVector& a) const;
 
   // destructive insert/delete/reorder operations
 
-  FloatColumnVector& insert (const FloatColumnVector& a, octave_idx_type r);
+  OCTAVE_API FloatColumnVector&
+  insert (const FloatColumnVector& a, octave_idx_type r);
 
-  FloatColumnVector& fill (float val);
-  FloatColumnVector& fill (float val, octave_idx_type r1, octave_idx_type r2);
+  OCTAVE_API FloatColumnVector& fill (float val);
+  OCTAVE_API FloatColumnVector&
+  fill (float val, octave_idx_type r1, octave_idx_type r2);
 
-  FloatColumnVector stack (const FloatColumnVector& a) const;
+  OCTAVE_API FloatColumnVector stack (const FloatColumnVector& a) const;
 
-  FloatRowVector transpose (void) const;
+  OCTAVE_API FloatRowVector transpose (void) const;
 
   friend OCTAVE_API FloatColumnVector real (const FloatComplexColumnVector& a);
   friend OCTAVE_API FloatColumnVector imag (const FloatComplexColumnVector& a);
 
   // resize is the destructive equivalent for this one
 
-  FloatColumnVector extract (octave_idx_type r1, octave_idx_type r2) const;
+  OCTAVE_API FloatColumnVector
+  extract (octave_idx_type r1, octave_idx_type r2) const;
 
-  FloatColumnVector extract_n (octave_idx_type r1, octave_idx_type n) const;
+  OCTAVE_API FloatColumnVector
+  extract_n (octave_idx_type r1, octave_idx_type n) const;
 
   // matrix by column vector -> column vector operations
 
-  friend OCTAVE_API FloatColumnVector operator * (const FloatMatrix& a,
-                                                  const FloatColumnVector& b);
+  friend OCTAVE_API FloatColumnVector
+  operator * (const FloatMatrix& a, const FloatColumnVector& b);
 
   // diagonal matrix by column vector -> column vector operations
 
-  friend OCTAVE_API FloatColumnVector operator * (const FloatDiagMatrix& a,
-                                                  const FloatColumnVector& b);
+  friend OCTAVE_API FloatColumnVector
+  operator * (const FloatDiagMatrix& a, const FloatColumnVector& b);
 
   // other operations
 
-  float min (void) const;
-  float max (void) const;
+  OCTAVE_API float min (void) const;
+  OCTAVE_API float max (void) const;
 
-  FloatColumnVector abs (void) const;
+  OCTAVE_API FloatColumnVector abs (void) const;
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const FloatColumnVector& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is,
-                                               FloatColumnVector& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const FloatColumnVector& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, FloatColumnVector& a);
 
   void resize (octave_idx_type n, const float& rfv = 0)
   {
--- a/liboctave/array/fDiagMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fDiagMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -66,53 +66,57 @@
   FloatDiagMatrix (const Array<float>& a, octave_idx_type r, octave_idx_type c)
     : MDiagArray2<float> (a, r, c) { }
 
-  bool operator == (const FloatDiagMatrix& a) const;
-  bool operator != (const FloatDiagMatrix& a) const;
+  OCTAVE_API bool operator == (const FloatDiagMatrix& a) const;
+  OCTAVE_API bool operator != (const FloatDiagMatrix& a) const;
 
-  FloatDiagMatrix& fill (float val);
-  FloatDiagMatrix& fill (float val, octave_idx_type beg, octave_idx_type end);
-  FloatDiagMatrix& fill (const FloatColumnVector& a);
-  FloatDiagMatrix& fill (const FloatRowVector& a);
-  FloatDiagMatrix& fill (const FloatColumnVector& a, octave_idx_type beg);
-  FloatDiagMatrix& fill (const FloatRowVector& a, octave_idx_type beg);
+  OCTAVE_API FloatDiagMatrix& fill (float val);
+  OCTAVE_API FloatDiagMatrix&
+  fill (float val, octave_idx_type beg, octave_idx_type end);
+  OCTAVE_API FloatDiagMatrix& fill (const FloatColumnVector& a);
+  OCTAVE_API FloatDiagMatrix& fill (const FloatRowVector& a);
+  OCTAVE_API FloatDiagMatrix&
+  fill (const FloatColumnVector& a, octave_idx_type beg);
+  OCTAVE_API FloatDiagMatrix&
+  fill (const FloatRowVector& a, octave_idx_type beg);
 
   FloatDiagMatrix transpose (void) const
   { return MDiagArray2<float>::transpose (); }
 
-  FloatDiagMatrix abs (void) const;
+  OCTAVE_API FloatDiagMatrix abs (void) const;
 
   friend OCTAVE_API FloatDiagMatrix real (const FloatComplexDiagMatrix& a);
   friend OCTAVE_API FloatDiagMatrix imag (const FloatComplexDiagMatrix& a);
 
   // resize is the destructive analog for this one
 
-  FloatMatrix extract (octave_idx_type r1, octave_idx_type c1,
-                       octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API FloatMatrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
   // extract row or column i.
 
-  FloatRowVector row (octave_idx_type i) const;
-  FloatRowVector row (char *s) const;
+  OCTAVE_API FloatRowVector row (octave_idx_type i) const;
+  OCTAVE_API FloatRowVector row (char *s) const;
 
-  FloatColumnVector column (octave_idx_type i) const;
-  FloatColumnVector column (char *s) const;
+  OCTAVE_API FloatColumnVector column (octave_idx_type i) const;
+  OCTAVE_API FloatColumnVector column (char *s) const;
 
-  FloatDiagMatrix inverse (void) const;
-  FloatDiagMatrix inverse (octave_idx_type& info) const;
-  FloatDiagMatrix pseudo_inverse (float tol = 0.0f) const;
+  OCTAVE_API FloatDiagMatrix inverse (void) const;
+  OCTAVE_API FloatDiagMatrix inverse (octave_idx_type& info) const;
+  OCTAVE_API FloatDiagMatrix pseudo_inverse (float tol = 0.0f) const;
 
   // other operations
 
   FloatColumnVector extract_diag (octave_idx_type k = 0) const
   { return MDiagArray2<float>::extract_diag (k); }
 
-  FloatDET determinant (void) const;
-  float rcond (void) const;
+  OCTAVE_API FloatDET determinant (void) const;
+  OCTAVE_API float rcond (void) const;
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const FloatDiagMatrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const FloatDiagMatrix& a);
 
 };
 
@@ -121,8 +125,8 @@
 
 // diagonal matrix by diagonal matrix -> diagonal matrix operations
 
-OCTAVE_API FloatDiagMatrix operator * (const FloatDiagMatrix& a,
-                                       const FloatDiagMatrix& b);
+OCTAVE_API FloatDiagMatrix
+operator * (const FloatDiagMatrix& a, const FloatDiagMatrix& b);
 
 MDIAGARRAY2_FORWARD_DEFS (MDiagArray2, FloatDiagMatrix, float)
 
--- a/liboctave/array/fMatrix.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fMatrix.cc	Sun May 16 09:44:35 2021 +0200
@@ -406,14 +406,14 @@
   if (r1 > r2) { std::swap (r1, r2); }
   if (c1 > c2) { std::swap (c1, c2); }
 
-  return index (idx_vector (r1, r2+1), idx_vector (c1, c2+1));
+  return index (octave::idx_vector (r1, r2+1), octave::idx_vector (c1, c2+1));
 }
 
 FloatMatrix
 FloatMatrix::extract_n (octave_idx_type r1, octave_idx_type c1,
                         octave_idx_type nr, octave_idx_type nc) const
 {
-  return index (idx_vector (r1, r1 + nr), idx_vector (c1, c1 + nc));
+  return index (octave::idx_vector (r1, r1 + nr), octave::idx_vector (c1, c1 + nc));
 }
 
 // extract row or column i.
@@ -421,13 +421,13 @@
 FloatRowVector
 FloatMatrix::row (octave_idx_type i) const
 {
-  return index (idx_vector (i), idx_vector::colon);
+  return index (octave::idx_vector (i), octave::idx_vector::colon);
 }
 
 FloatColumnVector
 FloatMatrix::column (octave_idx_type i) const
 {
-  return index (idx_vector::colon, idx_vector (i));
+  return index (octave::idx_vector::colon, octave::idx_vector (i));
 }
 
 // Local function to calculate the 1-norm.
@@ -2647,7 +2647,7 @@
       for (octave_idx_type j = 0; j < a.cols (); j++)
         {
           os << ' ';
-          octave_write_float (os, a.elem (i, j));
+          octave::write_value<float> (os, a.elem (i, j));
         }
       os << "\n";
     }
@@ -2666,7 +2666,7 @@
       for (octave_idx_type i = 0; i < nr; i++)
         for (octave_idx_type j = 0; j < nc; j++)
           {
-            tmp = octave_read_value<float> (is);
+            tmp = octave::read_value<float> (is);
             if (is)
               a.elem (i, j) = tmp;
             else
--- a/liboctave/array/fMatrix.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fMatrix.h	Sun May 16 09:44:35 2021 +0200
@@ -84,51 +84,52 @@
   template <typename U>
   FloatMatrix (const Array<U>& a) : FloatNDArray (a.as_matrix ()) { }
 
-  explicit FloatMatrix (const FloatRowVector& rv);
+  explicit OCTAVE_API FloatMatrix (const FloatRowVector& rv);
 
-  explicit FloatMatrix (const FloatColumnVector& cv);
+  explicit OCTAVE_API FloatMatrix (const FloatColumnVector& cv);
 
-  explicit FloatMatrix (const FloatDiagMatrix& a);
+  explicit OCTAVE_API FloatMatrix (const FloatDiagMatrix& a);
 
-  explicit FloatMatrix (const MDiagArray2<float>& a);
+  explicit OCTAVE_API FloatMatrix (const MDiagArray2<float>& a);
 
-  explicit FloatMatrix (const DiagArray2<float>& a);
+  explicit OCTAVE_API FloatMatrix (const DiagArray2<float>& a);
 
-  explicit FloatMatrix (const PermMatrix& a);
+  explicit OCTAVE_API FloatMatrix (const PermMatrix& a);
 
-  explicit FloatMatrix (const boolMatrix& a);
+  explicit OCTAVE_API FloatMatrix (const boolMatrix& a);
 
-  explicit FloatMatrix (const charMatrix& a);
+  explicit OCTAVE_API FloatMatrix (const charMatrix& a);
 
-  bool operator == (const FloatMatrix& a) const;
-  bool operator != (const FloatMatrix& a) const;
+  OCTAVE_API bool operator == (const FloatMatrix& a) const;
+  OCTAVE_API bool operator != (const FloatMatrix& a) const;
 
-  bool issymmetric (void) const;
+  OCTAVE_API bool issymmetric (void) const;
 
   // destructive insert/delete/reorder operations
 
-  FloatMatrix& insert (const FloatMatrix& a,
-                       octave_idx_type r, octave_idx_type c);
-  FloatMatrix& insert (const FloatRowVector& a,
-                       octave_idx_type r, octave_idx_type c);
-  FloatMatrix& insert (const FloatColumnVector& a,
-                       octave_idx_type r, octave_idx_type c);
-  FloatMatrix& insert (const FloatDiagMatrix& a,
-                       octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatMatrix&
+  insert (const FloatMatrix& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatMatrix&
+  insert (const FloatRowVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatMatrix&
+  insert (const FloatColumnVector& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatMatrix&
+  insert (const FloatDiagMatrix& a, octave_idx_type r, octave_idx_type c);
 
-  FloatMatrix& fill (float val);
-  FloatMatrix& fill (float val, octave_idx_type r1, octave_idx_type c1,
-                     octave_idx_type r2, octave_idx_type c2);
+  OCTAVE_API FloatMatrix& fill (float val);
+  OCTAVE_API FloatMatrix&
+  fill (float val, octave_idx_type r1, octave_idx_type c1,
+        octave_idx_type r2, octave_idx_type c2);
 
-  FloatMatrix append (const FloatMatrix& a) const;
-  FloatMatrix append (const FloatRowVector& a) const;
-  FloatMatrix append (const FloatColumnVector& a) const;
-  FloatMatrix append (const FloatDiagMatrix& a) const;
+  OCTAVE_API FloatMatrix append (const FloatMatrix& a) const;
+  OCTAVE_API FloatMatrix append (const FloatRowVector& a) const;
+  OCTAVE_API FloatMatrix append (const FloatColumnVector& a) const;
+  OCTAVE_API FloatMatrix append (const FloatDiagMatrix& a) const;
 
-  FloatMatrix stack (const FloatMatrix& a) const;
-  FloatMatrix stack (const FloatRowVector& a) const;
-  FloatMatrix stack (const FloatColumnVector& a) const;
-  FloatMatrix stack (const FloatDiagMatrix& a) const;
+  OCTAVE_API FloatMatrix stack (const FloatMatrix& a) const;
+  OCTAVE_API FloatMatrix stack (const FloatRowVector& a) const;
+  OCTAVE_API FloatMatrix stack (const FloatColumnVector& a) const;
+  OCTAVE_API FloatMatrix stack (const FloatDiagMatrix& a) const;
 
   friend OCTAVE_API FloatMatrix real (const FloatComplexMatrix& a);
   friend OCTAVE_API FloatMatrix imag (const FloatComplexMatrix& a);
@@ -140,17 +141,19 @@
 
   // resize is the destructive equivalent for this one
 
-  FloatMatrix extract (octave_idx_type r1, octave_idx_type c1,
-                       octave_idx_type r2, octave_idx_type c2) const;
+  OCTAVE_API FloatMatrix
+  extract (octave_idx_type r1, octave_idx_type c1,
+           octave_idx_type r2, octave_idx_type c2) const;
 
-  FloatMatrix extract_n (octave_idx_type r1, octave_idx_type c1,
-                         octave_idx_type nr, octave_idx_type nc) const;
+  OCTAVE_API FloatMatrix
+  extract_n (octave_idx_type r1, octave_idx_type c1,
+             octave_idx_type nr, octave_idx_type nc) const;
 
   // extract row or column i.
 
-  FloatRowVector row (octave_idx_type i) const;
+  OCTAVE_API FloatRowVector row (octave_idx_type i) const;
 
-  FloatColumnVector column (octave_idx_type i) const;
+  OCTAVE_API FloatColumnVector column (octave_idx_type i) const;
 
   void resize (octave_idx_type nr, octave_idx_type nc, float rfv = 0)
   {
@@ -165,33 +168,38 @@
                         float& rcon, bool force, bool calc_cond) const;
 
 public:
-  FloatMatrix inverse (void) const;
-  FloatMatrix inverse (octave_idx_type& info) const;
-  FloatMatrix inverse (octave_idx_type& info, float& rcon, bool force = false,
-                       bool calc_cond = true) const;
+  OCTAVE_API FloatMatrix inverse (void) const;
+  OCTAVE_API FloatMatrix inverse (octave_idx_type& info) const;
+  OCTAVE_API FloatMatrix
+  inverse (octave_idx_type& info, float& rcon, bool force = false,
+           bool calc_cond = true) const;
 
-  FloatMatrix inverse (MatrixType& mattype) const;
-  FloatMatrix inverse (MatrixType& mattype, octave_idx_type& info) const;
-  FloatMatrix inverse (MatrixType& mattype, octave_idx_type& info, float& rcon,
-                       bool force = false, bool calc_cond = true) const;
+  OCTAVE_API FloatMatrix inverse (MatrixType& mattype) const;
+  OCTAVE_API FloatMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info) const;
+  OCTAVE_API FloatMatrix
+  inverse (MatrixType& mattype, octave_idx_type& info, float& rcon,
+           bool force = false, bool calc_cond = true) const;
 
-  FloatMatrix pseudo_inverse (float tol = 0.0) const;
+  OCTAVE_API FloatMatrix pseudo_inverse (float tol = 0.0) const;
 
-  FloatComplexMatrix fourier (void) const;
-  FloatComplexMatrix ifourier (void) const;
+  OCTAVE_API FloatComplexMatrix fourier (void) const;
+  OCTAVE_API FloatComplexMatrix ifourier (void) const;
 
-  FloatComplexMatrix fourier2d (void) const;
-  FloatComplexMatrix ifourier2d (void) const;
+  OCTAVE_API FloatComplexMatrix fourier2d (void) const;
+  OCTAVE_API FloatComplexMatrix ifourier2d (void) const;
 
-  FloatDET determinant (void) const;
-  FloatDET determinant (octave_idx_type& info) const;
-  FloatDET determinant (octave_idx_type& info, float& rcon,
-                        bool calc_cond = true) const;
-  FloatDET determinant (MatrixType& mattype, octave_idx_type& info,
-                        float& rcon, bool calc_cond = true) const;
+  OCTAVE_API FloatDET determinant (void) const;
+  OCTAVE_API FloatDET determinant (octave_idx_type& info) const;
+  OCTAVE_API FloatDET
+  determinant (octave_idx_type& info, float& rcon,
+               bool calc_cond = true) const;
+  OCTAVE_API FloatDET
+  determinant (MatrixType& mattype, octave_idx_type& info, float& rcon,
+               bool calc_cond = true) const;
 
-  float rcond (void) const;
-  float rcond (MatrixType& mattype) const;
+  OCTAVE_API float rcond (void) const;
+  OCTAVE_API float rcond (MatrixType& mattype) const;
 
 private:
   // Upper triangular matrix solvers
@@ -216,162 +224,180 @@
 
 public:
   // Generic interface to solver with no probing of type
-  FloatMatrix solve (MatrixType& mattype, const FloatMatrix& b) const;
-  FloatMatrix solve (MatrixType& mattype, const FloatMatrix& b,
-                     octave_idx_type& info) const;
-  FloatMatrix solve (MatrixType& mattype, const FloatMatrix& b,
-                     octave_idx_type& info, float& rcon) const;
-  FloatMatrix solve (MatrixType& mattype, const FloatMatrix& b,
-                     octave_idx_type& info, float& rcon,
-                     solve_singularity_handler sing_handler,
-                     bool singular_fallback = true,
-                     blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatMatrix
+  solve (MatrixType& mattype, const FloatMatrix& b) const;
+  OCTAVE_API FloatMatrix
+  solve (MatrixType& mattype, const FloatMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API FloatMatrix
+  solve (MatrixType& mattype, const FloatMatrix& b, octave_idx_type& info,
+         float& rcon) const;
+  OCTAVE_API FloatMatrix
+  solve (MatrixType& mattype, const FloatMatrix& b, octave_idx_type& info,
+         float& rcon, solve_singularity_handler sing_handler,
+         bool singular_fallback = true,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexMatrix solve (MatrixType& mattype,
-                            const FloatComplexMatrix& b) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatComplexMatrix& b,
-                            octave_idx_type& info) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatComplexMatrix& b,
-                            octave_idx_type& info, float& rcon) const;
-  FloatComplexMatrix solve (MatrixType& mattype, const FloatComplexMatrix& b,
-                            octave_idx_type& info, float& rcon,
-                            solve_singularity_handler sing_handler,
-                            bool singular_fallback = true,
-                            blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatComplexMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatComplexMatrix& b,
+         octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatComplexMatrix& b,
+         octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (MatrixType& mattype, const FloatComplexMatrix& b,
+         octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler, bool singular_fallback = true,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatColumnVector solve (MatrixType& mattype, const FloatColumnVector& b) const;
-  FloatColumnVector solve (MatrixType& mattype, const FloatColumnVector& b,
-                           octave_idx_type& info) const;
-  FloatColumnVector solve (MatrixType& mattype, const FloatColumnVector& b,
-                           octave_idx_type& info, float& rcon) const;
-  FloatColumnVector solve (MatrixType& mattype, const FloatColumnVector& b,
-                           octave_idx_type& info, float& rcon,
-                           solve_singularity_handler sing_handler,
-                           blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatColumnVector
+  solve (MatrixType& mattype, const FloatColumnVector& b) const;
+  OCTAVE_API FloatColumnVector
+  solve (MatrixType& mattype, const FloatColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API FloatColumnVector
+  solve (MatrixType& mattype, const FloatColumnVector& b,
+         octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatColumnVector
+  solve (MatrixType& mattype, const FloatColumnVector& b,
+         octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatComplexColumnVector& b) const;
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatComplexColumnVector& b,
-                                  octave_idx_type& info) const;
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatComplexColumnVector& b,
-                                  octave_idx_type& info, float& rcon) const;
-  FloatComplexColumnVector solve (MatrixType& mattype,
-                                  const FloatComplexColumnVector& b,
-                                  octave_idx_type& info, float& rcon,
-                                  solve_singularity_handler sing_handler,
-                                  blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatComplexColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatComplexColumnVector& b,
+         octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatComplexColumnVector& b,
+         octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (MatrixType& mattype, const FloatComplexColumnVector& b,
+         octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
   // Generic interface to solver with probing of type
-  FloatMatrix solve (const FloatMatrix& b) const;
-  FloatMatrix solve (const FloatMatrix& b, octave_idx_type& info) const;
-  FloatMatrix solve (const FloatMatrix& b, octave_idx_type& info,
-                     float& rcon) const;
-  FloatMatrix solve (const FloatMatrix& b, octave_idx_type& info, float& rcon,
-                     solve_singularity_handler sing_handler,
-                     blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatMatrix solve (const FloatMatrix& b) const;
+  OCTAVE_API FloatMatrix
+  solve (const FloatMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API FloatMatrix
+  solve (const FloatMatrix& b, octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatMatrix
+  solve (const FloatMatrix& b, octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexMatrix solve (const FloatComplexMatrix& b) const;
-  FloatComplexMatrix solve (const FloatComplexMatrix& b,
-                            octave_idx_type& info) const;
-  FloatComplexMatrix solve (const FloatComplexMatrix& b, octave_idx_type& info,
-                            float& rcon) const;
-  FloatComplexMatrix solve (const FloatComplexMatrix& b, octave_idx_type& info,
-                            float& rcon,
-                            solve_singularity_handler sing_handler,
-                            blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexMatrix solve (const FloatComplexMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatComplexMatrix& b, octave_idx_type& info,
+         float& rcon) const;
+  OCTAVE_API FloatComplexMatrix
+  solve (const FloatComplexMatrix& b, octave_idx_type& info,
+         float& rcon, solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatColumnVector solve (const FloatColumnVector& b) const;
-  FloatColumnVector solve (const FloatColumnVector& b,
-                           octave_idx_type& info) const;
-  FloatColumnVector solve (const FloatColumnVector& b, octave_idx_type& info,
-                           float& rcon) const;
-  FloatColumnVector solve (const FloatColumnVector& b, octave_idx_type& info,
-                           float& rcon,
-                           solve_singularity_handler sing_handler,
-                           blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatColumnVector solve (const FloatColumnVector& b) const;
+  OCTAVE_API FloatColumnVector
+  solve (const FloatColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API FloatColumnVector
+  solve (const FloatColumnVector& b, octave_idx_type& info, float& rcon) const;
+  OCTAVE_API FloatColumnVector
+  solve (const FloatColumnVector& b, octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
-  FloatComplexColumnVector solve (const FloatComplexColumnVector& b) const;
-  FloatComplexColumnVector solve (const FloatComplexColumnVector& b,
-                                  octave_idx_type& info) const;
-  FloatComplexColumnVector solve (const FloatComplexColumnVector& b,
-                                  octave_idx_type& info,
-                                  float& rcon) const;
-  FloatComplexColumnVector solve (const FloatComplexColumnVector& b,
-                                  octave_idx_type& info,
-                                  float& rcon,
-                                  solve_singularity_handler sing_handler,
-                                  blas_trans_type transt = blas_no_trans) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatComplexColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatComplexColumnVector& b, octave_idx_type& info,
+         float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  solve (const FloatComplexColumnVector& b, octave_idx_type& info, float& rcon,
+         solve_singularity_handler sing_handler,
+         blas_trans_type transt = blas_no_trans) const;
 
   // Singular solvers
-  FloatMatrix lssolve (const FloatMatrix& b) const;
-  FloatMatrix lssolve (const FloatMatrix& b, octave_idx_type& info) const;
-  FloatMatrix lssolve (const FloatMatrix& b, octave_idx_type& info,
-                       octave_idx_type& rank) const;
-  FloatMatrix lssolve (const FloatMatrix& b, octave_idx_type& info,
-                       octave_idx_type& rank, float& rcon) const;
+  OCTAVE_API FloatMatrix lssolve (const FloatMatrix& b) const;
+  OCTAVE_API FloatMatrix
+  lssolve (const FloatMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API FloatMatrix
+  lssolve (const FloatMatrix& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API FloatMatrix
+  lssolve (const FloatMatrix& b, octave_idx_type& info,
+           octave_idx_type& rank, float& rcon) const;
 
-  FloatComplexMatrix lssolve (const FloatComplexMatrix& b) const;
-  FloatComplexMatrix lssolve (const FloatComplexMatrix& b,
-                              octave_idx_type& info) const;
-  FloatComplexMatrix lssolve (const FloatComplexMatrix& b,
-                              octave_idx_type& info,
-                              octave_idx_type& rank) const;
-  FloatComplexMatrix lssolve (const FloatComplexMatrix& b,
-                              octave_idx_type& info, octave_idx_type& rank,
-                              float& rcon) const;
+  OCTAVE_API FloatComplexMatrix lssolve (const FloatComplexMatrix& b) const;
+  OCTAVE_API FloatComplexMatrix
+  lssolve (const FloatComplexMatrix& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexMatrix
+  lssolve (const FloatComplexMatrix& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API FloatComplexMatrix
+ lssolve (const FloatComplexMatrix& b, octave_idx_type& info,
+          octave_idx_type& rank, float& rcon) const;
 
-  FloatColumnVector lssolve (const FloatColumnVector& b) const;
-  FloatColumnVector lssolve (const FloatColumnVector& b,
-                             octave_idx_type& info) const;
-  FloatColumnVector lssolve (const FloatColumnVector& b, octave_idx_type& info,
-                             octave_idx_type& rank) const;
-  FloatColumnVector lssolve (const FloatColumnVector& b, octave_idx_type& info,
-                             octave_idx_type& rank, float& rcon) const;
+  OCTAVE_API FloatColumnVector lssolve (const FloatColumnVector& b) const;
+  OCTAVE_API FloatColumnVector
+  lssolve (const FloatColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API FloatColumnVector
+  lssolve (const FloatColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API FloatColumnVector
+  lssolve (const FloatColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank, float& rcon) const;
 
-  FloatComplexColumnVector lssolve (const FloatComplexColumnVector& b) const;
-  FloatComplexColumnVector lssolve (const FloatComplexColumnVector& b,
-                                    octave_idx_type& info) const;
-  FloatComplexColumnVector lssolve (const FloatComplexColumnVector& b,
-                                    octave_idx_type& info,
-                                    octave_idx_type& rank) const;
-  FloatComplexColumnVector lssolve (const FloatComplexColumnVector& b,
-                                    octave_idx_type& info,
-                                    octave_idx_type& rank, float& rcon) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatComplexColumnVector& b) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatComplexColumnVector& b, octave_idx_type& info) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatComplexColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank) const;
+  OCTAVE_API FloatComplexColumnVector
+  lssolve (const FloatComplexColumnVector& b, octave_idx_type& info,
+           octave_idx_type& rank, float& rcon) const;
 
-  FloatMatrix& operator += (const FloatDiagMatrix& a);
-  FloatMatrix& operator -= (const FloatDiagMatrix& a);
+  OCTAVE_API FloatMatrix& operator += (const FloatDiagMatrix& a);
+  OCTAVE_API FloatMatrix& operator -= (const FloatDiagMatrix& a);
 
-  FloatMatrix cumprod (int dim = -1) const;
-  FloatMatrix cumsum (int dim = -1) const;
-  FloatMatrix prod (int dim = -1) const;
-  FloatMatrix sum (int dim = -1) const;
-  FloatMatrix sumsq (int dim = -1) const;
-  FloatMatrix abs (void) const;
+  OCTAVE_API FloatMatrix cumprod (int dim = -1) const;
+  OCTAVE_API FloatMatrix cumsum (int dim = -1) const;
+  OCTAVE_API FloatMatrix prod (int dim = -1) const;
+  OCTAVE_API FloatMatrix sum (int dim = -1) const;
+  OCTAVE_API FloatMatrix sumsq (int dim = -1) const;
+  OCTAVE_API FloatMatrix abs (void) const;
 
-  FloatMatrix diag (octave_idx_type k = 0) const;
+  OCTAVE_API FloatMatrix diag (octave_idx_type k = 0) const;
 
-  FloatDiagMatrix diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API FloatDiagMatrix diag (octave_idx_type m, octave_idx_type n) const;
 
-  FloatColumnVector row_min (void) const;
-  FloatColumnVector row_max (void) const;
+  OCTAVE_API FloatColumnVector row_min (void) const;
+  OCTAVE_API FloatColumnVector row_max (void) const;
 
-  FloatColumnVector row_min (Array<octave_idx_type>& index) const;
-  FloatColumnVector row_max (Array<octave_idx_type>& index) const;
+  OCTAVE_API FloatColumnVector row_min (Array<octave_idx_type>& index) const;
+  OCTAVE_API FloatColumnVector row_max (Array<octave_idx_type>& index) const;
 
-  FloatRowVector column_min (void) const;
-  FloatRowVector column_max (void) const;
+  OCTAVE_API FloatRowVector column_min (void) const;
+  OCTAVE_API FloatRowVector column_max (void) const;
 
-  FloatRowVector column_min (Array<octave_idx_type>& index) const;
-  FloatRowVector column_max (Array<octave_idx_type>& index) const;
+  OCTAVE_API FloatRowVector column_min (Array<octave_idx_type>& index) const;
+  OCTAVE_API FloatRowVector column_max (Array<octave_idx_type>& index) const;
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const FloatMatrix& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is,
-                                               FloatMatrix& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const FloatMatrix& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, FloatMatrix& a);
 };
 
 // Publish externally used friend functions.
--- a/liboctave/array/fNDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fNDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -594,7 +594,7 @@
   for (octave_idx_type i = 0; i < nel; i++)
     {
       os << ' ';
-      octave_write_float (os, a.elem (i));
+      octave::write_value<float> (os, a.elem (i));
       os << "\n";
     }
   return os;
@@ -610,7 +610,7 @@
       float tmp;
       for (octave_idx_type i = 0; i < nel; i++)
         {
-          tmp = octave_read_value<float> (is);
+          tmp = octave::read_value<float> (is);
           if (is)
             a.elem (i) = tmp;
           else
--- a/liboctave/array/fNDArray.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fNDArray.h	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
   template <typename U>
   explicit FloatNDArray (const intNDArray<U>& a) : MArray<float> (a) { }
 
-  FloatNDArray (const charNDArray&);
+  OCTAVE_API FloatNDArray (const charNDArray&);
 
   FloatNDArray& operator = (const FloatNDArray& a)
   {
@@ -69,68 +69,72 @@
 
   // unary operations
 
-  boolNDArray operator ! (void) const;
+  OCTAVE_API boolNDArray operator ! (void) const;
 
-  bool any_element_is_negative (bool = false) const;
-  bool any_element_is_positive (bool = false) const;
-  bool any_element_is_nan (void) const;
-  bool any_element_is_inf_or_nan (void) const;
-  bool any_element_not_one_or_zero (void) const;
-  bool all_elements_are_zero (void) const;
-  bool all_elements_are_int_or_inf_or_nan (void) const;
-  bool all_integers (float& max_val, float& min_val) const;
-  bool all_integers (void) const;
-  bool too_large_for_float (void) const;
+  OCTAVE_API bool any_element_is_negative (bool = false) const;
+  OCTAVE_API bool any_element_is_positive (bool = false) const;
+  OCTAVE_API bool any_element_is_nan (void) const;
+  OCTAVE_API bool any_element_is_inf_or_nan (void) const;
+  OCTAVE_API bool any_element_not_one_or_zero (void) const;
+  OCTAVE_API bool all_elements_are_zero (void) const;
+  OCTAVE_API bool all_elements_are_int_or_inf_or_nan (void) const;
+  OCTAVE_API bool all_integers (float& max_val, float& min_val) const;
+  OCTAVE_API bool all_integers (void) const;
+  OCTAVE_API bool too_large_for_float (void) const;
 
   // FIXME: this is not quite the right thing.
 
-  boolNDArray all (int dim = -1) const;
-  boolNDArray any (int dim = -1) const;
+  OCTAVE_API boolNDArray all (int dim = -1) const;
+  OCTAVE_API boolNDArray any (int dim = -1) const;
 
-  FloatNDArray cumprod (int dim = -1) const;
-  FloatNDArray cumsum (int dim = -1) const;
-  FloatNDArray prod (int dim = -1) const;
-  NDArray dprod (int dim = -1) const;
-  FloatNDArray sum (int dim = -1) const;
-  NDArray dsum (int dim = -1) const;
-  FloatNDArray sumsq (int dim = -1) const;
-  FloatNDArray concat (const FloatNDArray& rb,
-                       const Array<octave_idx_type>& ra_idx);
-  FloatComplexNDArray concat (const FloatComplexNDArray& rb,
-                              const Array<octave_idx_type>& ra_idx);
-  charNDArray concat (const charNDArray& rb,
-                      const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API FloatNDArray cumprod (int dim = -1) const;
+  OCTAVE_API FloatNDArray cumsum (int dim = -1) const;
+  OCTAVE_API FloatNDArray prod (int dim = -1) const;
+  OCTAVE_API NDArray dprod (int dim = -1) const;
+  OCTAVE_API FloatNDArray sum (int dim = -1) const;
+  OCTAVE_API NDArray dsum (int dim = -1) const;
+  OCTAVE_API FloatNDArray sumsq (int dim = -1) const;
+  OCTAVE_API FloatNDArray
+  concat (const FloatNDArray& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API FloatComplexNDArray
+  concat (const FloatComplexNDArray& rb, const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API charNDArray
+  concat (const charNDArray& rb, const Array<octave_idx_type>& ra_idx);
 
-  FloatNDArray max (int dim = -1) const;
-  FloatNDArray max (Array<octave_idx_type>& index, int dim = -1) const;
-  FloatNDArray min (int dim = -1) const;
-  FloatNDArray min (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API FloatNDArray max (int dim = -1) const;
+  OCTAVE_API FloatNDArray
+  max (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API FloatNDArray min (int dim = -1) const;
+  OCTAVE_API FloatNDArray
+  min (Array<octave_idx_type>& index, int dim = -1) const;
 
-  FloatNDArray cummax (int dim = -1) const;
-  FloatNDArray cummax (Array<octave_idx_type>& index, int dim = -1) const;
-  FloatNDArray cummin (int dim = -1) const;
-  FloatNDArray cummin (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API FloatNDArray cummax (int dim = -1) const;
+  OCTAVE_API FloatNDArray
+  cummax (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API FloatNDArray cummin (int dim = -1) const;
+  OCTAVE_API FloatNDArray
+  cummin (Array<octave_idx_type>& index, int dim = -1) const;
 
-  FloatNDArray diff (octave_idx_type order = 1, int dim = -1) const;
+  OCTAVE_API FloatNDArray diff (octave_idx_type order = 1, int dim = -1) const;
 
-  FloatNDArray& insert (const FloatNDArray& a,
-                        octave_idx_type r, octave_idx_type c);
-  FloatNDArray& insert (const FloatNDArray& a,
-                        const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API FloatNDArray&
+  insert (const FloatNDArray& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API FloatNDArray&
+  insert (const FloatNDArray& a, const Array<octave_idx_type>& ra_idx);
 
-  FloatNDArray abs (void) const;
-  boolNDArray isnan (void) const;
-  boolNDArray isinf (void) const;
-  boolNDArray isfinite (void) const;
+  OCTAVE_API FloatNDArray abs (void) const;
+  OCTAVE_API boolNDArray isnan (void) const;
+  OCTAVE_API boolNDArray isinf (void) const;
+  OCTAVE_API boolNDArray isfinite (void) const;
 
-  FloatComplexNDArray fourier (int dim = 1) const;
-  FloatComplexNDArray ifourier (int dim = 1) const;
+  OCTAVE_API FloatComplexNDArray fourier (int dim = 1) const;
+  OCTAVE_API FloatComplexNDArray ifourier (int dim = 1) const;
 
-  FloatComplexNDArray fourier2d (void) const;
-  FloatComplexNDArray ifourier2d (void) const;
+  OCTAVE_API FloatComplexNDArray fourier2d (void) const;
+  OCTAVE_API FloatComplexNDArray ifourier2d (void) const;
 
-  FloatComplexNDArray fourierNd (void) const;
-  FloatComplexNDArray ifourierNd (void) const;
+  OCTAVE_API FloatComplexNDArray fourierNd (void) const;
+  OCTAVE_API FloatComplexNDArray ifourierNd (void) const;
 
   friend OCTAVE_API FloatNDArray real (const FloatComplexNDArray& a);
   friend OCTAVE_API FloatNDArray imag (const FloatComplexNDArray& a);
@@ -139,22 +143,23 @@
 
   FloatNDArray squeeze (void) const { return MArray<float>::squeeze (); }
 
-  static void increment_index (Array<octave_idx_type>& ra_idx,
-                               const dim_vector& dimensions,
-                               int start_dimension = 0);
+  static OCTAVE_API void
+  increment_index (Array<octave_idx_type>& ra_idx,
+                   const dim_vector& dimensions, int start_dimension = 0);
 
-  static octave_idx_type compute_index (Array<octave_idx_type>& ra_idx,
-                                        const dim_vector& dimensions);
+  static OCTAVE_API octave_idx_type
+  compute_index (Array<octave_idx_type>& ra_idx, const dim_vector& dimensions);
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const FloatNDArray& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is, FloatNDArray& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const FloatNDArray& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, FloatNDArray& a);
 
-  FloatNDArray diag (octave_idx_type k = 0) const;
+  OCTAVE_API FloatNDArray diag (octave_idx_type k = 0) const;
 
-  FloatNDArray diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API FloatNDArray diag (octave_idx_type m, octave_idx_type n) const;
 
   FloatNDArray& changesign (void)
   {
--- a/liboctave/array/fRowVector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/fRowVector.h	Sun May 16 09:44:35 2021 +0200
@@ -60,45 +60,49 @@
     return *this;
   }
 
-  bool operator == (const FloatRowVector& a) const;
-  bool operator != (const FloatRowVector& a) const;
+  OCTAVE_API bool operator == (const FloatRowVector& a) const;
+  OCTAVE_API bool operator != (const FloatRowVector& a) const;
 
   // destructive insert/delete/reorder operations
 
-  FloatRowVector& insert (const FloatRowVector& a, octave_idx_type c);
+  OCTAVE_API FloatRowVector&
+  insert (const FloatRowVector& a, octave_idx_type c);
 
-  FloatRowVector& fill (float val);
-  FloatRowVector& fill (float val, octave_idx_type c1, octave_idx_type c2);
+  OCTAVE_API FloatRowVector& fill (float val);
+  OCTAVE_API FloatRowVector&
+  fill (float val, octave_idx_type c1, octave_idx_type c2);
 
-  FloatRowVector append (const FloatRowVector& a) const;
+  OCTAVE_API FloatRowVector append (const FloatRowVector& a) const;
 
-  FloatColumnVector transpose (void) const;
+  OCTAVE_API FloatColumnVector transpose (void) const;
 
   friend OCTAVE_API FloatRowVector real (const FloatComplexRowVector& a);
   friend OCTAVE_API FloatRowVector imag (const FloatComplexRowVector& a);
 
   // resize is the destructive equivalent for this one
 
-  FloatRowVector extract (octave_idx_type c1, octave_idx_type c2) const;
+  OCTAVE_API FloatRowVector
+  extract (octave_idx_type c1, octave_idx_type c2) const;
 
-  FloatRowVector extract_n (octave_idx_type c1, octave_idx_type n) const;
+  OCTAVE_API FloatRowVector
+  extract_n (octave_idx_type c1, octave_idx_type n) const;
 
   // row vector by matrix -> row vector
 
-  friend OCTAVE_API FloatRowVector operator * (const FloatRowVector& a,
-                                               const FloatMatrix& b);
+  friend OCTAVE_API FloatRowVector
+  operator * (const FloatRowVector& a, const FloatMatrix& b);
 
   // other operations
 
-  float min (void) const;
-  float max (void) const;
+  OCTAVE_API float min (void) const;
+  OCTAVE_API float max (void) const;
 
   // i/o
 
-  friend OCTAVE_API std::ostream& operator << (std::ostream& os,
-                                               const FloatRowVector& a);
-  friend OCTAVE_API std::istream& operator >> (std::istream& is,
-                                               FloatRowVector& a);
+  friend OCTAVE_API std::ostream&
+  operator << (std::ostream& os, const FloatRowVector& a);
+  friend OCTAVE_API std::istream&
+  operator >> (std::istream& is, FloatRowVector& a);
 
   void resize (octave_idx_type n, const float& rfv = 0)
   {
--- a/liboctave/array/idx-vector.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/idx-vector.cc	Sun May 16 09:44:35 2021 +0200
@@ -42,1292 +42,1238 @@
 #include "lo-error.h"
 #include "lo-mappers.h"
 
-OCTAVE_NORETURN static
-void
-err_invalid_range (void)
-{
-  (*current_liboctave_error_handler) ("invalid range used as index");
-}
-
-static void
-err_index_out_of_range (void)
+namespace octave
 {
-  (*current_liboctave_error_handler)
-    ("internal error: idx_vector index out of range");
-}
+  OCTAVE_NORETURN static void err_invalid_range (void)
+  {
+    (*current_liboctave_error_handler) ("invalid range used as index");
+  }
 
-idx_vector::idx_vector_rep *
-idx_vector::nil_rep (void)
-{
-  static idx_vector_rep ivr;
-  return &ivr;
-}
+  OCTAVE_NORETURN static void err_index_out_of_range (void)
+  {
+    (*current_liboctave_error_handler)
+      ("internal error: idx_vector index out of range");
+  }
 
-idx_vector::idx_vector_rep *
-idx_vector::err_rep (void)
-{
-  static idx_vector_rep ivr;
-  ivr.err = true;
-  return &ivr;
-}
+  idx_vector::idx_vector_rep * idx_vector::nil_rep (void)
+  {
+    static idx_vector_rep ivr;
+    return &ivr;
+  }
 
-Array<octave_idx_type>
-idx_vector::idx_base_rep::as_array (void)
-{
-  (*current_liboctave_error_handler)
-    ("internal error: as_array not allowed for this index class");
+  Array<octave_idx_type> idx_vector::idx_base_rep::as_array (void)
+  {
+    (*current_liboctave_error_handler)
+      ("internal error: as_array not allowed for this index class");
 
-  // Never actually executed, but required to silence compiler warning
-  return Array<octave_idx_type> ();
-}
+    // Never actually executed, but required to silence compiler warning
+    return Array<octave_idx_type> ();
+  }
 
-idx_vector::idx_colon_rep::idx_colon_rep (char c)
-  : idx_base_rep ()
-{
-  if (c != ':')
-    {
+  idx_vector::idx_colon_rep::idx_colon_rep (char c)
+    : idx_base_rep ()
+  {
+    if (c != ':')
       (*current_liboctave_error_handler)
         ("internal error: invalid character converted to idx_vector; must be ':'");
-      // FIXME: this is unreachable now.
-      err = true;
-    }
-}
-
-octave_idx_type
-idx_vector::idx_colon_rep::checkelem (octave_idx_type i) const
-{
-  if (i < 0)
-    err_index_out_of_range ();
-
-  return i;
-}
-
-idx_vector::idx_base_rep *
-idx_vector::idx_colon_rep::sort_idx (Array<octave_idx_type>&)
-{
-  (*current_liboctave_error_handler)
-    ("internal error: idx_colon_rep::sort_idx");
-}
-
-std::ostream&
-idx_vector::idx_colon_rep::print (std::ostream& os) const
-{
-  return os << ':';
-}
-
-idx_vector::idx_range_rep::idx_range_rep (octave_idx_type _start,
-                                          octave_idx_type _limit,
-                                          octave_idx_type _step)
-  : idx_base_rep (), start(_start),
-    len (_step ? std::max ((_limit - _start) / _step,
-                           static_cast<octave_idx_type> (0))
-               : -1),
-    step (_step)
-{
-  if (len < 0)
-    err_invalid_range ();
-  if (start < 0)
-    octave::err_invalid_index (start);
-  if (step < 0 && start + (len-1)*step < 0)
-    octave::err_invalid_index (start + (len-1)*step);
-}
-
-idx_vector::idx_range_rep::idx_range_rep (const Range& r)
-  : idx_base_rep (), start (0), len (r.numel ()), step (1)
-{
-  if (len < 0)
-    err_invalid_range ();
-
-  if (len > 0)
-    {
-      if (r.all_elements_are_ints ())
-        {
-          start = static_cast<octave_idx_type> (r.base ()) - 1;
-          step = static_cast<octave_idx_type> (r.inc ());
-          if (start < 0)
-            octave::err_invalid_index (start);
-          if (step < 0 && start + (len - 1)*step < 0)
-            octave::err_invalid_index (start + (len - 1)*step);
-        }
-      else
-        {
-          // find first non-integer, then gripe about it
-          double b = r.base ();
-          double inc = r.inc ();
-          octave::err_invalid_index (b != std::trunc (b) ? b : b + inc);
-        }
-    }
-}
-
-octave_idx_type
-idx_vector::idx_range_rep::checkelem (octave_idx_type i) const
-{
-  if (i < 0 || i >= len)
-    err_index_out_of_range ();
-
-  return start + i*step;
-}
-
-idx_vector::idx_base_rep *
-idx_vector::idx_range_rep::sort_uniq_clone (bool)
-{
-  if (step < 0)
-    return new idx_range_rep (start + (len - 1)*step, len, -step, DIRECT);
-  else
-    {
-      count++;
-      return this;
-    }
-}
+  }
 
-idx_vector::idx_base_rep *
-idx_vector::idx_range_rep::sort_idx (Array<octave_idx_type>& idx)
-{
-  if (step < 0 && len > 0)
-    {
-      idx.clear (1, len);
-      for (octave_idx_type i = 0; i < len; i++)
-        idx.xelem (i) = len - 1 - i;
-      return new idx_range_rep (start + (len - 1)*step, len, -step, DIRECT);
-    }
-  else
-    {
-      idx.clear (1, len);
-      for (octave_idx_type i = 0; i < len; i++)
-        idx.xelem (i) = i;
-      count++;
-      return this;
-    }
-}
-
-std::ostream&
-idx_vector::idx_range_rep::print (std::ostream& os) const
-{
-  os << start << ':' << step << ':' << start + len*step;
-  return os;
-}
-
-Range
-idx_vector::idx_range_rep::unconvert (void) const
-{
-  return Range (static_cast<double> (start+1),
-                static_cast<double> (step), len);
-}
-
-Array<octave_idx_type>
-idx_vector::idx_range_rep::as_array (void)
-{
-  Array<octave_idx_type> retval (dim_vector (1, len));
-  for (octave_idx_type i = 0; i < len; i++)
-    retval.xelem (i) = start + i*step;
-
-  return retval;
-}
-
-inline octave_idx_type
-convert_index (octave_idx_type i, bool& conv_error,
-               octave_idx_type& ext)
-{
-  if (i <= 0 && ! conv_error)
-    octave::err_invalid_index (i-1);
-
-  if (ext < i)
-    ext = i;
-
-  return i - 1;
-}
+  octave_idx_type
+  idx_vector::idx_colon_rep::checkelem (octave_idx_type i) const
+  {
+    if (i < 0)
+      err_index_out_of_range ();
 
-inline octave_idx_type
-convert_index (double x, bool& conv_error, octave_idx_type& ext)
-{
-  octave_idx_type i = static_cast<octave_idx_type> (x);
-
-  if (static_cast<double> (i) != x)
-    octave::err_invalid_index (x-1);
-
-  return convert_index (i, conv_error, ext);
-}
-
-inline octave_idx_type
-convert_index (float x, bool& conv_error, octave_idx_type& ext)
-{
-  return convert_index (static_cast<double> (x), conv_error, ext);
-}
-
-template <typename T>
-inline octave_idx_type
-convert_index (octave_int<T> x, bool& conv_error,
-               octave_idx_type& ext)
-{
-  octave_idx_type i = octave_int<octave_idx_type> (x).value ();
-
-  return convert_index (i, conv_error, ext);
-}
-
-template <typename T>
-idx_vector::idx_scalar_rep::idx_scalar_rep (T x)
-  : idx_base_rep (), data (0)
-{
-  octave_idx_type dummy = 0;
-
-  data = convert_index (x, err, dummy);
-}
-
-idx_vector::idx_scalar_rep::idx_scalar_rep (octave_idx_type i)
-  : idx_base_rep (), data (i)
-{
-  if (data < 0)
-    octave::err_invalid_index (data);
-}
-
-octave_idx_type
-idx_vector::idx_scalar_rep::checkelem (octave_idx_type i) const
-{
-  if (i != 0)
-    err_index_out_of_range ();
-
-  return data;
-}
-
-idx_vector::idx_base_rep *
-idx_vector::idx_scalar_rep::sort_idx (Array<octave_idx_type>& idx)
-{
-  idx.clear (1, 1);
-  idx.fill (0);
-  count++;
-  return this;
-}
-
-std::ostream& idx_vector::idx_scalar_rep::print (std::ostream& os) const
-{
-  return os << data;
-}
+    return i;
+  }
 
-double
-idx_vector::idx_scalar_rep::unconvert (void) const
-{
-  return data + 1;
-}
-
-Array<octave_idx_type>
-idx_vector::idx_scalar_rep::as_array (void)
-{
-  return Array<octave_idx_type> (dim_vector (1, 1), data);
-}
-
-template <typename T>
-idx_vector::idx_vector_rep::idx_vector_rep (const Array<T>& nda)
-  : idx_base_rep (), data (nullptr), len (nda.numel ()), ext (0),
-    aowner (nullptr), orig_dims (nda.dims ())
-{
-  if (len != 0)
-    {
-      std::unique_ptr<octave_idx_type []> d (new octave_idx_type [len]);
-
-      for (octave_idx_type i = 0; i < len; i++)
-        d[i] = convert_index (nda.xelem (i), err, ext);
-
-      data = d.release ();
-    }
-}
-
-// Note that this makes a shallow copy of the index array.
-
-idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda)
-  : idx_base_rep (), data (inda.data ()), len (inda.numel ()), ext (0),
-    aowner (new Array<octave_idx_type> (inda)), orig_dims (inda.dims ())
-{
-  if (len != 0)
-    {
-      octave_idx_type max = -1;
-      for (octave_idx_type i = 0; i < len; i++)
-        {
-          octave_idx_type k = inda.xelem (i);
-          if (k < 0)
-            {
-              if (! err)
-                octave::err_invalid_index (k);
-            }
-          else if (k > max)
-            max = k;
-        }
-
-      ext = max + 1;
-    }
-}
-
-idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda,
-                                            octave_idx_type _ext, direct)
-  : idx_base_rep (), data (inda.data ()), len (inda.numel ()), ext (_ext),
-    aowner (new Array<octave_idx_type> (inda)), orig_dims (inda.dims ())
-{
-  // No checking.
-  if (ext < 0)
-    {
-      octave_idx_type max = -1;
-      for (octave_idx_type i = 0; i < len; i++)
-        if (data[i] > max)
-          max = data[i];
-
-      ext = max + 1;
-    }
-}
-
-idx_vector::idx_vector_rep::idx_vector_rep (bool b)
-  : idx_base_rep (), data (nullptr), len (b ? 1 : 0), ext (0),
-    aowner (nullptr), orig_dims (len, len)
-{
-  if (len != 0)
-    {
-      octave_idx_type *d = new octave_idx_type [1];
-      d[0] = 0;
-      data = d;
-      ext = 1;
-    }
-}
-
-idx_vector::idx_vector_rep::idx_vector_rep (const Array<bool>& bnda,
-                                            octave_idx_type nnz)
-  : idx_base_rep (), data (nullptr), len (nnz), ext (0), aowner (nullptr),
-    orig_dims ()
-{
-  if (nnz < 0)
-    len = bnda.nnz ();
-
-  const dim_vector dv = bnda.dims ();
-
-  orig_dims = dv.make_nd_vector (len);
-
-  if (len != 0)
-    {
-      octave_idx_type *d = new octave_idx_type [len];
-
-      octave_idx_type ntot = bnda.numel ();
-
-      octave_idx_type k = 0;
-      for (octave_idx_type i = 0; i < ntot; i++)
-        if (bnda.xelem (i))
-          d[k++] = i;
-
-      data = d;
-
-      ext = d[k-1] + 1;
-    }
-}
+  idx_vector::idx_base_rep *
+  idx_vector::idx_colon_rep::sort_idx (Array<octave_idx_type>&)
+  {
+    (*current_liboctave_error_handler)
+      ("internal error: idx_colon_rep::sort_idx");
+  }
 
-idx_vector::idx_vector_rep::idx_vector_rep (const Sparse<bool>& bnda)
-  : idx_base_rep (), data (nullptr), len (bnda.nnz ()), ext (0),
-    aowner (nullptr), orig_dims ()
-{
-  const dim_vector dv = bnda.dims ();
-
-  orig_dims = dv.make_nd_vector (len);
-
-  if (len != 0)
-    {
-      octave_idx_type *d = new octave_idx_type [len];
-
-      octave_idx_type k = 0;
-      octave_idx_type nc = bnda.cols ();
-      octave_idx_type nr = bnda.rows ();
-
-      for (octave_idx_type j = 0; j < nc; j++)
-        for (octave_idx_type i = bnda.cidx (j); i < bnda.cidx (j+1); i++)
-          if (bnda.data (i))
-            d[k++] = j * nr + bnda.ridx (i);
-
-      data = d;
-
-      ext = d[k-1] + 1;
-    }
-}
-
-idx_vector::idx_vector_rep::~idx_vector_rep (void)
-{
-  if (aowner)
-    delete aowner;
-  else
-    delete [] data;
-}
-
-octave_idx_type
-idx_vector::idx_vector_rep::checkelem (octave_idx_type n) const
-{
-  if (n < 0 || n >= len)
-    octave::err_invalid_index (n);
-
-  return xelem (n);
-}
-
-idx_vector::idx_base_rep *
-idx_vector::idx_vector_rep::sort_uniq_clone (bool uniq)
-{
-  if (len == 0)
-    {
-      count++;
-      return this;
-    }
-
-  // This is wrapped in unique_ptr so that we don't leak on out-of-memory.
-  std::unique_ptr<idx_vector_rep> new_rep
-    (new idx_vector_rep (nullptr, len, ext, orig_dims, DIRECT));
-
-  if (ext > len*octave::math::log2 (1.0 + len))
-    {
-      // Use standard sort via octave_sort.
-      octave_idx_type *new_data = new octave_idx_type [len];
-      new_rep->data = new_data;
-
-      std::copy_n (data, len, new_data);
-      octave_sort<octave_idx_type> lsort;
-      lsort.set_compare (ASCENDING);
-      lsort.sort (new_data, len);
-
-      if (uniq)
-        {
-          octave_idx_type new_len = std::unique (new_data, new_data + len)
-                                    - new_data;
-          new_rep->len = new_len;
-          if (new_rep->orig_dims.ndims () == 2 && new_rep->orig_dims(0) == 1)
-            new_rep->orig_dims = dim_vector (1, new_len);
-          else
-            new_rep->orig_dims = dim_vector (new_len, 1);
-        }
-    }
-  else if (uniq)
-    {
-      // Use two-pass bucket sort (only a mask array needed).
-      OCTAVE_LOCAL_BUFFER_INIT (bool, has, ext, false);
-      for (octave_idx_type i = 0; i < len; i++)
-        has[data[i]] = true;
-
-      octave_idx_type new_len = 0;
-      for (octave_idx_type i = 0; i < ext; i++)
-        new_len += has[i];
-
-      new_rep->len = new_len;
-      if (new_rep->orig_dims.ndims () == 2 && new_rep->orig_dims(0) == 1)
-        new_rep->orig_dims = dim_vector (1, new_len);
-      else
-        new_rep->orig_dims = dim_vector (new_len, 1);
-
-      octave_idx_type *new_data = new octave_idx_type [new_len];
-      new_rep->data = new_data;
-
-      for (octave_idx_type i = 0, j = 0; i < ext; i++)
-        if (has[i])
-          new_data[j++] = i;
-    }
-  else
-    {
-      // Use two-pass bucket sort.
-      OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, cnt, ext, 0);
-      for (octave_idx_type i = 0; i < len; i++)
-        cnt[data[i]]++;
-
-      octave_idx_type *new_data = new octave_idx_type [len];
-      new_rep->data = new_data;
+  std::ostream& idx_vector::idx_colon_rep::print (std::ostream& os) const
+  {
+    return os << ':';
+  }
 
-      for (octave_idx_type i = 0, j = 0; i < ext; i++)
-        {
-          for (octave_idx_type k = 0; k < cnt[i]; k++)
-            new_data[j++] = i;
-        }
-    }
-
-  return new_rep.release ();
-}
-
-idx_vector::idx_base_rep *
-idx_vector::idx_vector_rep::sort_idx (Array<octave_idx_type>& idx)
-{
-  // This is wrapped in unique_ptr so that we don't leak on out-of-memory.
-  std::unique_ptr<idx_vector_rep> new_rep
-    (new idx_vector_rep (nullptr, len, ext, orig_dims, DIRECT));
-
-  if (ext > len*octave::math::log2 (1.0 + len))
-    {
-      // Use standard sort via octave_sort.
-      idx.clear (orig_dims);
-      octave_idx_type *idx_data = idx.fortran_vec ();
-      for (octave_idx_type i = 0; i < len; i++)
-        idx_data[i] = i;
-
-      octave_idx_type *new_data = new octave_idx_type [len];
-      new_rep->data = new_data;
-      std::copy_n (data, len, new_data);
-
-      octave_sort<octave_idx_type> lsort;
-      lsort.set_compare (ASCENDING);
-      lsort.sort (new_data, idx_data, len);
-    }
-  else
-    {
-      // Use two-pass bucket sort.
-      OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, cnt, ext, 0);
-
-      for (octave_idx_type i = 0; i < len; i++)
-        cnt[data[i]]++;
-
-      idx.clear (orig_dims);
-      octave_idx_type *idx_data = idx.fortran_vec ();
-
-      octave_idx_type *new_data = new octave_idx_type [len];
-      new_rep->data = new_data;
-
-      for (octave_idx_type i = 0, k = 0; i < ext; i++)
-        {
-          octave_idx_type j = cnt[i];
-          cnt[i] = k;
-          k += j;
-        }
-
-      for (octave_idx_type i = 0; i < len; i++)
-        {
-          octave_idx_type j = data[i];
-          octave_idx_type k = cnt[j]++;
-          new_data[k] = j;
-          idx_data[k] = i;
-        }
-    }
-
-  return new_rep.release ();
-}
-
-std::ostream&
-idx_vector::idx_vector_rep::print (std::ostream& os) const
-{
-  os << '[';
-
-  for (octave_idx_type i = 0; i < len - 1; i++)
-    os << data[i] << ',' << ' ';
-
-  if (len > 0)
-    os << data[len-1];
-
-  os << ']';
-
-  return os;
-}
-
-Array<double>
-idx_vector::idx_vector_rep::unconvert (void) const
-{
-  Array<double> retval (orig_dims);
-  for (octave_idx_type i = 0; i < len; i++)
-    retval.xelem (i) = data[i] + 1;
-  return retval;
-}
-
-Array<octave_idx_type>
-idx_vector::idx_vector_rep::as_array (void)
-{
-  if (aowner)
-    return *aowner;
-  else
-    {
-      Array<octave_idx_type> retval (orig_dims);
-
-      if (data)
-        {
-          std::memcpy (retval.fortran_vec (), data, len*sizeof (octave_idx_type));
-          // Delete the old copy and share the data instead to save memory.
-          delete [] data;
-        }
-
-      data = retval.fortran_vec ();
-      aowner = new Array<octave_idx_type> (retval);
-
-      return retval;
-    }
-}
-
-idx_vector::idx_mask_rep::idx_mask_rep (bool b)
-  : idx_base_rep (), data (nullptr), len (b ? 1 : 0), ext (0),
-    lsti (-1), lste (-1), aowner (nullptr), orig_dims (len, len)
-{
-  if (len != 0)
-    {
-      bool *d = new bool [1];
-      d[0] = true;
-      data = d;
-      ext = 1;
-    }
-}
-
-idx_vector::idx_mask_rep::idx_mask_rep (const Array<bool>& bnda,
-                                        octave_idx_type nnz)
-  : idx_base_rep (), data (nullptr), len (nnz), ext (bnda.numel ()),
-    lsti (-1), lste (-1), aowner (nullptr), orig_dims ()
-{
-  if (nnz < 0)
-    len = bnda.nnz ();
-
-  // We truncate the extent as much as possible.  For Matlab
-  // compatibility, but maybe it's not a bad idea anyway.
-  while (ext > 0 && ! bnda(ext-1))
-    ext--;
-
-  const dim_vector dv = bnda.dims ();
-
-  orig_dims = dv.make_nd_vector (len);
-
-  aowner = new Array<bool> (bnda);
-  data = bnda.data ();
-}
-
-idx_vector::idx_mask_rep::~idx_mask_rep (void)
-{
-  if (aowner)
-    delete aowner;
-  else
-    delete [] data;
-}
-
-octave_idx_type
-idx_vector::idx_mask_rep::xelem (octave_idx_type n) const
-{
-  if (n == lsti + 1)
-    {
-      lsti = n;
-      while (! data[++lste]) ;
-    }
-  else
-    {
-      lsti = n++;
-      lste = -1;
-      while (n > 0)
-        if (data[++lste]) --n;
-    }
-  return lste;
-}
-
-octave_idx_type
-idx_vector::idx_mask_rep::checkelem (octave_idx_type n) const
-{
-  if (n < 0 || n >= len)
-    octave::err_invalid_index (n);
-
-  return xelem (n);
-}
-
-std::ostream&
-idx_vector::idx_mask_rep::print (std::ostream& os) const
-{
-  os << '[';
-
-  for (octave_idx_type i = 0; i < ext - 1; i++)
-    os << data[i] << ',' << ' ';
-
-  if (ext > 0)
-    os << data[ext-1];
-
-  os << ']';
-
-  return os;
-}
-
-Array<bool>
-idx_vector::idx_mask_rep::unconvert (void) const
-{
-  if (aowner)
-    return *aowner;
-  else
-    {
-      Array<bool> retval (dim_vector (ext, 1));
-      for (octave_idx_type i = 0; i < ext; i++)
-        retval.xelem (i) = data[i];
-      return retval;
-    }
-}
+  idx_vector::idx_range_rep::idx_range_rep (octave_idx_type start,
+                                            octave_idx_type limit,
+                                            octave_idx_type step)
+    : idx_base_rep (), m_start(start),
+      m_len (step ? std::max ((limit - start) / step,
+                              static_cast<octave_idx_type> (0))
+             : -1),
+      m_step (step)
+  {
+    if (m_len < 0)
+      err_invalid_range ();
+    if (m_start < 0)
+      err_invalid_index (m_start);
+    if (m_step < 0 && m_start + (m_len-1)*m_step < 0)
+      err_invalid_index (m_start + (m_len-1)*m_step);
+  }
 
-Array<octave_idx_type>
-idx_vector::idx_mask_rep::as_array (void)
-{
-  if (aowner)
-    return aowner->find ().reshape (orig_dims);
-  else
-    {
-      Array<bool> retval (orig_dims);
-      for (octave_idx_type i = 0, j = 0; i < ext; i++)
-        if (data[i])
-          retval.xelem (j++) = i;
-
-      return retval;
-    }
-}
-
-idx_vector::idx_base_rep *
-idx_vector::idx_mask_rep::sort_idx (Array<octave_idx_type>& idx)
-{
-  idx.clear (len, 1);
-  for (octave_idx_type i = 0; i < len; i++)
-    idx.xelem (i) = i;
-
-  count++;
-  return this;
-}
-
-const idx_vector idx_vector::colon (new idx_vector::idx_colon_rep ());
-
-idx_vector::idx_vector (const Array<bool>& bnda)
-  : rep (nullptr)
-{
-  // Convert only if it means saving at least half the memory.
-  static const int factor = (2 * sizeof (octave_idx_type));
-  octave_idx_type nnz = bnda.nnz ();
-  if (nnz <= bnda.numel () / factor)
-    rep = new idx_vector_rep (bnda, nnz);
-  else
-    rep = new idx_mask_rep (bnda, nnz);
-}
-
-bool
-idx_vector::maybe_reduce (octave_idx_type n, const idx_vector& j,
-                          octave_idx_type nj)
-{
-  bool reduced = false;
-
-  // Empty index always reduces.
-  if (rep->length (n) == 0)
-    {
-      *this = idx_vector ();
-      return true;
-    }
+  idx_vector::idx_range_rep::idx_range_rep (const range<double>& r)
+    : idx_base_rep (), m_start (0), m_len (r.numel ()), m_step (1)
+  {
+    if (m_len < 0)
+      err_invalid_range ();
 
-  // Possibly skip singleton dims.
-  if (n == 1 && rep->is_colon_equiv (n))
-    {
-      *this = j;
-      return true;
-    }
-
-  if (nj == 1 && j.is_colon_equiv (nj))
-    return true;
-
-  switch (j.idx_class ())
-    {
-    case class_colon:
-      switch (rep->idx_class ())
-        {
-        case class_colon:
-          // (:,:) reduces to (:)
-          reduced = true;
-          break;
-
-        case class_scalar:
-          {
-            // (i,:) reduces to a range.
-            idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-            octave_idx_type k = r->get_data ();
-            *this = new idx_range_rep (k, nj, n, DIRECT);
-            reduced = true;
-          }
-          break;
-
-        case class_range:
-          {
-            // (i:k:end,:) reduces to a range if i <= k and k divides n.
-            idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-            octave_idx_type s = r->get_start ();
-            octave_idx_type l = r->length (n);
-            octave_idx_type t = r->get_step ();
-            if (l*t == n)
-              {
-                *this = new idx_range_rep (s, l * nj, t, DIRECT);
-                reduced = true;
-              }
-          }
-          break;
-
-        default:
-          break;
-        }
-      break;
-
-    case class_range:
-      switch (rep->idx_class ())
-        {
-        case class_colon:
+    if (m_len > 0)
+      {
+        if (r.all_elements_are_ints ())
           {
-            // (:,i:j) reduces to a range (the step must be 1)
-            idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.rep);
-            if (rj->get_step () == 1)
-              {
-                octave_idx_type sj = rj->get_start ();
-                octave_idx_type lj = rj->length (nj);
-                *this = new idx_range_rep (sj * n, lj * n, 1, DIRECT);
-                reduced = true;
-              }
-          }
-          break;
-
-        case class_scalar:
-          {
-            // (k,i:d:j) reduces to a range.
-            idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-            idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.rep);
-            octave_idx_type k = r->get_data ();
-            octave_idx_type sj = rj->get_start ();
-            octave_idx_type lj = rj->length (nj);
-            octave_idx_type tj = rj->get_step ();
-            *this = new idx_range_rep (n * sj + k, lj, n * tj, DIRECT);
-            reduced = true;
+            m_start = static_cast<octave_idx_type> (r.base ()) - 1;
+            m_step = static_cast<octave_idx_type> (r.increment ());
+            if (m_start < 0)
+              err_invalid_index (m_start);
+            if (m_step < 0 && m_start + (m_len - 1)*m_step < 0)
+              err_invalid_index (m_start + (m_len - 1)*m_step);
           }
-          break;
-
-        case class_range:
-          {
-            // (i:k:end,p:q) reduces to a range if i <= k and k divides n.
-            // (ones (1, m), ones (1, n)) reduces to (ones (1, m*n))
-            idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-            octave_idx_type s = r->get_start ();
-            octave_idx_type l = r->length (n);
-            octave_idx_type t = r->get_step ();
-            idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.rep);
-            octave_idx_type sj = rj->get_start ();
-            octave_idx_type lj = rj->length (nj);
-            octave_idx_type tj = rj->get_step ();
-            if ((l*t == n && tj == 1) || (t == 0 && tj == 0))
-              {
-                *this = new idx_range_rep (s + n * sj, l * lj, t, DIRECT);
-                reduced = true;
-              }
-          }
-          break;
-
-        default:
-          break;
-        }
-      break;
-
-    case class_scalar:
-      switch (rep->idx_class ())
-        {
-        case class_scalar:
+        else
           {
-            // (i,j) reduces to a single index.
-            idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-            idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.rep);
-            octave_idx_type k = r->get_data () + n * rj->get_data ();
-            *this = new idx_scalar_rep (k, DIRECT);
-            reduced = true;
-          }
-          break;
-
-        case class_range:
-          {
-            // (i:d:j,k) reduces to a range.
-            idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-            idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.rep);
-            octave_idx_type s = r->get_start ();
-            octave_idx_type l = r->length (nj);
-            octave_idx_type t = r->get_step ();
-            octave_idx_type k = rj->get_data ();
-            *this = new idx_range_rep (n * k + s, l, t, DIRECT);
-            reduced = true;
-          }
-          break;
-
-        case class_colon:
-          {
-            // (:,k) reduces to a range.
-            idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.rep);
-            octave_idx_type k = rj->get_data ();
-            *this = new idx_range_rep (n * k, n, 1, DIRECT);
-            reduced = true;
-          }
-          break;
-
-        default:
-          break;
-        }
-      break;
-
-    default:
-      break;
-    }
-
-  return reduced;
-}
-
-bool
-idx_vector::is_cont_range (octave_idx_type n,
-                           octave_idx_type& l, octave_idx_type& u) const
-{
-  bool res = false;
-
-  switch (rep->idx_class ())
-    {
-    case class_colon:
-      l = 0; u = n;
-      res = true;
-      break;
-
-    case class_range:
-      {
-        idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-        if (r->get_step () == 1)
-          {
-            l = r->get_start ();
-            u = l + r->length (n);
-            res = true;
+            // find first non-integer, then gripe about it
+            double b = r.base ();
+            double inc = r.increment ();
+            err_invalid_index (b != std::trunc (b) ? b : b + inc);
           }
       }
-      break;
+  }
+
+  octave_idx_type
+  idx_vector::idx_range_rep::checkelem (octave_idx_type i) const
+  {
+    if (i < 0 || i >= m_len)
+      err_index_out_of_range ();
+
+    return m_start + i*m_step;
+  }
 
-    case class_scalar:
+  idx_vector::idx_base_rep * idx_vector::idx_range_rep::sort_uniq_clone (bool)
+  {
+    if (m_step < 0)
+      return new idx_range_rep (m_start + (m_len - 1)*m_step, m_len, -m_step, DIRECT);
+    else
+      {
+        m_count++;
+        return this;
+      }
+  }
+
+  idx_vector::idx_base_rep *
+  idx_vector::idx_range_rep::sort_idx (Array<octave_idx_type>& idx)
+  {
+    if (m_step < 0 && m_len > 0)
+      {
+        idx.clear (1, m_len);
+        for (octave_idx_type i = 0; i < m_len; i++)
+          idx.xelem (i) = m_len - 1 - i;
+        return new idx_range_rep (m_start + (m_len - 1)*m_step, m_len, -m_step, DIRECT);
+      }
+    else
       {
-        idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-        l = r->get_data ();
-        u = l + 1;
-        res = true;
+        idx.clear (1, m_len);
+        for (octave_idx_type i = 0; i < m_len; i++)
+          idx.xelem (i) = i;
+        m_count++;
+        return this;
       }
-      break;
+  }
+
+  std::ostream& idx_vector::idx_range_rep::print (std::ostream& os) const
+  {
+    os << m_start << ':' << m_step << ':' << m_start + m_len*m_step;
+    return os;
+  }
+
+  range<double> idx_vector::idx_range_rep::unconvert (void) const
+  {
+    return range<double>::make_n_element_range
+      (static_cast<double> (m_start+1), static_cast<double> (m_step), m_len);
+  }
+
+  Array<octave_idx_type> idx_vector::idx_range_rep::as_array (void)
+  {
+    Array<octave_idx_type> retval (dim_vector (1, m_len));
+    for (octave_idx_type i = 0; i < m_len; i++)
+      retval.xelem (i) = m_start + i*m_step;
+
+    return retval;
+  }
+
+  inline octave_idx_type convert_index (octave_idx_type i, octave_idx_type& ext)
+  {
+    if (i <= 0)
+      err_invalid_index (i-1);
+
+    if (ext < i)
+      ext = i;
+
+    return i - 1;
+  }
+
+  inline octave_idx_type convert_index (double x, octave_idx_type& ext)
+  {
+    octave_idx_type i = static_cast<octave_idx_type> (x);
+
+    if (static_cast<double> (i) != x)
+      err_invalid_index (x-1);
+
+    return convert_index (i, ext);
+  }
+
+  inline octave_idx_type convert_index (float x, octave_idx_type& ext)
+  {
+    return convert_index (static_cast<double> (x), ext);
+  }
+
+  template <typename T>
+  inline octave_idx_type convert_index (octave_int<T> x, octave_idx_type& ext)
+  {
+    octave_idx_type i = octave_int<octave_idx_type> (x).value ();
+
+    return convert_index (i, ext);
+  }
+
+  template <typename T>
+  idx_vector::idx_scalar_rep::idx_scalar_rep (T x)
+    : idx_base_rep (), m_data (0)
+  {
+    octave_idx_type dummy = 0;
+
+    m_data = convert_index (x, dummy);
+  }
+
+  idx_vector::idx_scalar_rep::idx_scalar_rep (octave_idx_type i)
+    : idx_base_rep (), m_data (i)
+  {
+    if (m_data < 0)
+      err_invalid_index (m_data);
+  }
+
+  octave_idx_type
+  idx_vector::idx_scalar_rep::checkelem (octave_idx_type i) const
+  {
+    if (i != 0)
+      err_index_out_of_range ();
+
+    return m_data;
+  }
+
+  idx_vector::idx_base_rep *
+  idx_vector::idx_scalar_rep::sort_idx (Array<octave_idx_type>& idx)
+  {
+    idx.clear (1, 1);
+    idx.fill (0);
+    m_count++;
+    return this;
+  }
+
+  std::ostream& idx_vector::idx_scalar_rep::print (std::ostream& os) const
+  {
+    return os << m_data;
+  }
+
+  double idx_vector::idx_scalar_rep::unconvert (void) const
+  {
+    return m_data + 1;
+  }
+
+  Array<octave_idx_type> idx_vector::idx_scalar_rep::as_array (void)
+  {
+    return Array<octave_idx_type> (dim_vector (1, 1), m_data);
+  }
+
+  template <typename T>
+  idx_vector::idx_vector_rep::idx_vector_rep (const Array<T>& nda)
+    : idx_base_rep (), m_data (nullptr), m_len (nda.numel ()), m_ext (0),
+      m_aowner (nullptr), m_orig_dims (nda.dims ())
+  {
+    if (m_len != 0)
+      {
+        std::unique_ptr<octave_idx_type []> d (new octave_idx_type [m_len]);
+
+        for (octave_idx_type i = 0; i < m_len; i++)
+          d[i] = convert_index (nda.xelem (i), m_ext);
+
+        m_data = d.release ();
+      }
+  }
+
+  // Note that this makes a shallow copy of the index array.
+
+  idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda)
+    : idx_base_rep (), m_data (inda.data ()), m_len (inda.numel ()), m_ext (0),
+      m_aowner (new Array<octave_idx_type> (inda)), m_orig_dims (inda.dims ())
+  {
+    if (m_len != 0)
+      {
+        octave_idx_type max = -1;
+        for (octave_idx_type i = 0; i < m_len; i++)
+          {
+            octave_idx_type k = inda.xelem (i);
+            if (k < 0)
+              err_invalid_index (k);
+            else if (k > max)
+              max = k;
+          }
+
+        m_ext = max + 1;
+      }
+  }
+
+  idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda,
+                                              octave_idx_type ext, direct)
+    : idx_base_rep (), m_data (inda.data ()), m_len (inda.numel ()),
+      m_ext (ext), m_aowner (new Array<octave_idx_type> (inda)),
+      m_orig_dims (inda.dims ())
+  {
+    // No checking.
+    if (m_ext < 0)
+      {
+        octave_idx_type max = -1;
+        for (octave_idx_type i = 0; i < m_len; i++)
+          if (m_data[i] > max)
+            max = m_data[i];
+
+        m_ext = max + 1;
+      }
+  }
 
-    case class_mask:
+  idx_vector::idx_vector_rep::idx_vector_rep (bool b)
+    : idx_base_rep (), m_data (nullptr), m_len (b ? 1 : 0), m_ext (0),
+      m_aowner (nullptr), m_orig_dims (m_len, m_len)
+  {
+    if (m_len != 0)
+      {
+        octave_idx_type *d = new octave_idx_type [1];
+        d[0] = 0;
+        m_data = d;
+        m_ext = 1;
+      }
+  }
+
+  idx_vector::idx_vector_rep::idx_vector_rep (const Array<bool>& bnda,
+                                              octave_idx_type nnz)
+    : idx_base_rep (), m_data (nullptr), m_len (nnz), m_ext (0),
+      m_aowner (nullptr), m_orig_dims ()
+  {
+    if (nnz < 0)
+      m_len = bnda.nnz ();
+
+    const dim_vector dv = bnda.dims ();
+
+    m_orig_dims = dv.make_nd_vector (m_len);
+
+    if (m_len != 0)
+      {
+        octave_idx_type *d = new octave_idx_type [m_len];
+
+        octave_idx_type ntot = bnda.numel ();
+
+        octave_idx_type k = 0;
+        for (octave_idx_type i = 0; i < ntot; i++)
+          if (bnda.xelem (i))
+            d[k++] = i;
+
+        m_data = d;
+
+        m_ext = d[k-1] + 1;
+      }
+  }
+
+  idx_vector::idx_vector_rep::idx_vector_rep (const Sparse<bool>& bnda)
+    : idx_base_rep (), m_data (nullptr), m_len (bnda.nnz ()), m_ext (0),
+      m_aowner (nullptr), m_orig_dims ()
+  {
+    const dim_vector dv = bnda.dims ();
+
+    m_orig_dims = dv.make_nd_vector (m_len);
+
+    if (m_len != 0)
+      {
+        octave_idx_type *d = new octave_idx_type [m_len];
+
+        octave_idx_type k = 0;
+        octave_idx_type nc = bnda.cols ();
+        octave_idx_type nr = bnda.rows ();
+
+        for (octave_idx_type j = 0; j < nc; j++)
+          for (octave_idx_type i = bnda.cidx (j); i < bnda.cidx (j+1); i++)
+            if (bnda.data (i))
+              d[k++] = j * nr + bnda.ridx (i);
+
+        m_data = d;
+
+        m_ext = d[k-1] + 1;
+      }
+  }
+
+  idx_vector::idx_vector_rep::~idx_vector_rep (void)
+  {
+    if (m_aowner)
+      delete m_aowner;
+    else
+      delete [] m_data;
+  }
+
+  octave_idx_type
+  idx_vector::idx_vector_rep::checkelem (octave_idx_type n) const
+  {
+    if (n < 0 || n >= m_len)
+      err_invalid_index (n);
+
+    return xelem (n);
+  }
+
+  idx_vector::idx_base_rep *
+  idx_vector::idx_vector_rep::sort_uniq_clone (bool uniq)
+  {
+    if (m_len == 0)
+      {
+        m_count++;
+        return this;
+      }
+
+    // This is wrapped in unique_ptr so that we don't leak on out-of-memory.
+    std::unique_ptr<idx_vector_rep> new_rep
+      (new idx_vector_rep (nullptr, m_len, m_ext, m_orig_dims, DIRECT));
+
+    if (m_ext > m_len*math::log2 (1.0 + m_len))
       {
-        idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-        octave_idx_type ext = r->extent (0);
-        octave_idx_type len = r->length (0);
-        if (ext == len)
+        // Use standard sort via octave_sort.
+        octave_idx_type *new_data = new octave_idx_type [m_len];
+        new_rep->m_data = new_data;
+
+        std::copy_n (m_data, m_len, new_data);
+        octave_sort<octave_idx_type> lsort;
+        lsort.set_compare (ASCENDING);
+        lsort.sort (new_data, m_len);
+
+        if (uniq)
+          {
+            octave_idx_type new_len = std::unique (new_data, new_data + m_len)
+              - new_data;
+            new_rep->m_len = new_len;
+            if (new_rep->m_orig_dims.ndims () == 2 && new_rep->m_orig_dims(0) == 1)
+              new_rep->m_orig_dims = dim_vector (1, new_len);
+            else
+              new_rep->m_orig_dims = dim_vector (new_len, 1);
+          }
+      }
+    else if (uniq)
+      {
+        // Use two-pass bucket sort (only a mask array needed).
+        OCTAVE_LOCAL_BUFFER_INIT (bool, has, m_ext, false);
+        for (octave_idx_type i = 0; i < m_len; i++)
+          has[m_data[i]] = true;
+
+        octave_idx_type new_len = 0;
+        for (octave_idx_type i = 0; i < m_ext; i++)
+          new_len += has[i];
+
+        new_rep->m_len = new_len;
+        if (new_rep->m_orig_dims.ndims () == 2 && new_rep->m_orig_dims(0) == 1)
+          new_rep->m_orig_dims = dim_vector (1, new_len);
+        else
+          new_rep->m_orig_dims = dim_vector (new_len, 1);
+
+        octave_idx_type *new_data = new octave_idx_type [new_len];
+        new_rep->m_data = new_data;
+
+        for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
+          if (has[i])
+            new_data[j++] = i;
+      }
+    else
+      {
+        // Use two-pass bucket sort.
+        OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, cnt, m_ext, 0);
+        for (octave_idx_type i = 0; i < m_len; i++)
+          cnt[m_data[i]]++;
+
+        octave_idx_type *new_data = new octave_idx_type [m_len];
+        new_rep->m_data = new_data;
+
+        for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
           {
-            l = 0;
-            u = len;
-            res = true;
+            for (octave_idx_type k = 0; k < cnt[i]; k++)
+              new_data[j++] = i;
+          }
+      }
+
+    return new_rep.release ();
+  }
+
+  idx_vector::idx_base_rep *
+  idx_vector::idx_vector_rep::sort_idx (Array<octave_idx_type>& idx)
+  {
+    // This is wrapped in unique_ptr so that we don't leak on out-of-memory.
+    std::unique_ptr<idx_vector_rep> new_rep
+      (new idx_vector_rep (nullptr, m_len, m_ext, m_orig_dims, DIRECT));
+
+    if (m_ext > m_len*math::log2 (1.0 + m_len))
+      {
+        // Use standard sort via octave_sort.
+        idx.clear (m_orig_dims);
+        octave_idx_type *idx_data = idx.fortran_vec ();
+        for (octave_idx_type i = 0; i < m_len; i++)
+          idx_data[i] = i;
+
+        octave_idx_type *new_data = new octave_idx_type [m_len];
+        new_rep->m_data = new_data;
+        std::copy_n (m_data, m_len, new_data);
+
+        octave_sort<octave_idx_type> lsort;
+        lsort.set_compare (ASCENDING);
+        lsort.sort (new_data, idx_data, m_len);
+      }
+    else
+      {
+        // Use two-pass bucket sort.
+        OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, cnt, m_ext, 0);
+
+        for (octave_idx_type i = 0; i < m_len; i++)
+          cnt[m_data[i]]++;
+
+        idx.clear (m_orig_dims);
+        octave_idx_type *idx_data = idx.fortran_vec ();
+
+        octave_idx_type *new_data = new octave_idx_type [m_len];
+        new_rep->m_data = new_data;
+
+        for (octave_idx_type i = 0, k = 0; i < m_ext; i++)
+          {
+            octave_idx_type j = cnt[i];
+            cnt[i] = k;
+            k += j;
+          }
+
+        for (octave_idx_type i = 0; i < m_len; i++)
+          {
+            octave_idx_type j = m_data[i];
+            octave_idx_type k = cnt[j]++;
+            new_data[k] = j;
+            idx_data[k] = i;
           }
       }
 
-    default:
-      break;
-    }
+    return new_rep.release ();
+  }
+
+  std::ostream& idx_vector::idx_vector_rep::print (std::ostream& os) const
+  {
+    os << '[';
 
-  return res;
-}
+    for (octave_idx_type i = 0; i < m_len - 1; i++)
+      os << m_data[i] << ',' << ' ';
+
+    if (m_len > 0)
+      os << m_data[m_len-1];
+
+    os << ']';
 
-octave_idx_type
-idx_vector::increment (void) const
-{
-  octave_idx_type retval = 0;
+    return os;
+  }
 
-  switch (rep->idx_class ())
-    {
-    case class_colon:
-      retval = 1;
-      break;
+  Array<double> idx_vector::idx_vector_rep::unconvert (void) const
+  {
+    Array<double> retval (m_orig_dims);
+    for (octave_idx_type i = 0; i < m_len; i++)
+      retval.xelem (i) = m_data[i] + 1;
+    return retval;
+  }
+
+  Array<octave_idx_type> idx_vector::idx_vector_rep::as_array (void)
+  {
+    if (m_aowner)
+      return *m_aowner;
+    else
+      {
+        Array<octave_idx_type> retval (m_orig_dims);
 
-    case class_range:
-      retval = dynamic_cast<idx_range_rep *> (rep) -> get_step ();
-      break;
+        if (m_data)
+          {
+            std::memcpy (retval.fortran_vec (), m_data, m_len*sizeof (octave_idx_type));
+            // Delete the old copy and share the m_data instead to save memory.
+            delete [] m_data;
+          }
+
+        m_data = retval.fortran_vec ();
+        m_aowner = new Array<octave_idx_type> (retval);
 
-    case class_vector:
-    case class_mask:
+        return retval;
+      }
+  }
+
+  idx_vector::idx_mask_rep::idx_mask_rep (bool b)
+    : idx_base_rep (), m_data (nullptr), m_len (b ? 1 : 0), m_ext (0),
+      m_lsti (-1), m_lste (-1), m_aowner (nullptr), m_orig_dims (m_len, m_len)
+  {
+    if (m_len != 0)
       {
-        if (length (0) > 1)
-          retval = elem (1) - elem (0);
+        bool *d = new bool [1];
+        d[0] = true;
+        m_data = d;
+        m_ext = 1;
       }
-      break;
+  }
 
-    default:
-      break;
-    }
+  idx_vector::idx_mask_rep::idx_mask_rep (const Array<bool>& bnda,
+                                          octave_idx_type nnz)
+    : idx_base_rep (), m_data (nullptr), m_len (nnz), m_ext (bnda.numel ()),
+      m_lsti (-1), m_lste (-1), m_aowner (nullptr), m_orig_dims ()
+  {
+    if (nnz < 0)
+      m_len = bnda.nnz ();
 
-  return retval;
-}
+    // We truncate the extent as much as possible.  For Matlab
+    // compatibility, but maybe it's not a bad idea anyway.
+    while (m_ext > 0 && ! bnda(m_ext-1))
+      m_ext--;
+
+    const dim_vector dv = bnda.dims ();
+
+    m_orig_dims = dv.make_nd_vector (m_len);
 
-const octave_idx_type *
-idx_vector::raw (void)
-{
-  if (rep->idx_class () != class_vector)
-    *this = idx_vector (as_array (), extent (0));
+    m_aowner = new Array<bool> (bnda);
+    m_data = bnda.data ();
+  }
 
-  idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
+  idx_vector::idx_mask_rep::~idx_mask_rep (void)
+  {
+    if (m_aowner)
+      delete m_aowner;
+    else
+      delete [] m_data;
+  }
 
-  assert (r != nullptr);
-
-  return r->get_data ();
-}
+  octave_idx_type idx_vector::idx_mask_rep::xelem (octave_idx_type n) const
+  {
+    if (n == m_lsti + 1)
+      {
+        m_lsti = n;
+        while (! m_data[++m_lste]) ;
+      }
+    else
+      {
+        m_lsti = n++;
+        m_lste = -1;
+        while (n > 0)
+          if (m_data[++m_lste]) --n;
+      }
+    return m_lste;
+  }
 
-void
-idx_vector::copy_data (octave_idx_type *data) const
-{
-  octave_idx_type len = rep->length (0);
+  octave_idx_type idx_vector::idx_mask_rep::checkelem (octave_idx_type n) const
+  {
+    if (n < 0 || n >= m_len)
+      err_invalid_index (n);
+
+    return xelem (n);
+  }
 
-  switch (rep->idx_class ())
-    {
-    case class_colon:
-      (*current_liboctave_error_handler) ("colon not allowed");
-      break;
+  std::ostream& idx_vector::idx_mask_rep::print (std::ostream& os) const
+  {
+    os << '[';
+
+    for (octave_idx_type i = 0; i < m_ext - 1; i++)
+      os << m_data[i] << ',' << ' ';
+
+    if (m_ext > 0)
+      os << m_data[m_ext-1];
 
-    case class_range:
+    os << ']';
+
+    return os;
+  }
+
+  Array<bool> idx_vector::idx_mask_rep::unconvert (void) const
+  {
+    if (m_aowner)
+      return *m_aowner;
+    else
       {
-        idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-        octave_idx_type start = r->get_start ();
-        octave_idx_type step = r->get_step ();
-        octave_idx_type i, j;
-        if (step == 1)
-          for (i = start, j = start + len; i < j; i++) *data++ = i;
-        else if (step == -1)
-          for (i = start, j = start - len; i > j; i--) *data++ = i;
-        else
-          for (i = 0, j = start; i < len; i++, j += step) *data++ = j;
+        Array<bool> retval (dim_vector (m_ext, 1));
+        for (octave_idx_type i = 0; i < m_ext; i++)
+          retval.xelem (i) = m_data[i];
+        return retval;
       }
-      break;
+  }
 
-    case class_scalar:
+  Array<octave_idx_type> idx_vector::idx_mask_rep::as_array (void)
+  {
+    if (m_aowner)
+      return m_aowner->find ().reshape (m_orig_dims);
+    else
       {
-        idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-        *data = r->get_data ();
+        Array<bool> retval (m_orig_dims);
+        for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
+          if (m_data[i])
+            retval.xelem (j++) = i;
+
+        return retval;
       }
-      break;
+  }
+
+  idx_vector::idx_base_rep *
+  idx_vector::idx_mask_rep::sort_idx (Array<octave_idx_type>& idx)
+  {
+    idx.clear (m_len, 1);
+    for (octave_idx_type i = 0; i < m_len; i++)
+      idx.xelem (i) = i;
+
+    m_count++;
+    return this;
+  }
+
+  const idx_vector idx_vector::colon (new idx_vector::idx_colon_rep ());
 
-    case class_vector:
+  idx_vector::idx_vector (const Array<bool>& bnda)
+    : m_rep (nullptr)
+  {
+    // Convert only if it means saving at least half the memory.
+    static const int factor = (2 * sizeof (octave_idx_type));
+    octave_idx_type nnz = bnda.nnz ();
+    if (nnz <= bnda.numel () / factor)
+      m_rep = new idx_vector_rep (bnda, nnz);
+    else
+      m_rep = new idx_mask_rep (bnda, nnz);
+  }
+
+  bool idx_vector::maybe_reduce (octave_idx_type n, const idx_vector& j,
+                                 octave_idx_type nj)
+  {
+    bool reduced = false;
+
+    // Empty index always reduces.
+    if (m_rep->length (n) == 0)
       {
-        idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
-        const octave_idx_type *rdata = r->get_data ();
-        std::copy_n (rdata, len, data);
+        *this = idx_vector ();
+        return true;
       }
-      break;
 
-    case class_mask:
+    // Possibly skip singleton dims.
+    if (n == 1 && m_rep->is_colon_equiv (n))
+      {
+        *this = j;
+        return true;
+      }
+
+    if (nj == 1 && j.is_colon_equiv (nj))
+      return true;
+
+    switch (j.idx_class ())
       {
-        idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-        const bool *mask = r->get_data ();
-        octave_idx_type ext = r->extent (0);
-        for (octave_idx_type i = 0, j = 0; i < ext; i++)
-          if (mask[i])
-            data[j++] = i;
-      }
-      break;
+      case class_colon:
+        switch (m_rep->idx_class ())
+          {
+          case class_colon:
+            // (:,:) reduces to (:)
+            reduced = true;
+            break;
+
+          case class_scalar:
+            {
+              // (i,:) reduces to a range.
+              idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+              octave_idx_type k = r->get_data ();
+              *this = new idx_range_rep (k, nj, n, DIRECT);
+              reduced = true;
+            }
+            break;
 
-    default:
-      assert (false);
-      break;
-    }
-}
+          case class_range:
+            {
+              // (i:k:end,:) reduces to a range if i <= k and k divides n.
+              idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+              octave_idx_type s = r->get_start ();
+              octave_idx_type l = r->length (n);
+              octave_idx_type t = r->get_step ();
+              if (l*t == n)
+                {
+                  *this = new idx_range_rep (s, l * nj, t, DIRECT);
+                  reduced = true;
+                }
+            }
+            break;
 
-idx_vector
-idx_vector::complement (octave_idx_type n) const
-{
-  idx_vector retval;
-  if (extent (n) > n)
-    (*current_liboctave_error_handler)
-      ("internal error: out of range complement index requested");
+          default:
+            break;
+          }
+        break;
+
+      case class_range:
+        switch (m_rep->idx_class ())
+          {
+          case class_colon:
+            {
+              // (:,i:j) reduces to a range (the m_step must be 1)
+              idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
+              if (rj->get_step () == 1)
+                {
+                  octave_idx_type sj = rj->get_start ();
+                  octave_idx_type lj = rj->length (nj);
+                  *this = new idx_range_rep (sj * n, lj * n, 1, DIRECT);
+                  reduced = true;
+                }
+            }
+            break;
 
-  if (idx_class () == class_mask)
-    {
-      idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-      octave_idx_type nz = r->length (0);
-      octave_idx_type ext = r->extent (0);
-      Array<bool> mask (dim_vector (n, 1));
-      const bool *data = r->get_data ();
-      bool *ndata = mask.fortran_vec ();
-      for (octave_idx_type i = 0; i < ext; i++)
-        ndata[i] = ! data[i];
-      std::fill_n (ndata + ext, n - ext, true);
-      retval = new idx_mask_rep (mask, n - nz);
-    }
-  else
-    {
-      Array<bool> mask (dim_vector (n, 1), true);
-      fill (false, length (n), mask.fortran_vec ());
-      retval = idx_vector (mask);
-    }
+          case class_scalar:
+            {
+              // (k,i:d:j) reduces to a range.
+              idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+              idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
+              octave_idx_type k = r->get_data ();
+              octave_idx_type sj = rj->get_start ();
+              octave_idx_type lj = rj->length (nj);
+              octave_idx_type tj = rj->get_step ();
+              *this = new idx_range_rep (n * sj + k, lj, n * tj, DIRECT);
+              reduced = true;
+            }
+            break;
 
-  return retval;
-}
+          case class_range:
+            {
+              // (i:k:end,p:q) reduces to a range if i <= k and k divides n.
+              // (ones (1, m), ones (1, n)) reduces to (ones (1, m*n))
+              idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+              octave_idx_type s = r->get_start ();
+              octave_idx_type l = r->length (n);
+              octave_idx_type t = r->get_step ();
+              idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
+              octave_idx_type sj = rj->get_start ();
+              octave_idx_type lj = rj->length (nj);
+              octave_idx_type tj = rj->get_step ();
+              if ((l*t == n && tj == 1) || (t == 0 && tj == 0))
+                {
+                  *this = new idx_range_rep (s + n * sj, l * lj, t, DIRECT);
+                  reduced = true;
+                }
+            }
+            break;
+
+          default:
+            break;
+          }
+        break;
+
+      case class_scalar:
+        switch (m_rep->idx_class ())
+          {
+          case class_scalar:
+            {
+              // (i,j) reduces to a single index.
+              idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+              idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
+              octave_idx_type k = r->get_data () + n * rj->get_data ();
+              *this = new idx_scalar_rep (k, DIRECT);
+              reduced = true;
+            }
+            break;
 
-bool
-idx_vector::is_permutation (octave_idx_type n) const
-{
-  bool retval = false;
+          case class_range:
+            {
+              // (i:d:j,k) reduces to a range.
+              idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+              idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
+              octave_idx_type s = r->get_start ();
+              octave_idx_type l = r->length (nj);
+              octave_idx_type t = r->get_step ();
+              octave_idx_type k = rj->get_data ();
+              *this = new idx_range_rep (n * k + s, l, t, DIRECT);
+              reduced = true;
+            }
+            break;
 
-  if (is_colon_equiv (n))
-    retval = true;
-  else if (length(n) == n && extent(n) == n)
-    {
-      OCTAVE_LOCAL_BUFFER_INIT (bool, left, n, true);
+          case class_colon:
+            {
+              // (:,k) reduces to a range.
+              idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
+              octave_idx_type k = rj->get_data ();
+              *this = new idx_range_rep (n * k, n, 1, DIRECT);
+              reduced = true;
+            }
+            break;
 
-      retval = true;
+          default:
+            break;
+          }
+        break;
+
+      default:
+        break;
+      }
+
+    return reduced;
+  }
 
-      for (octave_idx_type i = 0, len = length (); i < len; i++)
+  bool idx_vector::is_cont_range (octave_idx_type n, octave_idx_type& l,
+                                  octave_idx_type& u) const
+  {
+    bool res = false;
+
+    switch (m_rep->idx_class ())
+      {
+      case class_colon:
+        l = 0; u = n;
+        res = true;
+        break;
+
+      case class_range:
         {
-          octave_idx_type k = xelem (i);
-          if (left[k])
-            left[k] = false;
-          else
+          idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+          if (r->get_step () == 1)
             {
-              retval = false;
-              break;
+              l = r->get_start ();
+              u = l + r->length (n);
+              res = true;
             }
         }
-    }
+        break;
 
-  return retval;
-}
+      case class_scalar:
+        {
+          idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+          l = r->get_data ();
+          u = l + 1;
+          res = true;
+        }
+        break;
 
-idx_vector
-idx_vector::inverse_permutation (octave_idx_type n) const
-{
-  assert (n == length (n));
+      case class_mask:
+        {
+          idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+          octave_idx_type m_ext = r->extent (0);
+          octave_idx_type m_len = r->length (0);
+          if (m_ext == m_len)
+            {
+              l = 0;
+              u = m_len;
+              res = true;
+            }
+        }
 
-  idx_vector retval;
+      default:
+        break;
+      }
+
+    return res;
+  }
+
+  octave_idx_type idx_vector::increment (void) const
+  {
+    octave_idx_type retval = 0;
 
-  switch (idx_class ())
-    {
-    case class_range:
+    switch (m_rep->idx_class ())
       {
-        if (increment () == -1)
-          retval = sorted ();
-        else
-          retval = *this;
+      case class_colon:
+        retval = 1;
+        break;
+
+      case class_range:
+        retval = dynamic_cast<idx_range_rep *> (m_rep) -> get_step ();
+        break;
+
+      case class_vector:
+      case class_mask:
+        {
+          if (length (0) > 1)
+            retval = elem (1) - elem (0);
+        }
+        break;
+
+      default:
         break;
       }
-    case class_vector:
+
+    return retval;
+  }
+
+  const octave_idx_type * idx_vector::raw (void)
+  {
+    if (m_rep->idx_class () != class_vector)
+      *this = idx_vector (as_array (), extent (0));
+
+    idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+
+    assert (r != nullptr);
+
+    return r->get_data ();
+  }
+
+  void idx_vector::copy_data (octave_idx_type *m_data) const
+  {
+    octave_idx_type m_len = m_rep->length (0);
+
+    switch (m_rep->idx_class ())
       {
-        idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
-        const octave_idx_type *ri = r->get_data ();
-        Array<octave_idx_type> idx (orig_dimensions ());
-        for (octave_idx_type i = 0; i < n; i++)
-          idx.xelem (ri[i]) = i;
-        retval = new idx_vector_rep (idx, r->extent (0), DIRECT);
+      case class_colon:
+        (*current_liboctave_error_handler) ("colon not allowed");
+        break;
+
+      case class_range:
+        {
+          idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+          octave_idx_type m_start = r->get_start ();
+          octave_idx_type m_step = r->get_step ();
+          octave_idx_type i, j;
+          if (m_step == 1)
+            for (i = m_start, j = m_start + m_len; i < j; i++) *m_data++ = i;
+          else if (m_step == -1)
+            for (i = m_start, j = m_start - m_len; i > j; i--) *m_data++ = i;
+          else
+            for (i = 0, j = m_start; i < m_len; i++, j += m_step) *m_data++ = j;
+        }
+        break;
+
+      case class_scalar:
+        {
+          idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+          *m_data = r->get_data ();
+        }
+        break;
+
+      case class_vector:
+        {
+          idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+          const octave_idx_type *rdata = r->get_data ();
+          std::copy_n (rdata, m_len, m_data);
+        }
+        break;
+
+      case class_mask:
+        {
+          idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+          const bool *mask = r->get_data ();
+          octave_idx_type m_ext = r->extent (0);
+          for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
+            if (mask[i])
+              m_data[j++] = i;
+        }
+        break;
+
+      default:
+        assert (false);
         break;
       }
-    default:
-      retval = *this;
-      break;
-    }
-
-  return retval;
-}
+  }
 
-idx_vector
-idx_vector::unmask (void) const
-{
-  if (idx_class () == class_mask)
-    {
-      idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-      const bool *data = r->get_data ();
-      octave_idx_type ext = r->extent (0);
-      octave_idx_type len = r->length (0);
-      octave_idx_type *idata = new octave_idx_type [len];
-
-      for (octave_idx_type i = 0, j = 0; i < ext; i++)
-        if (data[i])
-          idata[j++] = i;
+  idx_vector idx_vector::complement (octave_idx_type n) const
+  {
+    idx_vector retval;
+    if (extent (n) > n)
+      (*current_liboctave_error_handler)
+        ("internal error: out of range complement index requested");
 
-      ext = (len > 0 ? idata[len - 1] + 1 : 0);
+    if (idx_class () == class_mask)
+      {
+        idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+        octave_idx_type nz = r->length (0);
+        octave_idx_type m_ext = r->extent (0);
+        Array<bool> mask (dim_vector (n, 1));
+        const bool *m_data = r->get_data ();
+        bool *ndata = mask.fortran_vec ();
+        for (octave_idx_type i = 0; i < m_ext; i++)
+          ndata[i] = ! m_data[i];
+        std::fill_n (ndata + m_ext, n - m_ext, true);
+        retval = new idx_mask_rep (mask, n - nz);
+      }
+    else
+      {
+        Array<bool> mask (dim_vector (n, 1), true);
+        fill (false, length (n), mask.fortran_vec ());
+        retval = idx_vector (mask);
+      }
 
-      return new idx_vector_rep (idata, len, ext, r->orig_dimensions (),
-                                 DIRECT);
-    }
-  else
-    return *this;
-}
+    return retval;
+  }
 
-void idx_vector::unconvert (idx_class_type& iclass,
-                            double& scalar, Range& range,
-                            Array<double>& array, Array<bool>& mask) const
-{
-  iclass = idx_class ();
-  switch (iclass)
-    {
-    case class_colon:
-      break;
+  bool idx_vector::is_permutation (octave_idx_type n) const
+  {
+    bool retval = false;
+
+    if (is_colon_equiv (n))
+      retval = true;
+    else if (length(n) == n && extent(n) == n)
+      {
+        OCTAVE_LOCAL_BUFFER_INIT (bool, left, n, true);
+
+        retval = true;
 
-    case class_range:
-      {
-        idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-        range = r->unconvert ();
+        for (octave_idx_type i = 0, m_len = length (); i < m_len; i++)
+          {
+            octave_idx_type k = xelem (i);
+            if (left[k])
+              left[k] = false;
+            else
+              {
+                retval = false;
+                break;
+              }
+          }
       }
-      break;
+
+    return retval;
+  }
 
-    case class_scalar:
-      {
-        idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-        scalar = r->unconvert ();
-      }
-      break;
+  idx_vector idx_vector::inverse_permutation (octave_idx_type n) const
+  {
+    assert (n == length (n));
 
-    case class_vector:
+    idx_vector retval;
+
+    switch (idx_class ())
       {
-        idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
-        array = r->unconvert ();
+      case class_range:
+        {
+          if (increment () == -1)
+            retval = sorted ();
+          else
+            retval = *this;
+          break;
+        }
+      case class_vector:
+        {
+          idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+          const octave_idx_type *ri = r->get_data ();
+          Array<octave_idx_type> idx (orig_dimensions ());
+          for (octave_idx_type i = 0; i < n; i++)
+            idx.xelem (ri[i]) = i;
+          retval = new idx_vector_rep (idx, r->extent (0), DIRECT);
+          break;
+        }
+      default:
+        retval = *this;
+        break;
       }
-      break;
 
-    case class_mask:
+    return retval;
+  }
+
+  idx_vector idx_vector::unmask (void) const
+  {
+    if (idx_class () == class_mask)
       {
-        idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-        mask = r->unconvert ();
-      }
-      break;
+        idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+        const bool *m_data = r->get_data ();
+        octave_idx_type m_ext = r->extent (0);
+        octave_idx_type m_len = r->length (0);
+        octave_idx_type *idata = new octave_idx_type [m_len];
+
+        for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
+          if (m_data[i])
+            idata[j++] = i;
+
+        m_ext = (m_len > 0 ? idata[m_len - 1] + 1 : 0);
 
-    default:
-      assert (false);
-      break;
-    }
-}
+        return new idx_vector_rep (idata, m_len, m_ext, r->orig_dimensions (),
+                                   DIRECT);
+      }
+    else
+      return *this;
+  }
 
-Array<octave_idx_type>
-idx_vector::as_array (void) const
-{
-  return rep->as_array ();
-}
+  void idx_vector::unconvert (idx_class_type& iclass,
+                              double& scalar, range<double>& range,
+                              Array<double>& array, Array<bool>& mask) const
+  {
+    iclass = idx_class ();
+    switch (iclass)
+      {
+      case class_colon:
+        break;
+
+      case class_range:
+        {
+          idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+          range = r->unconvert ();
+        }
+        break;
+
+      case class_scalar:
+        {
+          idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+          scalar = r->unconvert ();
+        }
+        break;
 
-bool
-idx_vector::isvector (void) const
-{
-  return idx_class () != class_vector || orig_dimensions ().isvector ();
-}
+      case class_vector:
+        {
+          idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+          array = r->unconvert ();
+        }
+        break;
+
+      case class_mask:
+        {
+          idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+          mask = r->unconvert ();
+        }
+        break;
 
-octave_idx_type
-idx_vector::freeze (octave_idx_type z_len, const char *, bool resize_ok)
-{
-  if (! resize_ok && extent (z_len) > z_len)
-    {
+      default:
+        assert (false);
+        break;
+      }
+  }
+
+  Array<octave_idx_type> idx_vector::as_array (void) const
+  {
+    return m_rep->as_array ();
+  }
+
+  bool idx_vector::isvector (void) const
+  {
+    return idx_class () != class_vector || orig_dimensions ().isvector ();
+  }
+
+  octave_idx_type
+  idx_vector::freeze (octave_idx_type z_len, const char *, bool resize_ok)
+  {
+    if (! resize_ok && extent (z_len) > z_len)
       (*current_liboctave_error_handler)
         ("invalid matrix index = %" OCTAVE_IDX_TYPE_FORMAT, extent (z_len));
-      // FIXME: Should we call this before calling error_handler?
-      rep->err = true;
-      chkerr ();
-    }
+
+    return length (z_len);
+  }
 
-  return length (z_len);
-}
-
-octave_idx_type
-idx_vector::ones_count () const
-{
-  octave_idx_type n = 0;
+  octave_idx_type idx_vector::ones_count () const
+  {
+    octave_idx_type n = 0;
 
-  if (is_colon ())
-    n = 1;
-  else
-    {
-      for (octave_idx_type i = 0; i < length (1); i++)
-        if (xelem (i) == 0)
-          n++;
-    }
+    if (is_colon ())
+      n = 1;
+    else
+      {
+        for (octave_idx_type i = 0; i < length (1); i++)
+          if (xelem (i) == 0)
+            n++;
+      }
 
-  return n;
-}
+    return n;
+  }
 
-// Instantiate the octave_int constructors we want.
+  // Instantiate the octave_int constructors we want.
 #define INSTANTIATE_SCALAR_VECTOR_REP_CONST(T)                          \
   template OCTAVE_API idx_vector::idx_scalar_rep::idx_scalar_rep (T);   \
   template OCTAVE_API idx_vector::idx_vector_rep::idx_vector_rep (const Array<T>&);
 
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (float)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (double)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_int8)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_int16)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_int32)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_int64)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_uint8)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_uint16)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_uint32)
-INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_uint64)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (float)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (double)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_int8)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_int16)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_int32)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_int64)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_uint8)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_uint16)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_uint32)
+  INSTANTIATE_SCALAR_VECTOR_REP_CONST (octave_uint64)
+}
 
 /*
 
--- a/liboctave/array/idx-vector.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/idx-vector.h	Sun May 16 09:44:35 2021 +0200
@@ -41,1012 +41,995 @@
 
 template <typename T> class Array;
 template <typename T> class Sparse;
-class Range;
 
-// Design rationale:
-// idx_vector is a reference-counting, polymorphic pointer, that can contain
-// 4 types of index objects: a magic colon, a range, a scalar, or an index vector.
-// Polymorphic methods for single element access are provided, as well as
-// templates implementing "early dispatch", i.e., hoisting the checks for index
-// type out of loops.
-
-class
-OCTAVE_API
-idx_vector
+namespace octave
 {
-public:
-
-  enum idx_class_type
-  {
-    class_invalid = -1,
-    class_colon = 0,
-    class_range,
-    class_scalar,
-    class_vector,
-    class_mask
-  };
-
-  template <typename T, typename D> friend class std::unique_ptr;
-
-private:
-
-  class OCTAVE_API idx_base_rep
-  {
-  public:
-
-    idx_base_rep (void) : count (1), err (false) { }
-
-    // No copying!
-
-    idx_base_rep (const idx_base_rep&) = delete;
-
-    idx_base_rep& operator = (const idx_base_rep&) = delete;
-
-    virtual ~idx_base_rep (void) = default;
-
-    // Non-range-checking element query.
-    virtual octave_idx_type xelem (octave_idx_type i) const = 0;
-
-    // Range-checking element query.
-    virtual octave_idx_type checkelem (octave_idx_type i) const = 0;
-
-    // Length of the index vector.
-    virtual octave_idx_type length (octave_idx_type n) const = 0;
-
-    // The maximum index + 1.  The actual dimension is passed in.
-    virtual octave_idx_type extent (octave_idx_type n) const = 0;
-
-    // Index class.
-    virtual idx_class_type idx_class (void) const { return class_invalid; }
-
-    // Sorts, maybe uniqifies, and returns a clone object pointer.
-    virtual idx_base_rep * sort_uniq_clone (bool uniq = false) = 0;
-    // Sorts, and returns a sorting permutation (aka Array::sort).
-    virtual idx_base_rep * sort_idx (Array<octave_idx_type>&) = 0;
-
-    // Checks whether the index is colon or a range equivalent to colon.
-    virtual bool is_colon_equiv (octave_idx_type) const { return false; }
-
-    // The original dimensions of object (used when subscribing by matrices).
-    virtual dim_vector orig_dimensions (void) const { return dim_vector (); }
-
-    // i/o
-    virtual std::ostream& print (std::ostream& os) const = 0;
-
-    virtual Array<octave_idx_type> as_array (void);
-
-    octave::refcount<octave_idx_type> count;
-
-    bool err;
-  };
-
-  // The magic colon index.
-  class OCTAVE_API idx_colon_rep : public idx_base_rep
-  {
-  public:
-
-    idx_colon_rep (void) = default;
-
-    idx_colon_rep (char c);
-
-    // No copying!
-
-    idx_colon_rep (const idx_colon_rep& idx) = delete;
-
-    idx_colon_rep& operator = (const idx_colon_rep& idx) = delete;
-
-    octave_idx_type xelem (octave_idx_type i) const { return i; }
-
-    octave_idx_type checkelem (octave_idx_type i) const;
-
-    octave_idx_type length (octave_idx_type n) const { return n; }
-
-    octave_idx_type extent (octave_idx_type n) const { return n; }
-
-    idx_class_type idx_class (void) const { return class_colon; }
-
-    idx_base_rep * sort_uniq_clone (bool = false)
-    { count++; return this; }
-
-    OCTAVE_NORETURN idx_base_rep * sort_idx (Array<octave_idx_type>&);
-
-    bool is_colon_equiv (octave_idx_type) const { return true; }
-
-    std::ostream& print (std::ostream& os) const;
-  };
-
-  // To distinguish the "direct" constructors that blindly trust the data.
-  enum direct { DIRECT };
-
-  // The integer range index.
-  class OCTAVE_API idx_range_rep : public idx_base_rep
-  {
-  public:
-
-    idx_range_rep (void) = delete;
-
-    idx_range_rep (octave_idx_type _start, octave_idx_type _len,
-                   octave_idx_type _step, direct)
-      : idx_base_rep (), start(_start), len(_len), step(_step) { }
-
-    // Zero-based constructor.
-    idx_range_rep (octave_idx_type _start, octave_idx_type _limit,
-                   octave_idx_type _step);
-
-    idx_range_rep (const Range&);
-
-    // No copying!
-
-    idx_range_rep (const idx_range_rep& idx) = delete;
-
-    idx_range_rep& operator = (const idx_range_rep& idx) = delete;
-
-    octave_idx_type xelem (octave_idx_type i) const
-    { return start + i * step; }
-
-    octave_idx_type checkelem (octave_idx_type i) const;
-
-    octave_idx_type length (octave_idx_type) const { return len; }
-
-    octave_idx_type extent (octave_idx_type n) const
-    {
-      return len ? std::max (n, start + 1 + (step < 0 ? 0 : step * (len - 1)))
-                 : n;
-    }
-
-    idx_class_type idx_class (void) const { return class_range; }
-
-    idx_base_rep * sort_uniq_clone (bool uniq = false);
-
-    idx_base_rep * sort_idx (Array<octave_idx_type>&);
+  template <typename T> class range;
 
-    bool is_colon_equiv (octave_idx_type n) const
-    { return start == 0 && step == 1 && len == n; }
-
-    dim_vector orig_dimensions (void) const
-    { return dim_vector (1, len); }
-
-    octave_idx_type get_start (void) const { return start; }
-
-    octave_idx_type get_step (void) const { return step; }
-
-    std::ostream& print (std::ostream& os) const;
-
-    Range unconvert (void) const;
-
-    Array<octave_idx_type> as_array (void);
-
-  private:
-
-    octave_idx_type start, len, step;
-  };
-
-  // The integer scalar index.
-  class OCTAVE_API idx_scalar_rep : public idx_base_rep
-  {
-  public:
-
-    idx_scalar_rep (void) = delete;
-
-    idx_scalar_rep (octave_idx_type i, direct)
-      : idx_base_rep (), data (i) { }
-
-    // No copying!
-
-    idx_scalar_rep (const idx_scalar_rep& idx) = delete;
-
-    idx_scalar_rep& operator = (const idx_scalar_rep& idx) = delete;
-
-    // Zero-based constructor.
-    idx_scalar_rep (octave_idx_type i);
-
-    template <typename T>
-    idx_scalar_rep (T x);
-
-    octave_idx_type xelem (octave_idx_type) const { return data; }
-
-    octave_idx_type checkelem (octave_idx_type i) const;
-
-    octave_idx_type length (octave_idx_type) const { return 1; }
-
-    octave_idx_type extent (octave_idx_type n) const
-    { return std::max (n, data + 1); }
-
-    idx_class_type idx_class (void) const { return class_scalar; }
-
-    idx_base_rep * sort_uniq_clone (bool = false)
-    { count++; return this; }
-
-    idx_base_rep * sort_idx (Array<octave_idx_type>&);
-
-    bool is_colon_equiv (octave_idx_type n) const
-    { return n == 1 && data == 0; }
-
-    dim_vector orig_dimensions (void) const { return dim_vector (1, 1); }
-
-    octave_idx_type get_data (void) const { return data; }
-
-    std::ostream& print (std::ostream& os) const;
-
-    double unconvert (void) const;
-
-    Array<octave_idx_type> as_array (void);
-
-  private:
-
-    octave_idx_type data;
-  };
+  // Design rationale:
+  //
+  // idx_vector is a reference-counting, polymorphic pointer, that can
+  // contain 4 types of index objects: a magic colon, a range, a scalar,
+  // or an index vector.
+  //
+  // Polymorphic methods for single element access are provided, as well
+  // as templates implementing "early dispatch", i.e., hoisting the checks
+  // for index type out of loops.
 
-  // The integer vector index.
-  class OCTAVE_API idx_vector_rep : public idx_base_rep
-  {
-  public:
-
-    idx_vector_rep (void)
-      : data (nullptr), len (0), ext (0), aowner (nullptr), orig_dims ()
-    { }
-
-    // Direct constructor.
-    idx_vector_rep (octave_idx_type *_data, octave_idx_type _len,
-                    octave_idx_type _ext, const dim_vector& od, direct)
-      : idx_base_rep (), data (_data), len (_len), ext (_ext),
-        aowner (nullptr), orig_dims (od)
-    { }
-
-    // Zero-based constructor.
-    idx_vector_rep (const Array<octave_idx_type>& inda);
-
-    idx_vector_rep (const Array<octave_idx_type>& inda,
-                    octave_idx_type _ext, direct);
-
-    template <typename T>
-    idx_vector_rep (const Array<T>&);
-
-    idx_vector_rep (bool);
-
-    idx_vector_rep (const Array<bool>&, octave_idx_type = -1);
-
-    idx_vector_rep (const Sparse<bool>&);
-
-    // No copying!
-
-    idx_vector_rep (const idx_vector_rep& idx) = delete;
-
-    idx_vector_rep& operator = (const idx_vector_rep& idx) = delete;
-
-    ~idx_vector_rep (void);
-
-    octave_idx_type xelem (octave_idx_type i) const { return data[i]; }
-
-    octave_idx_type checkelem (octave_idx_type i) const;
-
-    octave_idx_type length (octave_idx_type) const { return len; }
-
-    octave_idx_type extent (octave_idx_type n) const
-    { return std::max (n, ext); }
-
-    idx_class_type idx_class (void) const { return class_vector; }
-
-    idx_base_rep * sort_uniq_clone (bool uniq = false);
-
-    idx_base_rep * sort_idx (Array<octave_idx_type>&);
-
-    dim_vector orig_dimensions (void) const { return orig_dims; }
-
-    const octave_idx_type * get_data (void) const { return data; }
-
-    std::ostream& print (std::ostream& os) const;
-
-    Array<double> unconvert (void) const;
-
-    Array<octave_idx_type> as_array (void);
-
-  private:
-
-    const octave_idx_type *data;
-    octave_idx_type len;
-    octave_idx_type ext;
-
-    // This is a trick to allow user-given zero-based arrays to be used
-    // as indices without copying.  If the following pointer is nonzero,
-    // we do not own the data, but rather have an Array<octave_idx_type>
-    // object that provides us the data.  Note that we need a pointer
-    // because we deferred the Array<T> declaration and we do not want
-    // it yet to be defined.
-
-    Array<octave_idx_type> *aowner;
-
-    dim_vector orig_dims;
-  };
-
-  // The logical mask index.
-  class OCTAVE_API idx_mask_rep : public idx_base_rep
+  class
+  OCTAVE_API
+  idx_vector
   {
   public:
 
-    idx_mask_rep (void) = delete;
-
-    // Direct constructor.
-    idx_mask_rep (bool *_data, octave_idx_type _len,
-                  octave_idx_type _ext, const dim_vector& od, direct)
-      : idx_base_rep (), data (_data), len (_len), ext (_ext),
-        lsti (-1), lste (-1), aowner (nullptr), orig_dims (od)
-    { }
-
-    idx_mask_rep (bool);
-
-    idx_mask_rep (const Array<bool>&, octave_idx_type = -1);
-
-    // No copying!
-
-    idx_mask_rep (const idx_mask_rep& idx) = delete;
+    enum idx_class_type
+    {
+      class_invalid = -1,
+      class_colon = 0,
+      class_range,
+      class_scalar,
+      class_vector,
+      class_mask
+    };
 
-    idx_mask_rep& operator = (const idx_mask_rep& idx) = delete;
-
-    ~idx_mask_rep (void);
-
-    octave_idx_type xelem (octave_idx_type i) const;
-
-    octave_idx_type checkelem (octave_idx_type i) const;
-
-    octave_idx_type length (octave_idx_type) const { return len; }
+    template <typename T, typename D> friend class std::unique_ptr;
 
-    octave_idx_type extent (octave_idx_type n) const
-    { return std::max (n, ext); }
-
-    idx_class_type idx_class (void) const { return class_mask; }
-
-    idx_base_rep * sort_uniq_clone (bool = false)
-    { count++; return this; }
-
-    idx_base_rep * sort_idx (Array<octave_idx_type>&);
+    private:
 
-    dim_vector orig_dimensions (void) const { return orig_dims; }
-
-    bool is_colon_equiv (octave_idx_type n) const
-    { return len == n && ext == n; }
-
-    const bool * get_data (void) const { return data; }
-
-    std::ostream& print (std::ostream& os) const;
+    class OCTAVE_API idx_base_rep
+    {
+    public:
 
-    Array<bool> unconvert (void) const;
-
-    Array<octave_idx_type> as_array (void);
+      idx_base_rep (void) : m_count (1) { }
 
-  private:
-
-    const bool *data;
-    octave_idx_type len;
-    octave_idx_type ext;
+      // No copying!
 
-    // FIXME: I'm not sure if this is a good design.  Maybe it would be
-    // better to employ some sort of generalized iteration scheme.
-    mutable octave_idx_type lsti;
-    mutable octave_idx_type lste;
+      idx_base_rep (const idx_base_rep&) = delete;
+
+      idx_base_rep& operator = (const idx_base_rep&) = delete;
 
-    // This is a trick to allow user-given mask arrays to be used as
-    // indices without copying.  If the following pointer is nonzero, we
-    // do not own the data, but rather have an Array<bool> object that
-    // provides us the data.  Note that we need a pointer because we
-    // deferred the Array<T> declaration and we do not want it yet to be
-    // defined.
+      virtual ~idx_base_rep (void) = default;
 
-    Array<bool> *aowner;
-
-    dim_vector orig_dims;
-  };
-
-  idx_vector (idx_base_rep *r) : rep (r) { }
+      // Non-range-checking element query.
+      virtual octave_idx_type xelem (octave_idx_type i) const = 0;
 
-  // The shared empty vector representation (for fast default
-  // constructor).
-  static idx_vector_rep *nil_rep (void);
-
-  // The shared empty vector representation with the error flag set.
-  static idx_vector_rep *err_rep (void);
+      // Range-checking element query.
+      virtual octave_idx_type checkelem (octave_idx_type i) const = 0;
 
-  // If there was an error in constructing the rep, replace it with
-  // empty vector for safety.
-  void chkerr (void)
-  {
-    if (rep->err)
-      {
-        if (--rep->count == 0)
-          delete rep;
-        rep = err_rep ();
-        rep->count++;
-      }
-  }
+      // Length of the index vector.
+      virtual octave_idx_type length (octave_idx_type n) const = 0;
 
-public:
-
-  // Fast empty constructor.
-  idx_vector (void) : rep (nil_rep ()) { rep->count++; }
-
-  // Zero-based constructors (for use from C++).
-  idx_vector (octave_idx_type i) : rep (new idx_scalar_rep (i))
-  { chkerr (); }
+      // The maximum index + 1.  The actual dimension is passed in.
+      virtual octave_idx_type extent (octave_idx_type n) const = 0;
 
-#if OCTAVE_SIZEOF_F77_INT_TYPE != OCTAVE_SIZEOF_IDX_TYPE
-  idx_vector (octave_f77_int_type i)
-    : rep (new idx_scalar_rep (static_cast<octave_idx_type> (i)))
-  { chkerr (); }
-#endif
+      // Index class.
+      virtual idx_class_type idx_class (void) const { return class_invalid; }
 
-  idx_vector (octave_idx_type start, octave_idx_type limit,
-              octave_idx_type step = 1)
-    : rep (new idx_range_rep (start, limit, step))
-  { chkerr (); }
+      // Sorts, maybe uniqifies, and returns a clone object pointer.
+      virtual idx_base_rep * sort_uniq_clone (bool uniq = false) = 0;
+      // Sorts, and returns a sorting permutation (aka Array::sort).
+      virtual idx_base_rep * sort_idx (Array<octave_idx_type>&) = 0;
 
-  static idx_vector
-  make_range (octave_idx_type start, octave_idx_type step,
-              octave_idx_type len)
-  {
-    return idx_vector (new idx_range_rep (start, len, step, DIRECT));
-  }
+      // Checks whether the index is colon or a range equivalent to colon.
+      virtual bool is_colon_equiv (octave_idx_type) const { return false; }
 
-  idx_vector (const Array<octave_idx_type>& inda)
-    : rep (new idx_vector_rep (inda))
-  { chkerr (); }
+      // The original dimensions of object (used when subscribing by matrices).
+      virtual dim_vector orig_dimensions (void) const { return dim_vector (); }
 
-  // Directly pass extent, no checking.
-  idx_vector (const Array<octave_idx_type>& inda, octave_idx_type ext)
-    : rep (new idx_vector_rep (inda, ext, DIRECT))
-  { }
-
-  // Colon is best constructed by simply copying (or referencing) this member.
-  static const idx_vector colon;
+      // i/o
+      virtual std::ostream& print (std::ostream& os) const = 0;
 
-  // or passing ':' here
-  idx_vector (char c) : rep (new idx_colon_rep (c)) { chkerr (); }
-
-  // Conversion constructors (used by interpreter).
+      virtual Array<octave_idx_type> as_array (void);
 
-  template <typename T>
-  idx_vector (octave_int<T> x) : rep (new idx_scalar_rep (x)) { chkerr (); }
-
-  idx_vector (double x) : rep (new idx_scalar_rep (x)) { chkerr (); }
+      refcount<octave_idx_type> m_count;
+    };
 
-  idx_vector (float x) : rep (new idx_scalar_rep (x)) { chkerr (); }
-
-  // A scalar bool does not necessarily map to scalar index.
-  idx_vector (bool x) : rep (new idx_mask_rep (x)) { chkerr (); }
-
-  template <typename T>
-  idx_vector (const Array<octave_int<T>>& nda) : rep (new idx_vector_rep (nda))
-  { chkerr (); }
-
-  idx_vector (const Array<double>& nda) : rep (new idx_vector_rep (nda))
-  { chkerr (); }
+    // The magic colon index.
+    class OCTAVE_API idx_colon_rep : public idx_base_rep
+    {
+    public:
 
-  idx_vector (const Array<float>& nda) : rep (new idx_vector_rep (nda))
-  { chkerr (); }
+      idx_colon_rep (void) = default;
 
-  idx_vector (const Array<bool>& nda);
+      OCTAVE_API idx_colon_rep (char c);
 
-  idx_vector (const Range& r)
-    : rep (new idx_range_rep (r))
-  { chkerr (); }
+      // No copying!
 
-  idx_vector (const Sparse<bool>& nda) : rep (new idx_vector_rep (nda))
-  { chkerr (); }
-
-  idx_vector (const idx_vector& a) : rep (a.rep) { rep->count++; }
+      idx_colon_rep (const idx_colon_rep& idx) = delete;
 
-  ~idx_vector (void)
-  {
-    if (--rep->count == 0 && rep != nil_rep ())
-      delete rep;
-  }
+      idx_colon_rep& operator = (const idx_colon_rep& idx) = delete;
+
+      octave_idx_type xelem (octave_idx_type i) const { return i; }
 
-  idx_vector& operator = (const idx_vector& a)
-  {
-    if (this != &a)
-      {
-        if (--rep->count == 0 && rep != nil_rep ())
-          delete rep;
+      OCTAVE_API octave_idx_type checkelem (octave_idx_type i) const;
 
-        rep = a.rep;
-        rep->count++;
-      }
-    return *this;
-  }
-
-  idx_class_type idx_class (void) const { return rep->idx_class (); }
-
-  octave_idx_type length (octave_idx_type n = 0) const
-  { return rep->length (n); }
+      octave_idx_type length (octave_idx_type n) const { return n; }
 
-  octave_idx_type extent (octave_idx_type n) const
-  { return rep->extent (n); }
-
-  octave_idx_type xelem (octave_idx_type n) const
-  { return rep->xelem (n); }
-
-  octave_idx_type checkelem (octave_idx_type n) const
-  { return rep->xelem (n); }
+      octave_idx_type extent (octave_idx_type n) const { return n; }
 
-  octave_idx_type operator () (octave_idx_type n) const
-  { return rep->xelem (n); }
+      idx_class_type idx_class (void) const { return class_colon; }
 
-  operator bool (void) const
-  { return ! rep->err; }
-
-  bool is_colon (void) const
-  { return rep->idx_class () == class_colon; }
+      idx_base_rep * sort_uniq_clone (bool = false)
+      { m_count++; return this; }
 
-  bool is_scalar (void) const
-  { return rep->idx_class () == class_scalar; }
+      OCTAVE_NORETURN idx_base_rep * sort_idx (Array<octave_idx_type>&);
 
-  bool is_range (void) const
-  { return rep->idx_class () == class_range; }
-
-  bool is_colon_equiv (octave_idx_type n) const
-  { return rep->is_colon_equiv (n); }
+      bool is_colon_equiv (octave_idx_type) const { return true; }
 
-  idx_vector sorted (bool uniq = false) const
-  { return idx_vector (rep->sort_uniq_clone (uniq)); }
-
-  idx_vector sorted (Array<octave_idx_type>& sidx) const
-  { return idx_vector (rep->sort_idx (sidx)); }
+      OCTAVE_API std::ostream& print (std::ostream& os) const;
+    };
 
-  dim_vector orig_dimensions (void) const { return rep->orig_dimensions (); }
-
-  octave_idx_type orig_rows (void) const
-  { return orig_dimensions () (0); }
-
-  octave_idx_type orig_columns (void) const
-  { return orig_dimensions () (1); }
+    // To distinguish the "direct" constructors that blindly trust the data.
+    enum direct { DIRECT };
 
-  int orig_empty (void) const
-  { return (! is_colon () && orig_dimensions ().any_zero ()); }
-
-  // i/o
+    // The integer range index.
+    class OCTAVE_API idx_range_rep : public idx_base_rep
+    {
+    public:
 
-  std::ostream& print (std::ostream& os) const { return rep->print (os); }
-
-  friend std::ostream& operator << (std::ostream& os, const idx_vector& a)
-  { return a.print (os); }
+      idx_range_rep (void) = delete;
 
-  // Slice with specializations.  No checking of bounds!
-  //
-  // This is equivalent to the following loop (but much faster):
-  //
-  // for (octave_idx_type i = 0; i < idx->length (n); i++)
-  //   dest[i] = src[idx(i)];
-  // return i;
-  //
-  template <typename T>
-  octave_idx_type
-  index (const T *src, octave_idx_type n, T *dest) const
-  {
-    octave_idx_type len = rep->length (n);
+      idx_range_rep (octave_idx_type start, octave_idx_type len,
+                     octave_idx_type step, direct)
+        : idx_base_rep (), m_start (start), m_len (len), m_step (step) { }
 
-    switch (rep->idx_class ())
-      {
-      case class_colon:
-        std::copy_n (src, len, dest);
-        break;
+      // Zero-based constructor.
+      idx_range_rep (octave_idx_type start, octave_idx_type limit,
+                     octave_idx_type step);
+
+      OCTAVE_API idx_range_rep (const range<double>&);
 
-      case class_range:
-        {
-          idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-          octave_idx_type start = r->get_start ();
-          octave_idx_type step = r->get_step ();
-          const T *ssrc = src + start;
-          if (step == 1)
-            std::copy_n (ssrc, len, dest);
-          else if (step == -1)
-            std::reverse_copy (ssrc - len + 1, ssrc + 1, dest);
-          else if (step == 0)
-            std::fill_n (dest, len, *ssrc);
-          else
-            {
-              for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
-                dest[i] = ssrc[j];
-            }
-        }
-        break;
+      // No copying!
+
+      idx_range_rep (const idx_range_rep& idx) = delete;
+
+      idx_range_rep& operator = (const idx_range_rep& idx) = delete;
 
-      case class_scalar:
-        {
-          idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-          dest[0] = src[r->get_data ()];
-        }
-        break;
+      octave_idx_type xelem (octave_idx_type i) const
+      { return m_start + i * m_step; }
+
+      octave_idx_type checkelem (octave_idx_type i) const;
 
-      case class_vector:
-        {
-          idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
-          const octave_idx_type *data = r->get_data ();
-          for (octave_idx_type i = 0; i < len; i++)
-            dest[i] = src[data[i]];
-        }
-        break;
+      octave_idx_type length (octave_idx_type) const { return m_len; }
 
-      case class_mask:
-        {
-          idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-          const bool *data = r->get_data ();
-          octave_idx_type ext = r->extent (0);
-          for (octave_idx_type i = 0; i < ext; i++)
-            if (data[i]) *dest++ = src[i];
-        }
-        break;
-
-      default:
-        assert (false);
-        break;
+      octave_idx_type extent (octave_idx_type n) const
+      {
+        return m_len ? std::max (n, m_start + 1 + (m_step < 0 ? 0 : m_step * (m_len - 1))) : n;
       }
 
-    return len;
-  }
+      idx_class_type idx_class (void) const { return class_range; }
+
+      OCTAVE_API idx_base_rep * sort_uniq_clone (bool uniq = false);
+
+      OCTAVE_API idx_base_rep * sort_idx (Array<octave_idx_type>&);
+
+      bool is_colon_equiv (octave_idx_type n) const
+      { return m_start == 0 && m_step == 1 && m_len == n; }
+
+      dim_vector orig_dimensions (void) const
+      { return dim_vector (1, m_len); }
+
+      octave_idx_type get_start (void) const { return m_start; }
+
+      octave_idx_type get_step (void) const { return m_step; }
+
+      OCTAVE_API std::ostream& print (std::ostream& os) const;
+
+      OCTAVE_API range<double> unconvert (void) const;
+
+      OCTAVE_API Array<octave_idx_type> as_array (void);
+
+    private:
 
-  // Slice assignment with specializations.  No checking of bounds!
-  //
-  // This is equivalent to the following loop (but much faster):
-  //
-  // for (octave_idx_type i = 0; i < idx->length (n); i++)
-  //   dest[idx(i)] = src[i];
-  // return i;
-  //
-  template <typename T>
-  octave_idx_type
-  assign (const T *src, octave_idx_type n, T *dest) const
-  {
-    octave_idx_type len = rep->length (n);
+      octave_idx_type m_start, m_len, m_step;
+    };
+
+    // The integer scalar index.
+    class OCTAVE_API idx_scalar_rep : public idx_base_rep
+    {
+    public:
+
+      idx_scalar_rep (void) = delete;
+
+      idx_scalar_rep (octave_idx_type i, direct) : idx_base_rep (), m_data (i) { }
+
+      // No copying!
+
+      idx_scalar_rep (const idx_scalar_rep& idx) = delete;
+
+      idx_scalar_rep& operator = (const idx_scalar_rep& idx) = delete;
+
+      // Zero-based constructor.
+      OCTAVE_API idx_scalar_rep (octave_idx_type i);
+
+      template <typename T>
+        idx_scalar_rep (T x);
+
+      octave_idx_type xelem (octave_idx_type) const { return m_data; }
 
-    switch (rep->idx_class ())
-      {
-      case class_colon:
-        std::copy_n (src, len, dest);
-        break;
+      OCTAVE_API octave_idx_type checkelem (octave_idx_type i) const;
+
+      octave_idx_type length (octave_idx_type) const { return 1; }
+
+      octave_idx_type extent (octave_idx_type n) const
+      { return std::max (n, m_data + 1); }
+
+      idx_class_type idx_class (void) const { return class_scalar; }
+
+      idx_base_rep * sort_uniq_clone (bool = false)
+      { m_count++; return this; }
+
+      OCTAVE_API idx_base_rep * sort_idx (Array<octave_idx_type>&);
+
+      bool is_colon_equiv (octave_idx_type n) const
+      { return n == 1 && m_data == 0; }
+
+      dim_vector orig_dimensions (void) const { return dim_vector (1, 1); }
+
+      octave_idx_type get_data (void) const { return m_data; }
+
+      OCTAVE_API std::ostream& print (std::ostream& os) const;
+
+      OCTAVE_API double unconvert (void) const;
 
-      case class_range:
-        {
-          idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-          octave_idx_type start = r->get_start ();
-          octave_idx_type step = r->get_step ();
-          T *sdest = dest + start;
-          if (step == 1)
-            std::copy_n (src, len, sdest);
-          else if (step == -1)
-            std::reverse_copy (src, src + len, sdest - len + 1);
-          else
-            {
-              for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
-                sdest[j] = src[i];
-            }
-        }
-        break;
+      OCTAVE_API Array<octave_idx_type> as_array (void);
+
+    private:
+
+      octave_idx_type m_data;
+    };
+
+    // The integer vector index.
+    class OCTAVE_API idx_vector_rep : public idx_base_rep
+    {
+    public:
+
+      idx_vector_rep (void)
+        : m_data (nullptr), m_len (0), m_ext (0), m_aowner (nullptr), m_orig_dims () { }
+
+      // Direct constructor.
+      idx_vector_rep (octave_idx_type *data, octave_idx_type len,
+                      octave_idx_type ext, const dim_vector& od, direct)
+        : idx_base_rep (), m_data (data), m_len (len), m_ext (ext),
+        m_aowner (nullptr), m_orig_dims (od)
+        { }
+
+      // Zero-based constructor.
+      OCTAVE_API idx_vector_rep (const Array<octave_idx_type>& inda);
 
-      case class_scalar:
-        {
-          idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-          dest[r->get_data ()] = src[0];
-        }
-        break;
+      OCTAVE_API idx_vector_rep (const Array<octave_idx_type>& inda,
+                                 octave_idx_type ext, direct);
+
+      template <typename T>
+        idx_vector_rep (const Array<T>&);
+
+      OCTAVE_API idx_vector_rep (bool);
+
+      OCTAVE_API idx_vector_rep (const Array<bool>&, octave_idx_type = -1);
+
+      OCTAVE_API idx_vector_rep (const Sparse<bool>&);
+
+      // No copying!
+
+      idx_vector_rep (const idx_vector_rep& idx) = delete;
+
+      idx_vector_rep& operator = (const idx_vector_rep& idx) = delete;
+
+      ~idx_vector_rep (void);
+
+      octave_idx_type xelem (octave_idx_type i) const { return m_data[i]; }
 
-      case class_vector:
-        {
-          idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
-          const octave_idx_type *data = r->get_data ();
-          for (octave_idx_type i = 0; i < len; i++)
-            dest[data[i]] = src[i];
-        }
-        break;
+      OCTAVE_API octave_idx_type checkelem (octave_idx_type i) const;
+
+      octave_idx_type length (octave_idx_type) const { return m_len; }
+
+      octave_idx_type extent (octave_idx_type n) const
+      { return std::max (n, m_ext); }
+
+      idx_class_type idx_class (void) const { return class_vector; }
+
+      idx_base_rep * sort_uniq_clone (bool uniq = false);
+
+      OCTAVE_API idx_base_rep * sort_idx (Array<octave_idx_type>&);
+
+      dim_vector orig_dimensions (void) const { return m_orig_dims; }
+
+      const octave_idx_type * get_data (void) const { return m_data; }
+
+      OCTAVE_API std::ostream& print (std::ostream& os) const;
+
+      OCTAVE_API Array<double> unconvert (void) const;
+
+      OCTAVE_API Array<octave_idx_type> as_array (void);
+
+    private:
 
-      case class_mask:
-        {
-          idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-          const bool *data = r->get_data ();
-          octave_idx_type ext = r->extent (0);
-          for (octave_idx_type i = 0; i < ext; i++)
-            if (data[i]) dest[i] = *src++;
-        }
-        break;
+      const octave_idx_type *m_data;
+      octave_idx_type m_len;
+      octave_idx_type m_ext;
+
+      // This is a trick to allow user-given zero-based arrays to be used
+      // as indices without copying.  If the following pointer is nonzero,
+      // we do not own the data, but rather have an Array<octave_idx_type>
+      // object that provides us the data.  Note that we need a pointer
+      // because we deferred the Array<T> declaration and we do not want
+      // it yet to be defined.
 
-      default:
-        assert (false);
-        break;
-      }
+      Array<octave_idx_type> *m_aowner;
+
+      dim_vector m_orig_dims;
+    };
+
+    // The logical mask index.
+    class OCTAVE_API idx_mask_rep : public idx_base_rep
+    {
+    public:
+
+      idx_mask_rep (void) = delete;
 
-    return len;
-  }
+      // Direct constructor.
+      idx_mask_rep (bool *data, octave_idx_type len,
+                    octave_idx_type ext, const dim_vector& od, direct)
+        : idx_base_rep (), m_data (data), m_len (len), m_ext (ext),
+        m_lsti (-1), m_lste (-1), m_aowner (nullptr), m_orig_dims (od)
+        { }
+
+      OCTAVE_API idx_mask_rep (bool);
+
+      OCTAVE_API idx_mask_rep (const Array<bool>&, octave_idx_type = -1);
+
+      // No copying!
+
+      idx_mask_rep (const idx_mask_rep& idx) = delete;
 
-  // Slice fill with specializations.  No checking of bounds!
-  //
-  // This is equivalent to the following loop (but much faster):
-  //
-  // for (octave_idx_type i = 0; i < idx->length (n); i++)
-  //   dest[idx(i)] = val;
-  // return i;
-  //
-  template <typename T>
-  octave_idx_type
-  fill (const T& val, octave_idx_type n, T *dest) const
-  {
-    octave_idx_type len = rep->length (n);
+      idx_mask_rep& operator = (const idx_mask_rep& idx) = delete;
+
+      OCTAVE_API ~idx_mask_rep (void);
+
+      octave_idx_type xelem (octave_idx_type i) const;
+
+      octave_idx_type checkelem (octave_idx_type i) const;
+
+      octave_idx_type length (octave_idx_type) const { return m_len; }
+
+      octave_idx_type extent (octave_idx_type n) const
+      { return std::max (n, m_ext); }
+
+      idx_class_type idx_class (void) const { return class_mask; }
 
-    switch (rep->idx_class ())
-      {
-      case class_colon:
-        std::fill_n (dest, len, val);
-        break;
+      idx_base_rep * sort_uniq_clone (bool = false)
+      { m_count++; return this; }
+
+      OCTAVE_API idx_base_rep * sort_idx (Array<octave_idx_type>&);
+
+      dim_vector orig_dimensions (void) const { return m_orig_dims; }
+
+      bool is_colon_equiv (octave_idx_type n) const
+      { return m_len == n && m_ext == n; }
+
+      const bool * get_data (void) const { return m_data; }
+
+      OCTAVE_API std::ostream& print (std::ostream& os) const;
+
+      OCTAVE_API Array<bool> unconvert (void) const;
+
+      OCTAVE_API Array<octave_idx_type> as_array (void);
+
+    private:
+
+      const bool *m_data;
+      octave_idx_type m_len;
+      octave_idx_type m_ext;
+
+      // FIXME: I'm not sure if this is a good design.  Maybe it would be
+      // better to employ some sort of generalized iteration scheme.
+      mutable octave_idx_type m_lsti;
+      mutable octave_idx_type m_lste;
+
+      // This is a trick to allow user-given mask arrays to be used as
+      // indices without copying.  If the following pointer is nonzero, we
+      // do not own the data, but rather have an Array<bool> object that
+      // provides us the data.  Note that we need a pointer because we
+      // deferred the Array<T> declaration and we do not want it yet to be
+      // defined.
+
+      Array<bool> *m_aowner;
+
+      dim_vector m_orig_dims;
+    };
+
+    idx_vector (idx_base_rep *r) : m_rep (r) { }
+
+    // The shared empty vector representation (for fast default
+    // constructor).
+    static OCTAVE_API idx_vector_rep *nil_rep (void);
+
+    public:
+
+    // Fast empty constructor.
+    idx_vector (void) : m_rep (nil_rep ()) { m_rep->m_count++; }
+
+    // Zero-based constructors (for use from C++).
+    idx_vector (octave_idx_type i) : m_rep (new idx_scalar_rep (i)) { }
+
+#if OCTAVE_SIZEOF_F77_INT_TYPE != OCTAVE_SIZEOF_IDX_TYPE
+    idx_vector (octave_f77_int_type i)
+    : m_rep (new idx_scalar_rep (static_cast<octave_idx_type> (i))) { }
+#endif
 
-      case class_range:
-        {
-          idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-          octave_idx_type start = r->get_start ();
-          octave_idx_type step = r->get_step ();
-          T *sdest = dest + start;
-          if (step == 1)
-            std::fill_n (sdest, len, val);
-          else if (step == -1)
-            std::fill (sdest - len + 1, sdest + 1, val);
-          else
-            {
-              for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
-                sdest[j] = val;
-            }
-        }
-        break;
+    idx_vector (octave_idx_type start, octave_idx_type limit,
+                octave_idx_type step = 1)
+    : m_rep (new idx_range_rep (start, limit, step)) { }
+
+    static idx_vector
+    make_range (octave_idx_type start, octave_idx_type step,
+                octave_idx_type len)
+    {
+      return idx_vector (new idx_range_rep (start, len, step, DIRECT));
+    }
+
+    idx_vector (const Array<octave_idx_type>& inda)
+    : m_rep (new idx_vector_rep (inda)) { }
+
+    // Directly pass extent, no checking.
+    idx_vector (const Array<octave_idx_type>& inda, octave_idx_type ext)
+    : m_rep (new idx_vector_rep (inda, ext, DIRECT)) { }
+
+    // Colon is best constructed by simply copying (or referencing) this member.
+    static const idx_vector colon;
+
+    // or passing ':' here
+    idx_vector (char c) : m_rep (new idx_colon_rep (c)) { }
+
+    // Conversion constructors (used by interpreter).
+
+    template <typename T>
+    idx_vector (octave_int<T> x) : m_rep (new idx_scalar_rep (x)) { }
+
+    idx_vector (double x) : m_rep (new idx_scalar_rep (x)) { }
 
-      case class_scalar:
-        {
-          idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-          dest[r->get_data ()] = val;
-        }
-        break;
+    idx_vector (float x) : m_rep (new idx_scalar_rep (x)) { }
+
+    // A scalar bool does not necessarily map to scalar index.
+    idx_vector (bool x) : m_rep (new idx_mask_rep (x)) { }
+
+    template <typename T>
+    idx_vector (const Array<octave_int<T>>& nda)
+    : m_rep (new idx_vector_rep (nda)) { }
+
+    idx_vector (const Array<double>& nda) : m_rep (new idx_vector_rep (nda)) { }
+
+    idx_vector (const Array<float>& nda) : m_rep (new idx_vector_rep (nda)) { }
+
+    OCTAVE_API idx_vector (const Array<bool>& nda);
 
-      case class_vector:
-        {
-          idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
-          const octave_idx_type *data = r->get_data ();
-          for (octave_idx_type i = 0; i < len; i++)
-            dest[data[i]] = val;
-        }
-        break;
+    idx_vector (const range<double>& r) : m_rep (new idx_range_rep (r)) { }
+
+    idx_vector (const Sparse<bool>& nda) : m_rep (new idx_vector_rep (nda)) { }
+
+    idx_vector (const idx_vector& a) : m_rep (a.m_rep) { m_rep->m_count++; }
 
-      case class_mask:
+    ~idx_vector (void)
+    {
+      if (--m_rep->m_count == 0 && m_rep != nil_rep ())
+        delete m_rep;
+    }
+
+    idx_vector& operator = (const idx_vector& a)
+    {
+      if (this != &a)
         {
-          idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-          const bool *data = r->get_data ();
-          octave_idx_type ext = r->extent (0);
-          for (octave_idx_type i = 0; i < ext; i++)
-            if (data[i]) dest[i] = val;
+          if (--m_rep->m_count == 0 && m_rep != nil_rep ())
+            delete m_rep;
+
+          m_rep = a.m_rep;
+          m_rep->m_count++;
         }
-        break;
+      return *this;
+    }
+
+    idx_class_type idx_class (void) const { return m_rep->idx_class (); }
+
+    octave_idx_type length (octave_idx_type n = 0) const
+    { return m_rep->length (n); }
+
+    octave_idx_type extent (octave_idx_type n) const
+    { return m_rep->extent (n); }
 
-      default:
-        assert (false);
-        break;
-      }
+    octave_idx_type xelem (octave_idx_type n) const
+    { return m_rep->xelem (n); }
+
+    octave_idx_type checkelem (octave_idx_type n) const
+    { return m_rep->xelem (n); }
+
+    octave_idx_type operator () (octave_idx_type n) const
+    { return m_rep->xelem (n); }
 
-    return len;
-  }
+    // FIXME: idx_vector objects are either created successfully or an
+    // error is thrown, so this method no longer makes sense.
+    operator bool (void) const { return true; }
 
-  // Generic non-breakable indexed loop.  The loop body should be
-  // encapsulated in a single functor body.  This is equivalent to the
-  // following loop (but faster, at least for simple inlined bodies):
-  //
-  // for (octave_idx_type i = 0; i < idx->length (n); i++) body (idx(i));
+    bool is_colon (void) const
+    { return m_rep->idx_class () == class_colon; }
+
+    bool is_scalar (void) const
+    { return m_rep->idx_class () == class_scalar; }
+
+    bool is_range (void) const
+    { return m_rep->idx_class () == class_range; }
 
-  template <typename Functor>
-  void
-  loop (octave_idx_type n, Functor body) const
-  {
-    octave_idx_type len = rep->length (n);
+    bool is_colon_equiv (octave_idx_type n) const
+    { return m_rep->is_colon_equiv (n); }
+
+    idx_vector sorted (bool uniq = false) const
+    { return idx_vector (m_rep->sort_uniq_clone (uniq)); }
+
+    idx_vector sorted (Array<octave_idx_type>& sidx) const
+    { return idx_vector (m_rep->sort_idx (sidx)); }
 
-    switch (rep->idx_class ())
-      {
-      case class_colon:
-        for (octave_idx_type i = 0; i < len; i++) body (i);
-        break;
+    dim_vector orig_dimensions (void) const { return m_rep->orig_dimensions (); }
+
+    octave_idx_type orig_rows (void) const
+    { return orig_dimensions () (0); }
+
+    octave_idx_type orig_columns (void) const
+    { return orig_dimensions () (1); }
+
+    int orig_empty (void) const
+    { return (! is_colon () && orig_dimensions ().any_zero ()); }
 
-      case class_range:
-        {
-          idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-          octave_idx_type start = r->get_start ();
-          octave_idx_type step = r->get_step ();
-          octave_idx_type i, j;
-          if (step == 1)
-            for (i = start, j = start + len; i < j; i++) body (i);
-          else if (step == -1)
-            for (i = start, j = start - len; i > j; i--) body (i);
-          else
-            for (i = 0, j = start; i < len; i++, j += step) body (j);
-        }
-        break;
+    // i/o
+
+    std::ostream& print (std::ostream& os) const { return m_rep->print (os); }
+
+    friend std::ostream& operator << (std::ostream& os, const idx_vector& a)
+    { return a.print (os); }
 
-      case class_scalar:
+    // Slice with specializations.  No checking of bounds!
+    //
+    // This is equivalent to the following loop (but much faster):
+    //
+    // for (octave_idx_type i = 0; i < idx->length (n); i++)
+    //   dest[i] = src[idx(i)];
+    // return i;
+    //
+    template <typename T>
+    octave_idx_type
+    index (const T *src, octave_idx_type n, T *dest) const
+    {
+      octave_idx_type len = m_rep->length (n);
+
+      switch (m_rep->idx_class ())
         {
-          idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-          body (r->get_data ());
-        }
-        break;
+        case class_colon:
+          std::copy_n (src, len, dest);
+          break;
+
+        case class_range:
+          {
+            idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+            octave_idx_type start = r->get_start ();
+            octave_idx_type step = r->get_step ();
+            const T *ssrc = src + start;
+            if (step == 1)
+              std::copy_n (ssrc, len, dest);
+            else if (step == -1)
+              std::reverse_copy (ssrc - len + 1, ssrc + 1, dest);
+            else if (step == 0)
+              std::fill_n (dest, len, *ssrc);
+            else
+              {
+                for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
+                  dest[i] = ssrc[j];
+              }
+          }
+          break;
 
-      case class_vector:
-        {
-          idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
-          const octave_idx_type *data = r->get_data ();
-          for (octave_idx_type i = 0; i < len; i++) body (data[i]);
-        }
-        break;
+        case class_scalar:
+          {
+            idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+            dest[0] = src[r->get_data ()];
+          }
+          break;
 
-      case class_mask:
-        {
-          idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-          const bool *data = r->get_data ();
-          octave_idx_type ext = r->extent (0);
-          for (octave_idx_type i = 0; i < ext; i++)
-            if (data[i]) body (i);
+        case class_vector:
+          {
+            idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+            const octave_idx_type *data = r->get_data ();
+            for (octave_idx_type i = 0; i < len; i++)
+              dest[i] = src[data[i]];
+          }
+          break;
+
+        case class_mask:
+          {
+            idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+            const bool *data = r->get_data ();
+            octave_idx_type ext = r->extent (0);
+            for (octave_idx_type i = 0; i < ext; i++)
+              if (data[i]) *dest++ = src[i];
+          }
+          break;
+
+        default:
+          assert (false);
+          break;
         }
-        break;
 
-      default:
-        assert (false);
-        break;
-      }
-
-  }
+      return len;
+    }
 
-  // Generic breakable indexed loop.  The loop body should be
-  // encapsulated in a single functor body.  This is equivalent to the
-  // following loop (but faster, at least for simple inlined bodies):
-  //
-  // for (octave_idx_type i = 0; i < idx->length (n); i++)
-  //   if (body (idx(i))) break;
-  // return i;
-  //
-
-  template <typename Functor>
-  octave_idx_type
-  bloop (octave_idx_type n, Functor body) const
-  {
-    octave_idx_type len = rep->length (n), ret;
+    // Slice assignment with specializations.  No checking of bounds!
+    //
+    // This is equivalent to the following loop (but much faster):
+    //
+    // for (octave_idx_type i = 0; i < idx->length (n); i++)
+    //   dest[idx(i)] = src[i];
+    // return i;
+    //
+    template <typename T>
+    octave_idx_type
+    assign (const T *src, octave_idx_type n, T *dest) const
+    {
+      octave_idx_type len = m_rep->length (n);
 
-    switch (rep->idx_class ())
-      {
-      case class_colon:
-        {
-          octave_idx_type i;
-          for (i = 0; i < len && body (i); i++) ;
-          ret = i;
-        }
-        break;
-
-      case class_range:
+      switch (m_rep->idx_class ())
         {
-          idx_range_rep *r = dynamic_cast<idx_range_rep *> (rep);
-          octave_idx_type start = r->get_start ();
-          octave_idx_type step = r->get_step ();
-          octave_idx_type i, j;
-          if (step == 1)
-            for (i = start, j = start + len; i < j && body (i); i++) ;
-          else if (step == -1)
-            for (i = start, j = start - len; i > j && body (i); i--) ;
-          else
-            for (i = 0, j = start; i < len && body (j); i++, j += step) ;
-          ret = i;
-        }
-        break;
+        case class_colon:
+          std::copy_n (src, len, dest);
+          break;
+
+        case class_range:
+          {
+            idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+            octave_idx_type start = r->get_start ();
+            octave_idx_type step = r->get_step ();
+            T *sdest = dest + start;
+            if (step == 1)
+              std::copy_n (src, len, sdest);
+            else if (step == -1)
+              std::reverse_copy (src, src + len, sdest - len + 1);
+            else
+              {
+                for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
+                  sdest[j] = src[i];
+              }
+          }
+          break;
+
+        case class_scalar:
+          {
+            idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+            dest[r->get_data ()] = src[0];
+          }
+          break;
 
-      case class_scalar:
-        {
-          idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (rep);
-          ret = (body (r->get_data ()) ? 1 : 0);
-        }
-        break;
+        case class_vector:
+          {
+            idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+            const octave_idx_type *data = r->get_data ();
+            for (octave_idx_type i = 0; i < len; i++)
+              dest[data[i]] = src[i];
+          }
+          break;
+
+        case class_mask:
+          {
+            idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+            const bool *data = r->get_data ();
+            octave_idx_type ext = r->extent (0);
+            for (octave_idx_type i = 0; i < ext; i++)
+              if (data[i]) dest[i] = *src++;
+          }
+          break;
 
-      case class_vector:
-        {
-          idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (rep);
-          const octave_idx_type *data = r->get_data ();
-          octave_idx_type i;
-          for (i = 0; i < len && body (data[i]); i++) ;
-          ret = i;
+        default:
+          assert (false);
+          break;
         }
-        break;
+
+      return len;
+    }
 
-      case class_mask:
+    // Slice fill with specializations.  No checking of bounds!
+    //
+    // This is equivalent to the following loop (but much faster):
+    //
+    // for (octave_idx_type i = 0; i < idx->length (n); i++)
+    //   dest[idx(i)] = val;
+    // return i;
+    //
+    template <typename T>
+    octave_idx_type
+    fill (const T& val, octave_idx_type n, T *dest) const
+    {
+      octave_idx_type len = m_rep->length (n);
+
+      switch (m_rep->idx_class ())
         {
-          idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (rep);
-          const bool *data = r->get_data ();
-          octave_idx_type ext = r->extent (0);
-          octave_idx_type j = 0;
-          for (octave_idx_type i = 0; i < ext; i++)
-            {
-              if (data[i])
-                {
-                  if (body (i))
-                    break;
-                  else
-                    j++;
-                }
-            }
+        case class_colon:
+          std::fill_n (dest, len, val);
+          break;
+
+        case class_range:
+          {
+            idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+            octave_idx_type start = r->get_start ();
+            octave_idx_type step = r->get_step ();
+            T *sdest = dest + start;
+            if (step == 1)
+              std::fill_n (sdest, len, val);
+            else if (step == -1)
+              std::fill (sdest - len + 1, sdest + 1, val);
+            else
+              {
+                for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
+                  sdest[j] = val;
+              }
+          }
+          break;
+
+        case class_scalar:
+          {
+            idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+            dest[r->get_data ()] = val;
+          }
+          break;
 
-          ret = j;
+        case class_vector:
+          {
+            idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+            const octave_idx_type *data = r->get_data ();
+            for (octave_idx_type i = 0; i < len; i++)
+              dest[data[i]] = val;
+          }
+          break;
+
+        case class_mask:
+          {
+            idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+            const bool *data = r->get_data ();
+            octave_idx_type ext = r->extent (0);
+            for (octave_idx_type i = 0; i < ext; i++)
+              if (data[i]) dest[i] = val;
+          }
+          break;
+
+        default:
+          assert (false);
+          break;
         }
-        break;
+
+      return len;
+    }
+
+    // Generic non-breakable indexed loop.  The loop body should be
+    // encapsulated in a single functor body.  This is equivalent to the
+    // following loop (but faster, at least for simple inlined bodies):
+    //
+    // for (octave_idx_type i = 0; i < idx->length (n); i++) body (idx(i));
+
+    template <typename Functor>
+    void
+    loop (octave_idx_type n, Functor body) const
+    {
+      octave_idx_type len = m_rep->length (n);
 
-      default:
-        assert (false);
-        break;
-      }
+      switch (m_rep->idx_class ())
+        {
+        case class_colon:
+          for (octave_idx_type i = 0; i < len; i++) body (i);
+          break;
 
-    return ret;
-  }
+        case class_range:
+          {
+            idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+            octave_idx_type start = r->get_start ();
+            octave_idx_type step = r->get_step ();
+            octave_idx_type i, j;
+            if (step == 1)
+              for (i = start, j = start + len; i < j; i++) body (i);
+            else if (step == -1)
+              for (i = start, j = start - len; i > j; i--) body (i);
+            else
+              for (i = 0, j = start; i < len; i++, j += step) body (j);
+          }
+          break;
 
-  // Rationale:
-  // This method is the key to "smart indexing".  When indexing cartesian
-  // arrays, sometimes consecutive index vectors can be reduced into a
-  // single index.  If rows (A) = k and i.maybe_reduce (j) gives k, then
-  // A(i,j)(:) is equal to A(k)(:).
+        case class_scalar:
+          {
+            idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+            body (r->get_data ());
+          }
+          break;
 
-  // If the next index can be reduced, returns true and updates this.
-  bool maybe_reduce (octave_idx_type n, const idx_vector& j,
-                     octave_idx_type nj);
+        case class_vector:
+          {
+            idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+            const octave_idx_type *data = r->get_data ();
+            for (octave_idx_type i = 0; i < len; i++) body (data[i]);
+          }
+          break;
 
-  bool is_cont_range (octave_idx_type n,
-                      octave_idx_type& l, octave_idx_type& u) const;
+        case class_mask:
+          {
+            idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+            const bool *data = r->get_data ();
+            octave_idx_type ext = r->extent (0);
+            for (octave_idx_type i = 0; i < ext; i++)
+              if (data[i]) body (i);
+          }
+          break;
 
-  // Returns the increment for ranges and colon, 0 for scalars and empty
-  // vectors, 1st difference otherwise.
-  octave_idx_type increment (void) const;
+        default:
+          assert (false);
+          break;
+        }
+
+    }
 
-  idx_vector
-  complement (octave_idx_type n) const;
+    // Generic breakable indexed loop.  The loop body should be
+    // encapsulated in a single functor body.  This is equivalent to the
+    // following loop (but faster, at least for simple inlined bodies):
+    //
+    // for (octave_idx_type i = 0; i < idx->length (n); i++)
+    //   if (body (idx(i))) break;
+    // return i;
+    //
+
+    template <typename Functor>
+    octave_idx_type
+    bloop (octave_idx_type n, Functor body) const
+    {
+      octave_idx_type len = m_rep->length (n), ret;
 
-  bool is_permutation (octave_idx_type n) const;
-
-  // Returns the inverse permutation.  If this is not a permutation on 1:n, the
-  // result is undefined (but no error unless extent () != n).
-  idx_vector inverse_permutation (octave_idx_type n) const;
+      switch (m_rep->idx_class ())
+        {
+        case class_colon:
+          {
+            octave_idx_type i;
+            for (i = 0; i < len && body (i); i++) ;
+            ret = i;
+          }
+          break;
 
-  // Copies all the indices to a given array.  Not allowed for colons.
-  void copy_data (octave_idx_type *data) const;
+        case class_range:
+          {
+            idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
+            octave_idx_type start = r->get_start ();
+            octave_idx_type step = r->get_step ();
+            octave_idx_type i, j;
+            if (step == 1)
+              for (i = start, j = start + len; i < j && body (i); i++) ;
+            else if (step == -1)
+              for (i = start, j = start - len; i > j && body (i); i--) ;
+            else
+              for (i = 0, j = start; i < len && body (j); i++, j += step) ;
+            ret = i;
+          }
+          break;
 
-  // If the index is a mask, convert it to index vector.
-  idx_vector unmask (void) const;
+        case class_scalar:
+          {
+            idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
+            ret = (body (r->get_data ()) ? 1 : 0);
+          }
+          break;
 
-  // Unconverts the index to a scalar, Range, double array or a mask.
-  void unconvert (idx_class_type& iclass,
-                  double& scalar, Range& range,
-                  Array<double>& array, Array<bool>& mask) const;
+        case class_vector:
+          {
+            idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
+            const octave_idx_type *data = r->get_data ();
+            octave_idx_type i;
+            for (i = 0; i < len && body (data[i]); i++) ;
+            ret = i;
+          }
+          break;
 
-  Array<octave_idx_type> as_array (void) const;
+        case class_mask:
+          {
+            idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
+            const bool *data = r->get_data ();
+            octave_idx_type ext = r->extent (0);
+            octave_idx_type j = 0;
+            for (octave_idx_type i = 0; i < ext; i++)
+              {
+                if (data[i])
+                  {
+                    if (body (i))
+                      break;
+                    else
+                      j++;
+                  }
+              }
 
-  // Raw pointer to index array.  This is non-const because it may be
-  // necessary to mutate the index.
-  const octave_idx_type * raw (void);
+            ret = j;
+          }
+          break;
 
-  bool isvector (void) const;
+        default:
+          assert (false);
+          break;
+        }
+
+      return ret;
+    }
 
-  // FIXME: these are here for compatibility.  They should be removed
-  // when no longer in use.
+    // Rationale:
+    // This method is the key to "smart indexing".  When indexing cartesian
+    // arrays, sometimes consecutive index vectors can be reduced into a
+    // single index.  If rows (A) = k and i.maybe_reduce (j) gives k, then
+    // A(i,j)(:) is equal to A(k)(:).
 
-  octave_idx_type elem (octave_idx_type n) const
-  { return (*this) (n); }
+    // If the next index can be reduced, returns true and updates this.
+    OCTAVE_API bool
+    maybe_reduce (octave_idx_type n, const idx_vector& j, octave_idx_type nj);
+
+    OCTAVE_API bool
+    is_cont_range (octave_idx_type n, octave_idx_type& l,
+                   octave_idx_type& u) const;
+
+    // Returns the increment for ranges and colon, 0 for scalars and empty
+    // vectors, 1st difference otherwise.
+    OCTAVE_API octave_idx_type increment (void) const;
 
-  bool is_colon_equiv (octave_idx_type n, int) const
-  { return is_colon_equiv (n); }
+    OCTAVE_API idx_vector
+    complement (octave_idx_type n) const;
+
+    OCTAVE_API bool is_permutation (octave_idx_type n) const;
+
+    // Returns the inverse permutation.  If this is not a permutation on 1:n, the
+    // result is undefined (but no error unless extent () != n).
+    OCTAVE_API idx_vector inverse_permutation (octave_idx_type n) const;
 
-  octave_idx_type
-  freeze (octave_idx_type z_len, const char *tag, bool resize_ok = false);
+    // Copies all the indices to a given array.  Not allowed for colons.
+    OCTAVE_API void copy_data (octave_idx_type *data) const;
+
+    // If the index is a mask, convert it to index vector.
+    OCTAVE_API idx_vector unmask (void) const;
+
+    // Unconverts the index to a scalar, Range, double array or a mask.
+    OCTAVE_API void
+    unconvert (idx_class_type& iclass, double& scalar, range<double>& range,
+               Array<double>& array, Array<bool>& mask) const;
 
-  void sort (bool uniq = false)
-  { *this = sorted (uniq); }
+    OCTAVE_API Array<octave_idx_type> as_array (void) const;
+
+    // Raw pointer to index array.  This is non-const because it may be
+    // necessary to mutate the index.
+    const OCTAVE_API octave_idx_type * raw (void);
+
+    OCTAVE_API bool isvector (void) const;
 
-  octave_idx_type ones_count (void) const;
+    // FIXME: these are here for compatibility.  They should be removed
+    // when no longer in use.
+
+    octave_idx_type elem (octave_idx_type n) const
+    { return (*this) (n); }
+
+    bool is_colon_equiv (octave_idx_type n, int) const
+    { return is_colon_equiv (n); }
 
-  octave_idx_type max (void) const { return extent (1) - 1; }
+    OCTAVE_API octave_idx_type
+    freeze (octave_idx_type z_len, const char *tag, bool resize_ok = false);
 
-private:
+    void sort (bool uniq = false)
+    { *this = sorted (uniq); }
+
+    OCTAVE_API octave_idx_type ones_count (void) const;
+
+    octave_idx_type max (void) const { return extent (1) - 1; }
 
-  idx_base_rep *rep;
+    private:
+
+    idx_base_rep *m_rep;
 
-};
+  };
+}
+
+// Provide the following typedef for backward compatibility.  Don't
+// deprecate (yet) because it is used extensively.
+
+typedef octave::idx_vector idx_vector;
 
 #endif
--- a/liboctave/array/int16NDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/int16NDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 #include "bsxfun-defs.cc"
 
-template class OCTAVE_API intNDArray<octave_int16>;
+INSTANTIATE_INTNDARRAY (octave_int16);
 
 template OCTAVE_API
 std::ostream&
--- a/liboctave/array/int32NDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/int32NDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 #include "bsxfun-defs.cc"
 
-template class OCTAVE_API intNDArray<octave_int32>;
+INSTANTIATE_INTNDARRAY (octave_int32);
 
 template OCTAVE_API
 std::ostream&
--- a/liboctave/array/int64NDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/int64NDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 #include "bsxfun-defs.cc"
 
-template class OCTAVE_API intNDArray<octave_int64>;
+INSTANTIATE_INTNDARRAY (octave_int64);
 
 template OCTAVE_API
 std::ostream&
--- a/liboctave/array/int8NDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/int8NDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 #include "bsxfun-defs.cc"
 
-template class OCTAVE_API intNDArray<octave_int8>;
+INSTANTIATE_INTNDARRAY (octave_int8);
 
 template OCTAVE_API
 std::ostream&
--- a/liboctave/array/intNDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/intNDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -300,3 +300,9 @@
 {
   return do_mx_diff_op<T> (*this, dim, order, mx_inline_diff);
 }
+
+#if defined (__clang__)
+#  define INSTANTIATE_INTNDARRAY(T) template class OCTAVE_API intNDArray<T>
+#else
+#  define INSTANTIATE_INTNDARRAY(T) template class intNDArray<T>
+#endif
--- a/liboctave/array/intNDArray.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/intNDArray.h	Sun May 16 09:44:35 2021 +0200
@@ -35,6 +35,7 @@
 
 template <typename T>
 class
+OCTAVE_API
 intNDArray : public MArray<T>
 {
 public:
@@ -65,14 +66,14 @@
   template <typename U>
   intNDArray (const intNDArray<U>& a) : MArray<T> (a) { }
 
-  boolNDArray operator ! (void) const;
+  OCTAVE_API boolNDArray operator ! (void) const;
 
   bool any_element_is_nan (void) const { return false; }
-  bool any_element_not_one_or_zero (void) const;
+  OCTAVE_API bool any_element_not_one_or_zero (void) const;
 
-  intNDArray diag (octave_idx_type k = 0) const;
+  OCTAVE_API intNDArray diag (octave_idx_type k = 0) const;
 
-  intNDArray diag (octave_idx_type m, octave_idx_type n) const;
+  OCTAVE_API intNDArray diag (octave_idx_type m, octave_idx_type n) const;
 
   intNDArray& changesign (void)
   {
@@ -82,28 +83,32 @@
 
   // FIXME: this is not quite the right thing.
 
-  boolNDArray all (int dim = -1) const;
-  boolNDArray any (int dim = -1) const;
+  OCTAVE_API boolNDArray all (int dim = -1) const;
+  OCTAVE_API boolNDArray any (int dim = -1) const;
 
-  intNDArray max (int dim = -1) const;
-  intNDArray max (Array<octave_idx_type>& index, int dim = -1) const;
-  intNDArray min (int dim = -1) const;
-  intNDArray min (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API intNDArray max (int dim = -1) const;
+  OCTAVE_API intNDArray
+  max (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API intNDArray min (int dim = -1) const;
+  OCTAVE_API intNDArray
+  min (Array<octave_idx_type>& index, int dim = -1) const;
 
-  intNDArray cummax (int dim = -1) const;
-  intNDArray cummax (Array<octave_idx_type>& index, int dim = -1) const;
-  intNDArray cummin (int dim = -1) const;
-  intNDArray cummin (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API intNDArray cummax (int dim = -1) const;
+  OCTAVE_API intNDArray
+  cummax (Array<octave_idx_type>& index, int dim = -1) const;
+  OCTAVE_API intNDArray cummin (int dim = -1) const;
+  OCTAVE_API intNDArray
+  cummin (Array<octave_idx_type>& index, int dim = -1) const;
 
-  intNDArray prod (int dim) const;
-  intNDArray sum (int dim) const;
-  NDArray dsum (int dim) const;
-  intNDArray cumsum (int dim) const;
+  OCTAVE_API intNDArray prod (int dim) const;
+  OCTAVE_API intNDArray sum (int dim) const;
+  OCTAVE_API NDArray dsum (int dim) const;
+  OCTAVE_API intNDArray cumsum (int dim) const;
 
-  intNDArray diff (octave_idx_type order = 1, int dim = -1) const;
+  OCTAVE_API intNDArray diff (octave_idx_type order = 1, int dim = -1) const;
 
-  intNDArray abs (void) const;
-  intNDArray signum (void) const;
+  OCTAVE_API intNDArray abs (void) const;
+  OCTAVE_API intNDArray signum (void) const;
 
   intNDArray squeeze (void) const
   { return intNDArray<T> (MArray<T>::squeeze ()); }
@@ -111,28 +116,30 @@
   intNDArray transpose (void) const
   { return intNDArray<T> (MArray<T>::transpose ()); }
 
-  intNDArray concat (const intNDArray<T>& rb,
-                     const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API intNDArray
+  concat (const intNDArray<T>& rb, const Array<octave_idx_type>& ra_idx);
 
-  intNDArray& insert (const intNDArray<T>& a,
-                      octave_idx_type r, octave_idx_type c);
-  intNDArray& insert (const intNDArray<T>& a,
-                      const Array<octave_idx_type>& ra_idx);
+  OCTAVE_API intNDArray&
+  insert (const intNDArray<T>& a, octave_idx_type r, octave_idx_type c);
+  OCTAVE_API intNDArray&
+  insert (const intNDArray<T>& a, const Array<octave_idx_type>& ra_idx);
 
-  static void increment_index (Array<octave_idx_type>& ra_idx,
-                               const dim_vector& dimensions,
-                               int start_dimension = 0);
+  static OCTAVE_API void
+  increment_index (Array<octave_idx_type>& ra_idx,
+                   const dim_vector& dimensions, int start_dimension = 0);
 
-  static octave_idx_type compute_index (Array<octave_idx_type>& ra_idx,
-                                        const dim_vector& dimensions);
+  static OCTAVE_API octave_idx_type
+  compute_index (Array<octave_idx_type>& ra_idx, const dim_vector& dimensions);
 };
 
 // i/o
 
 template <typename T>
-std::ostream& operator << (std::ostream& os, const intNDArray<T>& a);
+OCTAVE_API std::ostream&
+operator << (std::ostream& os, const intNDArray<T>& a);
 
 template <typename T>
-std::istream& operator >> (std::istream& is, intNDArray<T>& a);
+OCTAVE_API std::istream&
+operator >> (std::istream& is, intNDArray<T>& a);
 
 #endif
--- a/liboctave/array/uint16NDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/uint16NDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 #include "bsxfun-defs.cc"
 
-template class OCTAVE_API intNDArray<octave_uint16>;
+INSTANTIATE_INTNDARRAY (octave_uint16);
 
 template OCTAVE_API
 std::ostream&
--- a/liboctave/array/uint32NDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/uint32NDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 #include "bsxfun-defs.cc"
 
-template class OCTAVE_API intNDArray<octave_uint32>;
+INSTANTIATE_INTNDARRAY (octave_uint32);
 
 template OCTAVE_API
 std::ostream&
--- a/liboctave/array/uint64NDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/uint64NDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 #include "bsxfun-defs.cc"
 
-template class OCTAVE_API intNDArray<octave_uint64>;
+INSTANTIATE_INTNDARRAY (octave_uint64);
 
 template OCTAVE_API
 std::ostream&
--- a/liboctave/array/uint8NDArray.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/array/uint8NDArray.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 #include "bsxfun-defs.cc"
 
-template class OCTAVE_API intNDArray<octave_uint8>;
+INSTANTIATE_INTNDARRAY (octave_uint8);
 
 template OCTAVE_API
 std::ostream&
--- a/liboctave/external/odepack/cfode.f	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-      SUBROUTINE CFODE (METH, ELCO, TESCO)
-CLLL. OPTIMIZE
-      INTEGER METH
-      INTEGER I, IB, NQ, NQM1, NQP1
-      DOUBLE PRECISION ELCO, TESCO
-      DOUBLE PRECISION AGAMQ, FNQ, FNQM1, PC, PINT, RAGQ,
-     1   RQFAC, RQ1FAC, TSIGN, XPIN
-      DIMENSION ELCO(13,12), TESCO(3,12)
-C-----------------------------------------------------------------------
-C CFODE IS CALLED BY THE INTEGRATOR ROUTINE TO SET COEFFICIENTS
-C NEEDED THERE.  THE COEFFICIENTS FOR THE CURRENT METHOD, AS
-C GIVEN BY THE VALUE OF METH, ARE SET FOR ALL ORDERS AND SAVED.
-C THE MAXIMUM ORDER ASSUMED HERE IS 12 IF METH = 1 AND 5 IF METH = 2.
-C (A SMALLER VALUE OF THE MAXIMUM ORDER IS ALSO ALLOWED.)
-C CFODE IS CALLED ONCE AT THE BEGINNING OF THE PROBLEM,
-C AND IS NOT CALLED AGAIN UNLESS AND UNTIL METH IS CHANGED.
-C
-C THE ELCO ARRAY CONTAINS THE BASIC METHOD COEFFICIENTS.
-C THE COEFFICIENTS EL(I), 1 .LE. I .LE. NQ+1, FOR THE METHOD OF
-C ORDER NQ ARE STORED IN ELCO(I,NQ).  THEY ARE GIVEN BY A GENETRATING
-C POLYNOMIAL, I.E.,
-C     L(X) = EL(1) + EL(2)*X + ... + EL(NQ+1)*X**NQ.
-C FOR THE IMPLICIT ADAMS METHODS, L(X) IS GIVEN BY
-C     DL/DX = (X+1)*(X+2)*...*(X+NQ-1)/FACTORIAL(NQ-1),    L(-1) = 0.
-C FOR THE BDF METHODS, L(X) IS GIVEN BY
-C     L(X) = (X+1)*(X+2)* ... *(X+NQ)/K,
-C WHERE         K = FACTORIAL(NQ)*(1 + 1/2 + ... + 1/NQ).
-C
-C THE TESCO ARRAY CONTAINS TEST CONSTANTS USED FOR THE
-C LOCAL ERROR TEST AND THE SELECTION OF STEP SIZE AND/OR ORDER.
-C AT ORDER NQ, TESCO(K,NQ) IS USED FOR THE SELECTION OF STEP
-C SIZE AT ORDER NQ - 1 IF K = 1, AT ORDER NQ IF K = 2, AND AT ORDER
-C NQ + 1 IF K = 3.
-C-----------------------------------------------------------------------
-      DIMENSION PC(12)
-C
-      GO TO (100, 200), METH
-C
- 100  ELCO(1,1) = 1.0D0
-      ELCO(2,1) = 1.0D0
-      TESCO(1,1) = 0.0D0
-      TESCO(2,1) = 2.0D0
-      TESCO(1,2) = 1.0D0
-      TESCO(3,12) = 0.0D0
-      PC(1) = 1.0D0
-      RQFAC = 1.0D0
-      DO 140 NQ = 2,12
-C-----------------------------------------------------------------------
-C THE PC ARRAY WILL CONTAIN THE COEFFICIENTS OF THE POLYNOMIAL
-C     P(X) = (X+1)*(X+2)*...*(X+NQ-1).
-C INITIALLY, P(X) = 1.
-C-----------------------------------------------------------------------
-        RQ1FAC = RQFAC
-        RQFAC = RQFAC/DBLE(NQ)
-        NQM1 = NQ - 1
-        FNQM1 = DBLE(NQM1)
-        NQP1 = NQ + 1
-C FORM COEFFICIENTS OF P(X)*(X+NQ-1). ----------------------------------
-        PC(NQ) = 0.0D0
-        DO 110 IB = 1,NQM1
-          I = NQP1 - IB
- 110      PC(I) = PC(I-1) + FNQM1*PC(I)
-        PC(1) = FNQM1*PC(1)
-C COMPUTE INTEGRAL, -1 TO 0, OF P(X) AND X*P(X). -----------------------
-        PINT = PC(1)
-        XPIN = PC(1)/2.0D0
-        TSIGN = 1.0D0
-        DO 120 I = 2,NQ
-          TSIGN = -TSIGN
-          PINT = PINT + TSIGN*PC(I)/DBLE(I)
- 120      XPIN = XPIN + TSIGN*PC(I)/DBLE(I+1)
-C STORE COEFFICIENTS IN ELCO AND TESCO. --------------------------------
-        ELCO(1,NQ) = PINT*RQ1FAC
-        ELCO(2,NQ) = 1.0D0
-        DO 130 I = 2,NQ
- 130      ELCO(I+1,NQ) = RQ1FAC*PC(I)/DBLE(I)
-        AGAMQ = RQFAC*XPIN
-        RAGQ = 1.0D0/AGAMQ
-        TESCO(2,NQ) = RAGQ
-        IF (NQ .LT. 12) TESCO(1,NQP1) = RAGQ*RQFAC/DBLE(NQP1)
-        TESCO(3,NQM1) = RAGQ
- 140    CONTINUE
-      RETURN
-C
- 200  PC(1) = 1.0D0
-      RQ1FAC = 1.0D0
-      DO 230 NQ = 1,5
-C-----------------------------------------------------------------------
-C THE PC ARRAY WILL CONTAIN THE COEFFICIENTS OF THE POLYNOMIAL
-C     P(X) = (X+1)*(X+2)*...*(X+NQ).
-C INITIALLY, P(X) = 1.
-C-----------------------------------------------------------------------
-        FNQ = DBLE(NQ)
-        NQP1 = NQ + 1
-C FORM COEFFICIENTS OF P(X)*(X+NQ). ------------------------------------
-        PC(NQP1) = 0.0D0
-        DO 210 IB = 1,NQ
-          I = NQ + 2 - IB
- 210      PC(I) = PC(I-1) + FNQ*PC(I)
-        PC(1) = FNQ*PC(1)
-C STORE COEFFICIENTS IN ELCO AND TESCO. --------------------------------
-        DO 220 I = 1,NQP1
- 220      ELCO(I,NQ) = PC(I)/PC(2)
-        ELCO(2,NQ) = 1.0D0
-        TESCO(1,NQ) = RQ1FAC
-        TESCO(2,NQ) = DBLE(NQP1)/ELCO(1,NQ)
-        TESCO(3,NQ) = DBLE(NQ+2)/ELCO(1,NQ)
-        RQ1FAC = RQ1FAC/FNQ
- 230    CONTINUE
-      RETURN
-C----------------------- END OF SUBROUTINE CFODE -----------------------
-      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dcfode.f	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,127 @@
+      SUBROUTINE DCFODE (METH, ELCO, TESCO)
+C***BEGIN PROLOGUE  DCFODE
+C***SUBSIDIARY
+C***PURPOSE  Set ODE integrator coefficients.
+C***TYPE      DOUBLE PRECISION (SCFODE-S, DCFODE-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  DCFODE is called by the integrator routine to set coefficients
+C  needed there.  The coefficients for the current method, as
+C  given by the value of METH, are set for all orders and saved.
+C  The maximum order assumed here is 12 if METH = 1 and 5 if METH = 2.
+C  (A smaller value of the maximum order is also allowed.)
+C  DCFODE is called once at the beginning of the problem,
+C  and is not called again unless and until METH is changed.
+C
+C  The ELCO array contains the basic method coefficients.
+C  The coefficients el(i), 1 .le. i .le. nq+1, for the method of
+C  order nq are stored in ELCO(i,nq).  They are given by a genetrating
+C  polynomial, i.e.,
+C      l(x) = el(1) + el(2)*x + ... + el(nq+1)*x**nq.
+C  For the implicit Adams methods, l(x) is given by
+C      dl/dx = (x+1)*(x+2)*...*(x+nq-1)/factorial(nq-1),    l(-1) = 0.
+C  For the BDF methods, l(x) is given by
+C      l(x) = (x+1)*(x+2)* ... *(x+nq)/K,
+C  where         K = factorial(nq)*(1 + 1/2 + ... + 1/nq).
+C
+C  The TESCO array contains test constants used for the
+C  local error test and the selection of step size and/or order.
+C  At order nq, TESCO(k,nq) is used for the selection of step
+C  size at order nq - 1 if k = 1, at order nq if k = 2, and at order
+C  nq + 1 if k = 3.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C***END PROLOGUE  DCFODE
+C**End
+      INTEGER METH
+      INTEGER I, IB, NQ, NQM1, NQP1
+      DOUBLE PRECISION ELCO, TESCO
+      DOUBLE PRECISION AGAMQ, FNQ, FNQM1, PC, PINT, RAGQ,
+     1   RQFAC, RQ1FAC, TSIGN, XPIN
+      DIMENSION ELCO(13,12), TESCO(3,12)
+      DIMENSION PC(12)
+C
+C***FIRST EXECUTABLE STATEMENT  DCFODE
+      GO TO (100, 200), METH
+C
+ 100  ELCO(1,1) = 1.0D0
+      ELCO(2,1) = 1.0D0
+      TESCO(1,1) = 0.0D0
+      TESCO(2,1) = 2.0D0
+      TESCO(1,2) = 1.0D0
+      TESCO(3,12) = 0.0D0
+      PC(1) = 1.0D0
+      RQFAC = 1.0D0
+      DO 140 NQ = 2,12
+C-----------------------------------------------------------------------
+C The PC array will contain the coefficients of the polynomial
+C     p(x) = (x+1)*(x+2)*...*(x+nq-1).
+C Initially, p(x) = 1.
+C-----------------------------------------------------------------------
+        RQ1FAC = RQFAC
+        RQFAC = RQFAC/NQ
+        NQM1 = NQ - 1
+        FNQM1 = NQM1
+        NQP1 = NQ + 1
+C Form coefficients of p(x)*(x+nq-1). ----------------------------------
+        PC(NQ) = 0.0D0
+        DO 110 IB = 1,NQM1
+          I = NQP1 - IB
+ 110      PC(I) = PC(I-1) + FNQM1*PC(I)
+        PC(1) = FNQM1*PC(1)
+C Compute integral, -1 to 0, of p(x) and x*p(x). -----------------------
+        PINT = PC(1)
+        XPIN = PC(1)/2.0D0
+        TSIGN = 1.0D0
+        DO 120 I = 2,NQ
+          TSIGN = -TSIGN
+          PINT = PINT + TSIGN*PC(I)/I
+ 120      XPIN = XPIN + TSIGN*PC(I)/(I+1)
+C Store coefficients in ELCO and TESCO. --------------------------------
+        ELCO(1,NQ) = PINT*RQ1FAC
+        ELCO(2,NQ) = 1.0D0
+        DO 130 I = 2,NQ
+ 130      ELCO(I+1,NQ) = RQ1FAC*PC(I)/I
+        AGAMQ = RQFAC*XPIN
+        RAGQ = 1.0D0/AGAMQ
+        TESCO(2,NQ) = RAGQ
+        IF (NQ .LT. 12) TESCO(1,NQP1) = RAGQ*RQFAC/NQP1
+        TESCO(3,NQM1) = RAGQ
+ 140    CONTINUE
+      RETURN
+C
+ 200  PC(1) = 1.0D0
+      RQ1FAC = 1.0D0
+      DO 230 NQ = 1,5
+C-----------------------------------------------------------------------
+C The PC array will contain the coefficients of the polynomial
+C     p(x) = (x+1)*(x+2)*...*(x+nq).
+C Initially, p(x) = 1.
+C-----------------------------------------------------------------------
+        FNQ = NQ
+        NQP1 = NQ + 1
+C Form coefficients of p(x)*(x+nq). ------------------------------------
+        PC(NQP1) = 0.0D0
+        DO 210 IB = 1,NQ
+          I = NQ + 2 - IB
+ 210      PC(I) = PC(I-1) + FNQ*PC(I)
+        PC(1) = FNQ*PC(1)
+C Store coefficients in ELCO and TESCO. --------------------------------
+        DO 220 I = 1,NQP1
+ 220      ELCO(I,NQ) = PC(I)/PC(2)
+        ELCO(2,NQ) = 1.0D0
+        TESCO(1,NQ) = RQ1FAC
+        TESCO(2,NQ) = NQP1/ELCO(1,NQ)
+        TESCO(3,NQ) = (NQ+2)/ELCO(1,NQ)
+        RQ1FAC = RQ1FAC/FNQ
+ 230    CONTINUE
+      RETURN
+C----------------------- END OF SUBROUTINE DCFODE ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dewset.f	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,47 @@
+      SUBROUTINE DEWSET (N, ITOL, RTOL, ATOL, YCUR, EWT)
+C***BEGIN PROLOGUE  DEWSET
+C***SUBSIDIARY
+C***PURPOSE  Set error weight vector.
+C***TYPE      DOUBLE PRECISION (SEWSET-S, DEWSET-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  This subroutine sets the error weight vector EWT according to
+C      EWT(i) = RTOL(i)*ABS(YCUR(i)) + ATOL(i),  i = 1,...,N,
+C  with the subscript on RTOL and/or ATOL possibly replaced by 1 above,
+C  depending on the value of ITOL.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C***END PROLOGUE  DEWSET
+C**End
+      INTEGER N, ITOL
+      INTEGER I
+      DOUBLE PRECISION RTOL, ATOL, YCUR, EWT
+      DIMENSION RTOL(*), ATOL(*), YCUR(N), EWT(N)
+C
+C***FIRST EXECUTABLE STATEMENT  DEWSET
+      GO TO (10, 20, 30, 40), ITOL
+ 10   CONTINUE
+      DO 15 I = 1,N
+ 15     EWT(I) = RTOL(1)*ABS(YCUR(I)) + ATOL(1)
+      RETURN
+ 20   CONTINUE
+      DO 25 I = 1,N
+ 25     EWT(I) = RTOL(1)*ABS(YCUR(I)) + ATOL(I)
+      RETURN
+ 30   CONTINUE
+      DO 35 I = 1,N
+ 35     EWT(I) = RTOL(I)*ABS(YCUR(I)) + ATOL(1)
+      RETURN
+ 40   CONTINUE
+      DO 45 I = 1,N
+ 45     EWT(I) = RTOL(I)*ABS(YCUR(I)) + ATOL(I)
+      RETURN
+C----------------------- END OF SUBROUTINE DEWSET ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dintdy.f	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,110 @@
+      SUBROUTINE DINTDY (T, K, YH, NYH, DKY, IFLAG)
+C***BEGIN PROLOGUE  DINTDY
+C***SUBSIDIARY
+C***PURPOSE  Interpolate solution derivatives.
+C***TYPE      DOUBLE PRECISION (SINTDY-S, DINTDY-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  DINTDY computes interpolated values of the K-th derivative of the
+C  dependent variable vector y, and stores it in DKY.  This routine
+C  is called within the package with K = 0 and T = TOUT, but may
+C  also be called by the user for any K up to the current order.
+C  (See detailed instructions in the usage documentation.)
+C
+C  The computed values in DKY are gotten by interpolation using the
+C  Nordsieck history array YH.  This array corresponds uniquely to a
+C  vector-valued polynomial of degree NQCUR or less, and DKY is set
+C  to the K-th derivative of this polynomial at T.
+C  The formula for DKY is:
+C               q
+C   DKY(i)  =  sum  c(j,K) * (T - tn)**(j-K) * h**(-j) * YH(i,j+1)
+C              j=K
+C  where  c(j,K) = j*(j-1)*...*(j-K+1), q = NQCUR, tn = TCUR, h = HCUR.
+C  The quantities  nq = NQCUR, l = nq+1, N = NEQ, tn, and h are
+C  communicated by COMMON.  The above sum is done in reverse order.
+C  IFLAG is returned negative if either K or T is out of bounds.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  XERRWD
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C   010418  Reduced size of Common block /DLS001/. (ACH)
+C   031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C   050427  Corrected roundoff decrement in TP. (ACH)
+C***END PROLOGUE  DINTDY
+C**End
+      INTEGER K, NYH, IFLAG
+      DOUBLE PRECISION T, YH, DKY
+      DIMENSION YH(NYH,*), DKY(*)
+      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
+      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
+     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
+     1   HOLD, RMAX, TESCO(3,12),
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
+     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
+     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER I, IC, J, JB, JB2, JJ, JJ1, JP1
+      DOUBLE PRECISION C, R, S, TP
+      CHARACTER*80 MSG
+C
+C***FIRST EXECUTABLE STATEMENT  DINTDY
+      IFLAG = 0
+      IF (K .LT. 0 .OR. K .GT. NQ) GO TO 80
+      TP = TN - HU -  100.0D0*UROUND*SIGN(ABS(TN) + ABS(HU), HU)
+      IF ((T-TP)*(T-TN) .GT. 0.0D0) GO TO 90
+C
+      S = (T - TN)/H
+      IC = 1
+      IF (K .EQ. 0) GO TO 15
+      JJ1 = L - K
+      DO 10 JJ = JJ1,NQ
+ 10     IC = IC*JJ
+ 15   C = IC
+      DO 20 I = 1,N
+ 20     DKY(I) = C*YH(I,L)
+      IF (K .EQ. NQ) GO TO 55
+      JB2 = NQ - K
+      DO 50 JB = 1,JB2
+        J = NQ - JB
+        JP1 = J + 1
+        IC = 1
+        IF (K .EQ. 0) GO TO 35
+        JJ1 = JP1 - K
+        DO 30 JJ = JJ1,J
+ 30       IC = IC*JJ
+ 35     C = IC
+        DO 40 I = 1,N
+ 40       DKY(I) = C*YH(I,JP1) + S*DKY(I)
+ 50     CONTINUE
+      IF (K .EQ. 0) RETURN
+ 55   R = H**(-K)
+      DO 60 I = 1,N
+ 60     DKY(I) = R*DKY(I)
+      RETURN
+C
+ 80   MSG = 'DINTDY-  K (=I1) illegal      '
+      CALL XERRWD (MSG, 30, 51, 0, 1, K, 0, 0, 0.0D0, 0.0D0)
+      IFLAG = -1
+      RETURN
+ 90   MSG = 'DINTDY-  T (=R1) illegal      '
+      CALL XERRWD (MSG, 30, 52, 0, 0, 0, 0, 1, T, 0.0D0)
+      MSG='      T not in interval TCUR - HU (= R1) to TCUR (=R2)      '
+      CALL XERRWD (MSG, 60, 52, 0, 0, 0, 0, 2, TP, TN)
+      IFLAG = -2
+      RETURN
+C----------------------- END OF SUBROUTINE DINTDY ----------------------
+      END
--- a/liboctave/external/odepack/dlsode.f	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/external/odepack/dlsode.f	Sun May 16 09:44:35 2021 +0200
@@ -1,949 +1,1211 @@
       SUBROUTINE DLSODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
-     1            ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
+     1                  ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
       EXTERNAL F, JAC
       INTEGER NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, IWORK, LIW, MF
       DOUBLE PRECISION Y, T, TOUT, RTOL, ATOL, RWORK
       DIMENSION NEQ(*), Y(*), RTOL(*), ATOL(*), RWORK(LRW), IWORK(LIW)
-C-----------------------------------------------------------------------
-C THIS IS THE MARCH 30, 1987 VERSION OF
-C LSODE.. LIVERMORE SOLVER FOR ORDINARY DIFFERENTIAL EQUATIONS.
-C THIS VERSION IS IN DOUBLE PRECISION.
+C***BEGIN PROLOGUE  DLSODE
+C***PURPOSE  Livermore Solver for Ordinary Differential Equations.
+C            DLSODE solves the initial-value problem for stiff or
+C            nonstiff systems of first-order ODE's,
+C               dy/dt = f(t,y),   or, in component form,
+C               dy(i)/dt = f(i) = f(i,t,y(1),y(2),...,y(N)),  i=1,...,N.
+C***CATEGORY  I1A
+C***TYPE      DOUBLE PRECISION (SLSODE-S, DLSODE-D)
+C***KEYWORDS  ORDINARY DIFFERENTIAL EQUATIONS, INITIAL VALUE PROBLEM,
+C             STIFF, NONSTIFF
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C             Center for Applied Scientific Computing, L-561
+C             Lawrence Livermore National Laboratory
+C             Livermore, CA 94551.
+C***DESCRIPTION
+C
+C     NOTE: The "Usage" and "Arguments" sections treat only a subset of
+C           available options, in condensed fashion.  The options
+C           covered and the information supplied will support most
+C           standard uses of DLSODE.
+C
+C           For more sophisticated uses, full details on all options are
+C           given in the concluding section, headed "Long Description."
+C           A synopsis of the DLSODE Long Description is provided at the
+C           beginning of that section; general topics covered are:
+C           - Elements of the call sequence; optional input and output
+C           - Optional supplemental routines in the DLSODE package
+C           - internal COMMON block
 C
-C LSODE SOLVES THE INITIAL VALUE PROBLEM FOR STIFF OR NONSTIFF
-C SYSTEMS OF FIRST ORDER ODE-S,
-C     DY/DT = F(T,Y) ,  OR, IN COMPONENT FORM,
-C     DY(I)/DT = F(I) = F(I,T,Y(1),Y(2),...,Y(NEQ)) (I = 1,...,NEQ).
-C LSODE IS A PACKAGE BASED ON THE GEAR AND GEARB PACKAGES, AND ON THE
-C OCTOBER 23, 1978 VERSION OF THE TENTATIVE ODEPACK USER INTERFACE
-C STANDARD, WITH MINOR MODIFICATIONS.
-C-----------------------------------------------------------------------
-C REFERENCE..
-C     ALAN C. HINDMARSH,  ODEPACK, A SYSTEMATIZED COLLECTION OF ODE
-C     SOLVERS, IN SCIENTIFIC COMPUTING, R. S. STEPLEMAN ET AL. (EDS.),
-C     NORTH-HOLLAND, AMSTERDAM, 1983, PP. 55-64.
-C-----------------------------------------------------------------------
-C AUTHOR AND CONTACT.. ALAN C. HINDMARSH,
-C                      COMPUTING AND MATHEMATICS RESEARCH DIV., L-316
-C                      LAWRENCE LIVERMORE NATIONAL LABORATORY
-C                      LIVERMORE, CA 94550.
-C-----------------------------------------------------------------------
-C SUMMARY OF USAGE.
+C *Usage:
+C     Communication between the user and the DLSODE package, for normal
+C     situations, is summarized here.  This summary describes a subset
+C     of the available options.  See "Long Description" for complete
+C     details, including optional communication, nonstandard options,
+C     and instructions for special situations.
+C
+C     A sample program is given in the "Examples" section.
+C
+C     Refer to the argument descriptions for the definitions of the
+C     quantities that appear in the following sample declarations.
+C
+C     For MF = 10,
+C        PARAMETER  (LRW = 20 + 16*NEQ,           LIW = 20)
+C     For MF = 21 or 22,
+C        PARAMETER  (LRW = 22 +  9*NEQ + NEQ**2,  LIW = 20 + NEQ)
+C     For MF = 24 or 25,
+C        PARAMETER  (LRW = 22 + 10*NEQ + (2*ML+MU)*NEQ,
+C       *                                         LIW = 20 + NEQ)
 C
-C COMMUNICATION BETWEEN THE USER AND THE LSODE PACKAGE, FOR NORMAL
-C SITUATIONS, IS SUMMARIZED HERE.  THIS SUMMARY DESCRIBES ONLY A SUBSET
-C OF THE FULL SET OF OPTIONS AVAILABLE.  SEE THE FULL DESCRIPTION FOR
-C DETAILS, INCLUDING OPTIONAL COMMUNICATION, NONSTANDARD OPTIONS,
-C AND INSTRUCTIONS FOR SPECIAL SITUATIONS.  SEE ALSO THE EXAMPLE
-C PROBLEM (WITH PROGRAM AND OUTPUT) FOLLOWING THIS SUMMARY.
+C        EXTERNAL F, JAC
+C        INTEGER  NEQ, ITOL, ITASK, ISTATE, IOPT, LRW, IWORK(LIW),
+C       *         LIW, MF
+C        DOUBLE PRECISION Y(NEQ), T, TOUT, RTOL, ATOL(ntol), RWORK(LRW)
+C
+C        CALL DLSODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
+C       *            ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
+C
+C *Arguments:
+C     F     :EXT    Name of subroutine for right-hand-side vector f.
+C                   This name must be declared EXTERNAL in calling
+C                   program.  The form of F must be:
+C
+C                   SUBROUTINE  F (NEQ, T, Y, YDOT)
+C                   INTEGER  NEQ
+C                   DOUBLE PRECISION  T, Y(*), YDOT(*)
+C
+C                   The inputs are NEQ, T, Y.  F is to set
+C
+C                   YDOT(i) = f(i,T,Y(1),Y(2),...,Y(NEQ)),
+C                                                     i = 1, ..., NEQ .
 C
-C A. FIRST PROVIDE A SUBROUTINE OF THE FORM..
-C               SUBROUTINE F (NEQ, T, Y, YDOT, IERR)
-C               DIMENSION Y(NEQ), YDOT(NEQ)
-C WHICH SUPPLIES THE VECTOR FUNCTION F BY LOADING YDOT(I) WITH F(I).
+C     NEQ   :IN     Number of first-order ODE's.
+C
+C     Y     :INOUT  Array of values of the y(t) vector, of length NEQ.
+C                   Input:  For the first call, Y should contain the
+C                           values of y(t) at t = T. (Y is an input
+C                           variable only if ISTATE = 1.)
+C                   Output: On return, Y will contain the values at the
+C                           new t-value.
+C
+C     T     :INOUT  Value of the independent variable.  On return it
+C                   will be the current value of t (normally TOUT).
+C
+C     TOUT  :IN     Next point where output is desired (.NE. T).
+C
+C     ITOL  :IN     1 or 2 according as ATOL (below) is a scalar or
+C                   an array.
+C
+C     RTOL  :IN     Relative tolerance parameter (scalar).
+C
+C     ATOL  :IN     Absolute tolerance parameter (scalar or array).
+C                   If ITOL = 1, ATOL need not be dimensioned.
+C                   If ITOL = 2, ATOL must be dimensioned at least NEQ.
+C
+C                   The estimated local error in Y(i) will be controlled
+C                   so as to be roughly less (in magnitude) than
+C
+C                   EWT(i) = RTOL*ABS(Y(i)) + ATOL     if ITOL = 1, or
+C                   EWT(i) = RTOL*ABS(Y(i)) + ATOL(i)  if ITOL = 2.
+C
+C                   Thus the local error test passes if, in each
+C                   component, either the absolute error is less than
+C                   ATOL (or ATOL(i)), or the relative error is less
+C                   than RTOL.
 C
-C B. NEXT DETERMINE (OR GUESS) WHETHER OR NOT THE PROBLEM IS STIFF.
-C STIFFNESS OCCURS WHEN THE JACOBIAN MATRIX DF/DY HAS AN EIGENVALUE
-C WHOSE REAL PART IS NEGATIVE AND LARGE IN MAGNITUDE, COMPARED TO THE
-C RECIPROCAL OF THE T SPAN OF INTEREST.  IF THE PROBLEM IS NONSTIFF,
-C USE A METHOD FLAG MF = 10.  IF IT IS STIFF, THERE ARE FOUR STANDARD
-C CHOICES FOR MF, AND LSODE REQUIRES THE JACOBIAN MATRIX IN SOME FORM.
-C THIS MATRIX IS REGARDED EITHER AS FULL (MF = 21 OR 22),
-C OR BANDED (MF = 24 OR 25).  IN THE BANDED CASE, LSODE REQUIRES TWO
-C HALF-BANDWIDTH PARAMETERS ML AND MU.  THESE ARE, RESPECTIVELY, THE
-C WIDTHS OF THE LOWER AND UPPER PARTS OF THE BAND, EXCLUDING THE MAIN
-C DIAGONAL.  THUS THE BAND CONSISTS OF THE LOCATIONS (I,J) WITH
-C I-ML .LE. J .LE. I+MU, AND THE FULL BANDWIDTH IS ML+MU+1.
+C                   Use RTOL = 0.0 for pure absolute error control, and
+C                   use ATOL = 0.0 (or ATOL(i) = 0.0) for pure relative
+C                   error control.  Caution:  Actual (global) errors may
+C                   exceed these local tolerances, so choose them
+C                   conservatively.
+C
+C     ITASK :IN     Flag indicating the task DLSODE is to perform.
+C                   Use ITASK = 1 for normal computation of output
+C                   values of y at t = TOUT.
 C
-C C. IF THE PROBLEM IS STIFF, YOU ARE ENCOURAGED TO SUPPLY THE JACOBIAN
-C DIRECTLY (MF = 21 OR 24), BUT IF THIS IS NOT FEASIBLE, LSODE WILL
-C COMPUTE IT INTERNALLY BY DIFFERENCE QUOTIENTS (MF = 22 OR 25).
-C IF YOU ARE SUPPLYING THE JACOBIAN, PROVIDE A SUBROUTINE OF THE FORM..
-C               SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
-C               DIMENSION Y(NEQ), PD(NROWPD,NEQ)
-C WHICH SUPPLIES DF/DY BY LOADING PD AS FOLLOWS..
-C     FOR A FULL JACOBIAN (MF = 21), LOAD PD(I,J) WITH DF(I)/DY(J),
-C THE PARTIAL DERIVATIVE OF F(I) WITH RESPECT TO Y(J).  (IGNORE THE
-C ML AND MU ARGUMENTS IN THIS CASE.)
-C     FOR A BANDED JACOBIAN (MF = 24), LOAD PD(I-J+MU+1,J) WITH
-C DF(I)/DY(J), I.E. LOAD THE DIAGONAL LINES OF DF/DY INTO THE ROWS OF
-C PD FROM THE TOP DOWN.
-C     IN EITHER CASE, ONLY NONZERO ELEMENTS NEED BE LOADED.
+C     ISTATE:INOUT  Index used for input and output to specify the state
+C                   of the calculation.
+C                   Input:
+C                    1   This is the first call for a problem.
+C                    2   This is a subsequent call.
+C                   Output:
+C                    1   Nothing was done, because TOUT was equal to T.
+C                    2   DLSODE was successful (otherwise, negative).
+C                        Note that ISTATE need not be modified after a
+C                        successful return.
+C                   -1   Excess work done on this call (perhaps wrong
+C                        MF).
+C                   -2   Excess accuracy requested (tolerances too
+C                        small).
+C                   -3   Illegal input detected (see printed message).
+C                   -4   Repeated error test failures (check all
+C                        inputs).
+C                   -5   Repeated convergence failures (perhaps bad
+C                        Jacobian supplied or wrong choice of MF or
+C                        tolerances).
+C                   -6   Error weight became zero during problem
+C                        (solution component i vanished, and ATOL or
+C                        ATOL(i) = 0.).
+C
+C     IOPT  :IN     Flag indicating whether optional inputs are used:
+C                   0   No.
+C                   1   Yes.  (See "Optional inputs" under "Long
+C                       Description," Part 1.)
 C
-C D. WRITE A MAIN PROGRAM WHICH CALLS SUBROUTINE LSODE ONCE FOR
-C EACH POINT AT WHICH ANSWERS ARE DESIRED.  THIS SHOULD ALSO PROVIDE
-C FOR POSSIBLE USE OF LOGICAL UNIT 6 FOR OUTPUT OF ERROR MESSAGES
-C BY LSODE.  ON THE FIRST CALL TO LSODE, SUPPLY ARGUMENTS AS FOLLOWS..
-C F      = NAME OF SUBROUTINE FOR RIGHT-HAND SIDE VECTOR F.
-C          THIS NAME MUST BE DECLARED EXTERNAL IN CALLING PROGRAM.
-C NEQ    = NUMBER OF FIRST ORDER ODE-S.
-C Y      = ARRAY OF INITIAL VALUES, OF LENGTH NEQ.
-C T      = THE INITIAL VALUE OF THE INDEPENDENT VARIABLE.
-C TOUT   = FIRST POINT WHERE OUTPUT IS DESIRED (.NE. T).
-C ITOL   = 1 OR 2 ACCORDING AS ATOL (BELOW) IS A SCALAR OR ARRAY.
-C RTOL   = RELATIVE TOLERANCE PARAMETER (SCALAR).
-C ATOL   = ABSOLUTE TOLERANCE PARAMETER (SCALAR OR ARRAY).
-C          THE ESTIMATED LOCAL ERROR IN Y(I) WILL BE CONTROLLED SO AS
-C          TO BE ROUGHLY LESS (IN MAGNITUDE) THAN
-C             EWT(I) = RTOL*ABS(Y(I)) + ATOL     IF ITOL = 1, OR
-C             EWT(I) = RTOL*ABS(Y(I)) + ATOL(I)  IF ITOL = 2.
-C          THUS THE LOCAL ERROR TEST PASSES IF, IN EACH COMPONENT,
-C          EITHER THE ABSOLUTE ERROR IS LESS THAN ATOL (OR ATOL(I)),
-C          OR THE RELATIVE ERROR IS LESS THAN RTOL.
-C          USE RTOL = 0.0 FOR PURE ABSOLUTE ERROR CONTROL, AND
-C          USE ATOL = 0.0 (OR ATOL(I) = 0.0) FOR PURE RELATIVE ERROR
-C          CONTROL.  CAUTION.. ACTUAL (GLOBAL) ERRORS MAY EXCEED THESE
-C          LOCAL TOLERANCES, SO CHOOSE THEM CONSERVATIVELY.
-C ITASK  = 1 FOR NORMAL COMPUTATION OF OUTPUT VALUES OF Y AT T = TOUT.
-C ISTATE = INTEGER FLAG (INPUT AND OUTPUT).  SET ISTATE = 1.
-C IOPT   = 0 TO INDICATE NO OPTIONAL INPUTS USED.
-C RWORK  = REAL WORK ARRAY OF LENGTH AT LEAST..
-C             20 + 16*NEQ                    FOR MF = 10,
-C             22 +  9*NEQ + NEQ**2           FOR MF = 21 OR 22,
-C             22 + 10*NEQ + (2*ML + MU)*NEQ  FOR MF = 24 OR 25.
-C LRW    = DECLARED LENGTH OF RWORK (IN USER-S DIMENSION).
-C IWORK  = INTEGER WORK ARRAY OF LENGTH AT LEAST..
-C             20        FOR MF = 10,
-C             20 + NEQ  FOR MF = 21, 22, 24, OR 25.
-C          IF MF = 24 OR 25, INPUT IN IWORK(1),IWORK(2) THE LOWER
-C          AND UPPER HALF-BANDWIDTHS ML,MU.
-C LIW    = DECLARED LENGTH OF IWORK (IN USER-S DIMENSION).
-C JAC    = NAME OF SUBROUTINE FOR JACOBIAN MATRIX (MF = 21 OR 24).
-C          IF USED, THIS NAME MUST BE DECLARED EXTERNAL IN CALLING
-C          PROGRAM.  IF NOT USED, PASS A DUMMY NAME.
-C MF     = METHOD FLAG.  STANDARD VALUES ARE..
-C          10 FOR NONSTIFF (ADAMS) METHOD, NO JACOBIAN USED.
-C          21 FOR STIFF (BDF) METHOD, USER-SUPPLIED FULL JACOBIAN.
-C          22 FOR STIFF METHOD, INTERNALLY GENERATED FULL JACOBIAN.
-C          24 FOR STIFF METHOD, USER-SUPPLIED BANDED JACOBIAN.
-C          25 FOR STIFF METHOD, INTERNALLY GENERATED BANDED JACOBIAN.
-C NOTE THAT THE MAIN PROGRAM MUST DECLARE ARRAYS Y, RWORK, IWORK,
-C AND POSSIBLY ATOL.
+C     RWORK :WORK   Real work array of length at least:
+C                   20 + 16*NEQ                    for MF = 10,
+C                   22 +  9*NEQ + NEQ**2           for MF = 21 or 22,
+C                   22 + 10*NEQ + (2*ML + MU)*NEQ  for MF = 24 or 25.
+C
+C     LRW   :IN     Declared length of RWORK (in user's DIMENSION
+C                   statement).
+C
+C     IWORK :WORK   Integer work array of length at least:
+C                   20        for MF = 10,
+C                   20 + NEQ  for MF = 21, 22, 24, or 25.
+C
+C                   If MF = 24 or 25, input in IWORK(1),IWORK(2) the
+C                   lower and upper Jacobian half-bandwidths ML,MU.
+C
+C                   On return, IWORK contains information that may be
+C                   of interest to the user:
 C
-C E. THE OUTPUT FROM THE FIRST CALL (OR ANY CALL) IS..
-C      Y = ARRAY OF COMPUTED VALUES OF Y(T) VECTOR.
-C      T = CORRESPONDING VALUE OF INDEPENDENT VARIABLE (NORMALLY TOUT).
-C ISTATE = 2  IF LSODE WAS SUCCESSFUL, NEGATIVE OTHERWISE.
-C          -1 MEANS EXCESS WORK DONE ON THIS CALL (PERHAPS WRONG MF).
-C          -2 MEANS EXCESS ACCURACY REQUESTED (TOLERANCES TOO SMALL).
-C          -3 MEANS ILLEGAL INPUT DETECTED (SEE PRINTED MESSAGE).
-C          -4 MEANS REPEATED ERROR TEST FAILURES (CHECK ALL INPUTS).
-C          -5 MEANS REPEATED CONVERGENCE FAILURES (PERHAPS BAD JACOBIAN
-C             SUPPLIED OR WRONG CHOICE OF MF OR TOLERANCES).
-C          -6 MEANS ERROR WEIGHT BECAME ZERO DURING PROBLEM. (SOLUTION
-C             COMPONENT I VANISHED, AND ATOL OR ATOL(I) = 0.)
-C         -13 MEANS EXIT REQUESTED IN USER-SUPPLIED FUNCTION.
+C            Name   Location   Meaning
+C            -----  ---------  -----------------------------------------
+C            NST    IWORK(11)  Number of steps taken for the problem so
+C                              far.
+C            NFE    IWORK(12)  Number of f evaluations for the problem
+C                              so far.
+C            NJE    IWORK(13)  Number of Jacobian evaluations (and of
+C                              matrix LU decompositions) for the problem
+C                              so far.
+C            NQU    IWORK(14)  Method order last used (successfully).
+C            LENRW  IWORK(17)  Length of RWORK actually required.  This
+C                              is defined on normal returns and on an
+C                              illegal input return for insufficient
+C                              storage.
+C            LENIW  IWORK(18)  Length of IWORK actually required.  This
+C                              is defined on normal returns and on an
+C                              illegal input return for insufficient
+C                              storage.
+C
+C     LIW   :IN     Declared length of IWORK (in user's DIMENSION
+C                   statement).
+C
+C     JAC   :EXT    Name of subroutine for Jacobian matrix (MF =
+C                   21 or 24).  If used, this name must be declared
+C                   EXTERNAL in calling program.  If not used, pass a
+C                   dummy name.  The form of JAC must be:
 C
-C F. TO CONTINUE THE INTEGRATION AFTER A SUCCESSFUL RETURN, SIMPLY
-C RESET TOUT AND CALL LSODE AGAIN.  NO OTHER PARAMETERS NEED BE RESET.
+C                   SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
+C                   INTEGER  NEQ, ML, MU, NROWPD
+C                   DOUBLE PRECISION  T, Y(*), PD(NROWPD,*)
+C
+C                   See item c, under "Description" below for more
+C                   information about JAC.
 C
-C-----------------------------------------------------------------------
-C EXAMPLE PROBLEM.
+C     MF    :IN     Method flag.  Standard values are:
+C                   10  Nonstiff (Adams) method, no Jacobian used.
+C                   21  Stiff (BDF) method, user-supplied full Jacobian.
+C                   22  Stiff method, internally generated full
+C                       Jacobian.
+C                   24  Stiff method, user-supplied banded Jacobian.
+C                   25  Stiff method, internally generated banded
+C                       Jacobian.
+C
+C *Description:
+C     DLSODE solves the initial value problem for stiff or nonstiff
+C     systems of first-order ODE's,
+C
+C        dy/dt = f(t,y) ,
+C
+C     or, in component form,
+C
+C        dy(i)/dt = f(i) = f(i,t,y(1),y(2),...,y(NEQ))
+C                                                  (i = 1, ..., NEQ) .
 C
-C THE FOLLOWING IS A SIMPLE EXAMPLE PROBLEM, WITH THE CODING
-C NEEDED FOR ITS SOLUTION BY LSODE.  THE PROBLEM IS FROM CHEMICAL
-C KINETICS, AND CONSISTS OF THE FOLLOWING THREE RATE EQUATIONS..
-C     DY1/DT = -.04*Y1 + 1.E4*Y2*Y3
-C     DY2/DT = .04*Y1 - 1.E4*Y2*Y3 - 3.E7*Y2**2
-C     DY3/DT = 3.E7*Y2**2
-C ON THE INTERVAL FROM T = 0.0 TO T = 4.E10, WITH INITIAL CONDITIONS
-C Y1 = 1.0, Y2 = Y3 = 0.  THE PROBLEM IS STIFF.
+C     DLSODE is a package based on the GEAR and GEARB packages, and on
+C     the October 23, 1978, version of the tentative ODEPACK user
+C     interface standard, with minor modifications.
+C
+C     The steps in solving such a problem are as follows.
+C
+C     a. First write a subroutine of the form
+C
+C           SUBROUTINE  F (NEQ, T, Y, YDOT)
+C           INTEGER  NEQ
+C           DOUBLE PRECISION  T, Y(*), YDOT(*)
+C
+C        which supplies the vector function f by loading YDOT(i) with
+C        f(i).
 C
-C THE FOLLOWING CODING SOLVES THIS PROBLEM WITH LSODE, USING MF = 21
-C AND PRINTING RESULTS AT T = .4, 4., ..., 4.E10.  IT USES
-C ITOL = 2 AND ATOL MUCH SMALLER FOR Y2 THAN Y1 OR Y3 BECAUSE
-C Y2 HAS MUCH SMALLER VALUES.
-C AT THE END OF THE RUN, STATISTICAL QUANTITIES OF INTEREST ARE
-C PRINTED (SEE OPTIONAL OUTPUTS IN THE FULL DESCRIPTION BELOW).
+C     b. Next determine (or guess) whether or not the problem is stiff.
+C        Stiffness occurs when the Jacobian matrix df/dy has an
+C        eigenvalue whose real part is negative and large in magnitude
+C        compared to the reciprocal of the t span of interest.  If the
+C        problem is nonstiff, use method flag MF = 10.  If it is stiff,
+C        there are four standard choices for MF, and DLSODE requires the
+C        Jacobian matrix in some form.  This matrix is regarded either
+C        as full (MF = 21 or 22), or banded (MF = 24 or 25).  In the
+C        banded case, DLSODE requires two half-bandwidth parameters ML
+C        and MU. These are, respectively, the widths of the lower and
+C        upper parts of the band, excluding the main diagonal.  Thus the
+C        band consists of the locations (i,j) with
+C
+C           i - ML <= j <= i + MU ,
+C
+C        and the full bandwidth is ML + MU + 1 .
 C
-C     EXTERNAL FEX, JEX
-C     DOUBLE PRECISION ATOL, RTOL, RWORK, T, TOUT, Y
-C     DIMENSION Y(3), ATOL(3), RWORK(58), IWORK(23)
-C     NEQ = 3
-C     Y(1) = 1.D0
-C     Y(2) = 0.D0
-C     Y(3) = 0.D0
-C     T = 0.D0
-C     TOUT = .4D0
-C     ITOL = 2
-C     RTOL = 1.D-4
-C     ATOL(1) = 1.D-6
-C     ATOL(2) = 1.D-10
-C     ATOL(3) = 1.D-6
-C     ITASK = 1
-C     ISTATE = 1
-C     IOPT = 0
-C     LRW = 58
-C     LIW = 23
-C     MF = 21
-C     DO 40 IOUT = 1,12
-C       CALL LSODE(FEX,NEQ,Y,T,TOUT,ITOL,RTOL,ATOL,ITASK,ISTATE,
-C    1     IOPT,RWORK,LRW,IWORK,LIW,JEX,MF)
-C       WRITE(6,20)T,Y(1),Y(2),Y(3)
-C 20    FORMAT(7H AT T =,E12.4,6H   Y =,3E14.6)
-C       IF (ISTATE .LT. 0) GO TO 80
-C 40    TOUT = TOUT*10.D0
-C     WRITE(6,60)IWORK(11),IWORK(12),IWORK(13)
-C 60  FORMAT(/12H NO. STEPS =,I4,11H  NO. F-S =,I4,11H  NO. J-S =,I4)
-C     STOP
-C 80  WRITE(6,90)ISTATE
-C 90  FORMAT(///22H ERROR HALT.. ISTATE =,I3)
-C     STOP
-C     END
+C     c. If the problem is stiff, you are encouraged to supply the
+C        Jacobian directly (MF = 21 or 24), but if this is not feasible,
+C        DLSODE will compute it internally by difference quotients (MF =
+C        22 or 25).  If you are supplying the Jacobian, write a
+C        subroutine of the form
+C
+C           SUBROUTINE  JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
+C           INTEGER  NEQ, ML, MU, NRWOPD
+C           DOUBLE PRECISION  T, Y(*), PD(NROWPD,*)
+C
+C        which provides df/dy by loading PD as follows:
+C        - For a full Jacobian (MF = 21), load PD(i,j) with df(i)/dy(j),
+C          the partial derivative of f(i) with respect to y(j).  (Ignore
+C          the ML and MU arguments in this case.)
+C        - For a banded Jacobian (MF = 24), load PD(i-j+MU+1,j) with
+C          df(i)/dy(j); i.e., load the diagonal lines of df/dy into the
+C          rows of PD from the top down.
+C        - In either case, only nonzero elements need be loaded.
 C
-C     SUBROUTINE FEX (NEQ, T, Y, YDOT)
-C     DOUBLE PRECISION T, Y, YDOT
-C     DIMENSION Y(3), YDOT(3)
-C     YDOT(1) = -.04D0*Y(1) + 1.D4*Y(2)*Y(3)
-C     YDOT(3) = 3.D7*Y(2)*Y(2)
-C     YDOT(2) = -YDOT(1) - YDOT(3)
-C     RETURN
-C     END
+C     d. Write a main program that calls subroutine DLSODE once for each
+C        point at which answers are desired.  This should also provide
+C        for possible use of logical unit 6 for output of error messages
+C        by DLSODE.
+C
+C        Before the first call to DLSODE, set ISTATE = 1, set Y and T to
+C        the initial values, and set TOUT to the first output point.  To
+C        continue the integration after a successful return, simply
+C        reset TOUT and call DLSODE again.  No other parameters need be
+C        reset.
 C
-C     SUBROUTINE JEX (NEQ, T, Y, ML, MU, PD, NRPD)
-C     DOUBLE PRECISION PD, T, Y
-C     DIMENSION Y(3), PD(NRPD,3)
-C     PD(1,1) = -.04D0
-C     PD(1,2) = 1.D4*Y(3)
-C     PD(1,3) = 1.D4*Y(2)
-C     PD(2,1) = .04D0
-C     PD(2,3) = -PD(1,3)
-C     PD(3,2) = 6.D7*Y(2)
-C     PD(2,2) = -PD(1,2) - PD(3,2)
-C     RETURN
-C     END
+C *Examples:
+C     The following is a simple example problem, with the coding needed
+C     for its solution by DLSODE. The problem is from chemical kinetics,
+C     and consists of the following three rate equations:
 C
-C THE OUTPUT OF THIS PROGRAM (ON A CDC-7600 IN SINGLE PRECISION)
-C IS AS FOLLOWS..
+C        dy1/dt = -.04*y1 + 1.E4*y2*y3
+C        dy2/dt = .04*y1 - 1.E4*y2*y3 - 3.E7*y2**2
+C        dy3/dt = 3.E7*y2**2
+C
+C     on the interval from t = 0.0 to t = 4.E10, with initial conditions
+C     y1 = 1.0, y2 = y3 = 0. The problem is stiff.
 C
-C   AT T =  4.0000E-01   Y =  9.851726E-01  3.386406E-05  1.479357E-02
-C   AT T =  4.0000E+00   Y =  9.055142E-01  2.240418E-05  9.446344E-02
-C   AT T =  4.0000E+01   Y =  7.158050E-01  9.184616E-06  2.841858E-01
-C   AT T =  4.0000E+02   Y =  4.504846E-01  3.222434E-06  5.495122E-01
-C   AT T =  4.0000E+03   Y =  1.831701E-01  8.940379E-07  8.168290E-01
-C   AT T =  4.0000E+04   Y =  3.897016E-02  1.621193E-07  9.610297E-01
-C   AT T =  4.0000E+05   Y =  4.935213E-03  1.983756E-08  9.950648E-01
-C   AT T =  4.0000E+06   Y =  5.159269E-04  2.064759E-09  9.994841E-01
-C   AT T =  4.0000E+07   Y =  5.306413E-05  2.122677E-10  9.999469E-01
-C   AT T =  4.0000E+08   Y =  5.494529E-06  2.197824E-11  9.999945E-01
-C   AT T =  4.0000E+09   Y =  5.129458E-07  2.051784E-12  9.999995E-01
-C   AT T =  4.0000E+10   Y = -7.170586E-08 -2.868234E-13  1.000000E+00
-C
-C   NO. STEPS = 330  NO. F-S = 405  NO. J-S =  69
-C-----------------------------------------------------------------------
-C FULL DESCRIPTION OF USER INTERFACE TO LSODE.
-C
-C THE USER INTERFACE TO LSODE CONSISTS OF THE FOLLOWING PARTS.
-C
-C I.   THE CALL SEQUENCE TO SUBROUTINE LSODE, WHICH IS A DRIVER
-C      ROUTINE FOR THE SOLVER.  THIS INCLUDES DESCRIPTIONS OF BOTH
-C      THE CALL SEQUENCE ARGUMENTS AND OF USER-SUPPLIED ROUTINES.
-C      FOLLOWING THESE DESCRIPTIONS IS A DESCRIPTION OF
-C      OPTIONAL INPUTS AVAILABLE THROUGH THE CALL SEQUENCE, AND THEN
-C      A DESCRIPTION OF OPTIONAL OUTPUTS (IN THE WORK ARRAYS).
+C     The following coding solves this problem with DLSODE, using 
+C     MF = 21 and printing results at t = .4, 4., ..., 4.E10.  It uses 
+C     ITOL = 2 and ATOL much smaller for y2 than for y1 or y3 because y2 
+C     has much smaller values.  At the end of the run, statistical 
+C     quantities of interest are printed.
 C
-C II.  DESCRIPTIONS OF OTHER ROUTINES IN THE LSODE PACKAGE THAT MAY BE
-C      (OPTIONALLY) CALLED BY THE USER.  THESE PROVIDE THE ABILITY TO
-C      ALTER ERROR MESSAGE HANDLING, SAVE AND RESTORE THE INTERNAL
-C      COMMON, AND OBTAIN SPECIFIED DERIVATIVES OF THE SOLUTION Y(T).
-C
-C III. DESCRIPTIONS OF COMMON BLOCKS TO BE DECLARED IN OVERLAY
-C      OR SIMILAR ENVIRONMENTS, OR TO BE SAVED WHEN DOING AN INTERRUPT
-C      OF THE PROBLEM AND CONTINUED SOLUTION LATER.
-C
-C IV.  DESCRIPTION OF TWO ROUTINES IN THE LSODE PACKAGE, EITHER OF
-C      WHICH THE USER MAY REPLACE WITH HIS OWN VERSION, IF DESIRED.
-C      THESE RELATE TO THE MEASUREMENT OF ERRORS.
+C        EXTERNAL  FEX, JEX
+C        INTEGER  IOPT, IOUT, ISTATE, ITASK, ITOL, IWORK(23), LIW, LRW,
+C       *         MF, NEQ
+C        DOUBLE PRECISION  ATOL(3), RTOL, RWORK(58), T, TOUT, Y(3)
+C        NEQ = 3
+C        Y(1) = 1.D0
+C        Y(2) = 0.D0
+C        Y(3) = 0.D0
+C        T = 0.D0
+C        TOUT = .4D0
+C        ITOL = 2
+C        RTOL = 1.D-4
+C        ATOL(1) = 1.D-6
+C        ATOL(2) = 1.D-10
+C        ATOL(3) = 1.D-6
+C        ITASK = 1
+C        ISTATE = 1
+C        IOPT = 0
+C        LRW = 58
+C        LIW = 23
+C        MF = 21
+C        DO 40 IOUT = 1,12
+C          CALL DLSODE (FEX, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
+C       *               ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JEX, MF)
+C          WRITE(6,20)  T, Y(1), Y(2), Y(3)
+C    20    FORMAT(' At t =',D12.4,'   y =',3D14.6)
+C          IF (ISTATE .LT. 0)  GO TO 80
+C    40    TOUT = TOUT*10.D0
+C        WRITE(6,60)  IWORK(11), IWORK(12), IWORK(13)
+C    60  FORMAT(/' No. steps =',i4,',  No. f-s =',i4,',  No. J-s =',i4)
+C        STOP
+C    80  WRITE(6,90)  ISTATE
+C    90  FORMAT(///' Error halt.. ISTATE =',I3)
+C        STOP
+C        END
 C
-C-----------------------------------------------------------------------
-C PART I.  CALL SEQUENCE.
+C        SUBROUTINE  FEX (NEQ, T, Y, YDOT)
+C        INTEGER  NEQ
+C        DOUBLE PRECISION  T, Y(3), YDOT(3)
+C        YDOT(1) = -.04D0*Y(1) + 1.D4*Y(2)*Y(3)
+C        YDOT(3) = 3.D7*Y(2)*Y(2)
+C        YDOT(2) = -YDOT(1) - YDOT(3)
+C        RETURN
+C        END
 C
-C THE CALL SEQUENCE PARAMETERS USED FOR INPUT ONLY ARE
-C     F, NEQ, TOUT, ITOL, RTOL, ATOL, ITASK, IOPT, LRW, LIW, JAC, MF,
-C AND THOSE USED FOR BOTH INPUT AND OUTPUT ARE
-C     Y, T, ISTATE.
-C THE WORK ARRAYS RWORK AND IWORK ARE ALSO USED FOR CONDITIONAL AND
-C OPTIONAL INPUTS AND OPTIONAL OUTPUTS.  (THE TERM OUTPUT HERE REFERS
-C TO THE RETURN FROM SUBROUTINE LSODE TO THE USER-S CALLING PROGRAM.)
+C        SUBROUTINE  JEX (NEQ, T, Y, ML, MU, PD, NRPD)
+C        INTEGER  NEQ, ML, MU, NRPD
+C        DOUBLE PRECISION  T, Y(3), PD(NRPD,3)
+C        PD(1,1) = -.04D0
+C        PD(1,2) = 1.D4*Y(3)
+C        PD(1,3) = 1.D4*Y(2)
+C        PD(2,1) = .04D0
+C        PD(2,3) = -PD(1,3)
+C        PD(3,2) = 6.D7*Y(2)
+C        PD(2,2) = -PD(1,2) - PD(3,2)
+C        RETURN
+C        END
 C
-C THE LEGALITY OF INPUT PARAMETERS WILL BE THOROUGHLY CHECKED ON THE
-C INITIAL CALL FOR THE PROBLEM, BUT NOT CHECKED THEREAFTER UNLESS A
-C CHANGE IN INPUT PARAMETERS IS FLAGGED BY ISTATE = 3 ON INPUT.
+C     The output from this program (on a Cray-1 in single precision)
+C     is as follows.
 C
-C THE DESCRIPTIONS OF THE CALL ARGUMENTS ARE AS FOLLOWS.
+C     At t =  4.0000e-01   y =  9.851726e-01  3.386406e-05  1.479357e-02
+C     At t =  4.0000e+00   y =  9.055142e-01  2.240418e-05  9.446344e-02
+C     At t =  4.0000e+01   y =  7.158050e-01  9.184616e-06  2.841858e-01
+C     At t =  4.0000e+02   y =  4.504846e-01  3.222434e-06  5.495122e-01
+C     At t =  4.0000e+03   y =  1.831701e-01  8.940379e-07  8.168290e-01
+C     At t =  4.0000e+04   y =  3.897016e-02  1.621193e-07  9.610297e-01
+C     At t =  4.0000e+05   y =  4.935213e-03  1.983756e-08  9.950648e-01
+C     At t =  4.0000e+06   y =  5.159269e-04  2.064759e-09  9.994841e-01
+C     At t =  4.0000e+07   y =  5.306413e-05  2.122677e-10  9.999469e-01
+C     At t =  4.0000e+08   y =  5.494530e-06  2.197825e-11  9.999945e-01
+C     At t =  4.0000e+09   y =  5.129458e-07  2.051784e-12  9.999995e-01
+C     At t =  4.0000e+10   y = -7.170603e-08 -2.868241e-13  1.000000e+00
+C
+C     No. steps = 330,  No. f-s = 405,  No. J-s = 69
 C
-C F      = THE NAME OF THE USER-SUPPLIED SUBROUTINE DEFINING THE
-C          ODE SYSTEM.  THE SYSTEM MUST BE PUT IN THE FIRST-ORDER
-C          FORM DY/DT = F(T,Y), WHERE F IS A VECTOR-VALUED FUNCTION
-C          OF THE SCALAR T AND THE VECTOR Y.  SUBROUTINE F IS TO
-C          COMPUTE THE FUNCTION F.  IT IS TO HAVE THE FORM
-C               SUBROUTINE F (NEQ, T, Y, YDOT)
-C               DIMENSION Y(1), YDOT(1)
-C          WHERE NEQ, T, AND Y ARE INPUT, AND THE ARRAY YDOT = F(T,Y)
-C          IS OUTPUT.  Y AND YDOT ARE ARRAYS OF LENGTH NEQ.
-C          (IN THE DIMENSION STATEMENT ABOVE, 1 IS A DUMMY
-C          DIMENSION.. IT CAN BE REPLACED BY ANY VALUE.)
-C          SUBROUTINE F SHOULD NOT ALTER Y(1),...,Y(NEQ).
-C          F MUST BE DECLARED EXTERNAL IN THE CALLING PROGRAM.
+C *Accuracy:
+C     The accuracy of the solution depends on the choice of tolerances
+C     RTOL and ATOL.  Actual (global) errors may exceed these local
+C     tolerances, so choose them conservatively.
 C
-C          SUBROUTINE F MAY ACCESS USER-DEFINED QUANTITIES IN
-C          NEQ(2),... AND/OR IN Y(NEQ(1)+1),... IF NEQ IS AN ARRAY
-C          (DIMENSIONED IN F) AND/OR Y HAS LENGTH EXCEEDING NEQ(1).
-C          SEE THE DESCRIPTIONS OF NEQ AND Y BELOW.
+C *Cautions:
+C     The work arrays should not be altered between calls to DLSODE for
+C     the same problem, except possibly for the conditional and optional
+C     inputs.
 C
-C          IF QUANTITIES COMPUTED IN THE F ROUTINE ARE NEEDED
-C          EXTERNALLY TO LSODE, AN EXTRA CALL TO F SHOULD BE MADE
-C          FOR THIS PURPOSE, FOR CONSISTENT AND ACCURATE RESULTS.
-C          IF ONLY THE DERIVATIVE DY/DT IS NEEDED, USE INTDY INSTEAD.
+C *Portability:
+C     Since NEQ is dimensioned inside DLSODE, some compilers may object
+C     to a call to DLSODE with NEQ a scalar variable.  In this event, 
+C     use DIMENSION NEQ(1).  Similar remarks apply to RTOL and ATOL.
+C
+C     Note to Cray users:
+C     For maximum efficiency, use the CFT77 compiler.  Appropriate
+C     compiler optimization directives have been inserted for CFT77.
 C
-C NEQ    = THE SIZE OF THE ODE SYSTEM (NUMBER OF FIRST ORDER
-C          ORDINARY DIFFERENTIAL EQUATIONS).  USED ONLY FOR INPUT.
-C          NEQ MAY BE DECREASED, BUT NOT INCREASED, DURING THE PROBLEM.
-C          IF NEQ IS DECREASED (WITH ISTATE = 3 ON INPUT), THE
-C          REMAINING COMPONENTS OF Y SHOULD BE LEFT UNDISTURBED, IF
-C          THESE ARE TO BE ACCESSED IN F AND/OR JAC.
+C *Reference:
+C     Alan C. Hindmarsh, "ODEPACK, A Systematized Collection of ODE
+C     Solvers," in Scientific Computing, R. S. Stepleman, et al., Eds.
+C     (North-Holland, Amsterdam, 1983), pp. 55-64.
+C
+C *Long Description:
+C     The following complete description of the user interface to
+C     DLSODE consists of four parts:
+C
+C     1.  The call sequence to subroutine DLSODE, which is a driver
+C         routine for the solver.  This includes descriptions of both
+C         the call sequence arguments and user-supplied routines.
+C         Following these descriptions is a description of optional
+C         inputs available through the call sequence, and then a
+C         description of optional outputs in the work arrays.
+C
+C     2.  Descriptions of other routines in the DLSODE package that may
+C         be (optionally) called by the user.  These provide the ability
+C         to alter error message handling, save and restore the internal
+C         COMMON, and obtain specified derivatives of the solution y(t).
 C
-C          NORMALLY, NEQ IS A SCALAR, AND IT IS GENERALLY REFERRED TO
-C          AS A SCALAR IN THIS USER INTERFACE DESCRIPTION.  HOWEVER,
-C          NEQ MAY BE AN ARRAY, WITH NEQ(1) SET TO THE SYSTEM SIZE.
-C          (THE LSODE PACKAGE ACCESSES ONLY NEQ(1).)  IN EITHER CASE,
-C          THIS PARAMETER IS PASSED AS THE NEQ ARGUMENT IN ALL CALLS
-C          TO F AND JAC.  HENCE, IF IT IS AN ARRAY, LOCATIONS
-C          NEQ(2),... MAY BE USED TO STORE OTHER INTEGER DATA AND PASS
-C          IT TO F AND/OR JAC.  SUBROUTINES F AND/OR JAC MUST INCLUDE
-C          NEQ IN A DIMENSION STATEMENT IN THAT CASE.
+C     3.  Descriptions of COMMON block to be declared in overlay or
+C         similar environments, or to be saved when doing an interrupt
+C         of the problem and continued solution later.
+C
+C     4.  Description of two routines in the DLSODE package, either of
+C         which the user may replace with his own version, if desired.
+C         These relate to the measurement of errors.
+C
 C
-C Y      = A REAL ARRAY FOR THE VECTOR OF DEPENDENT VARIABLES, OF
-C          LENGTH NEQ OR MORE.  USED FOR BOTH INPUT AND OUTPUT ON THE
-C          FIRST CALL (ISTATE = 1), AND ONLY FOR OUTPUT ON OTHER CALLS.
-C          ON THE FIRST CALL, Y MUST CONTAIN THE VECTOR OF INITIAL
-C          VALUES.  ON OUTPUT, Y CONTAINS THE COMPUTED SOLUTION VECTOR,
-C          EVALUATED AT T.  IF DESIRED, THE Y ARRAY MAY BE USED
-C          FOR OTHER PURPOSES BETWEEN CALLS TO THE SOLVER.
+C                         Part 1.  Call Sequence
+C                         ----------------------
 C
-C          THIS ARRAY IS PASSED AS THE Y ARGUMENT IN ALL CALLS TO
-C          F AND JAC.  HENCE ITS LENGTH MAY EXCEED NEQ, AND LOCATIONS
-C          Y(NEQ+1),... MAY BE USED TO STORE OTHER REAL DATA AND
-C          PASS IT TO F AND/OR JAC.  (THE LSODE PACKAGE ACCESSES ONLY
-C          Y(1),...,Y(NEQ).)
+C     Arguments
+C     ---------
+C     The call sequence parameters used for input only are
+C
+C        F, NEQ, TOUT, ITOL, RTOL, ATOL, ITASK, IOPT, LRW, LIW, JAC, MF,
+C
+C     and those used for both input and output are
+C
+C        Y, T, ISTATE.
 C
-C T      = THE INDEPENDENT VARIABLE.  ON INPUT, T IS USED ONLY ON THE
-C          FIRST CALL, AS THE INITIAL POINT OF THE INTEGRATION.
-C          ON OUTPUT, AFTER EACH CALL, T IS THE VALUE AT WHICH A
-C          COMPUTED SOLUTION Y IS EVALUATED (USUALLY THE SAME AS TOUT).
-C          ON AN ERROR RETURN, T IS THE FARTHEST POINT REACHED.
+C     The work arrays RWORK and IWORK are also used for conditional and
+C     optional inputs and optional outputs.  (The term output here
+C     refers to the return from subroutine DLSODE to the user's calling
+C     program.)
 C
-C TOUT   = THE NEXT VALUE OF T AT WHICH A COMPUTED SOLUTION IS DESIRED.
-C          USED ONLY FOR INPUT.
+C     The legality of input parameters will be thoroughly checked on the
+C     initial call for the problem, but not checked thereafter unless a
+C     change in input parameters is flagged by ISTATE = 3 on input.
+C
+C     The descriptions of the call arguments are as follows.
 C
-C          WHEN STARTING THE PROBLEM (ISTATE = 1), TOUT MAY BE EQUAL
-C          TO T FOR ONE CALL, THEN SHOULD .NE. T FOR THE NEXT CALL.
-C          FOR THE INITIAL T, AN INPUT VALUE OF TOUT .NE. T IS USED
-C          IN ORDER TO DETERMINE THE DIRECTION OF THE INTEGRATION
-C          (I.E. THE ALGEBRAIC SIGN OF THE STEP SIZES) AND THE ROUGH
-C          SCALE OF THE PROBLEM.  INTEGRATION IN EITHER DIRECTION
-C          (FORWARD OR BACKWARD IN T) IS PERMITTED.
+C     F        The name of the user-supplied subroutine defining the ODE
+C              system.  The system must be put in the first-order form
+C              dy/dt = f(t,y), where f is a vector-valued function of
+C              the scalar t and the vector y. Subroutine F is to compute
+C              the function f. It is to have the form
+C
+C                 SUBROUTINE F (NEQ, T, Y, YDOT)
+C                 DOUBLE PRECISION  T, Y(*), YDOT(*)
 C
-C          IF ITASK = 2 OR 5 (ONE-STEP MODES), TOUT IS IGNORED AFTER
-C          THE FIRST CALL (I.E. THE FIRST CALL WITH TOUT .NE. T).
-C          OTHERWISE, TOUT IS REQUIRED ON EVERY CALL.
+C              where NEQ, T, and Y are input, and the array YDOT =
+C              f(T,Y) is output.  Y and YDOT are arrays of length NEQ.
+C              Subroutine F should not alter Y(1),...,Y(NEQ).  F must be
+C              declared EXTERNAL in the calling program.
 C
-C          IF ITASK = 1, 3, OR 4, THE VALUES OF TOUT NEED NOT BE
-C          MONOTONE, BUT A VALUE OF TOUT WHICH BACKS UP IS LIMITED
-C          TO THE CURRENT INTERNAL T INTERVAL, WHOSE ENDPOINTS ARE
-C          TCUR - HU AND TCUR (SEE OPTIONAL OUTPUTS, BELOW, FOR
-C          TCUR AND HU).
+C              Subroutine F may access user-defined quantities in
+C              NEQ(2),... and/or in Y(NEQ(1)+1),..., if NEQ is an array
+C              (dimensioned in F) and/or Y has length exceeding NEQ(1).
+C              See the descriptions of NEQ and Y below.
 C
-C ITOL   = AN INDICATOR FOR THE TYPE OF ERROR CONTROL.  SEE
-C          DESCRIPTION BELOW UNDER ATOL.  USED ONLY FOR INPUT.
+C              If quantities computed in the F routine are needed
+C              externally to DLSODE, an extra call to F should be made
+C              for this purpose, for consistent and accurate results.
+C              If only the derivative dy/dt is needed, use DINTDY
+C              instead.
 C
-C RTOL   = A RELATIVE ERROR TOLERANCE PARAMETER, EITHER A SCALAR OR
-C          AN ARRAY OF LENGTH NEQ.  SEE DESCRIPTION BELOW UNDER ATOL.
-C          INPUT ONLY.
-C
-C ATOL   = AN ABSOLUTE ERROR TOLERANCE PARAMETER, EITHER A SCALAR OR
-C          AN ARRAY OF LENGTH NEQ.  INPUT ONLY.
+C     NEQ      The size of the ODE system (number of first-order
+C              ordinary differential equations).  Used only for input.
+C              NEQ may be decreased, but not increased, during the
+C              problem.  If NEQ is decreased (with ISTATE = 3 on input),
+C              the remaining components of Y should be left undisturbed,
+C              if these are to be accessed in F and/or JAC.
 C
-C             THE INPUT PARAMETERS ITOL, RTOL, AND ATOL DETERMINE
-C          THE ERROR CONTROL PERFORMED BY THE SOLVER.  THE SOLVER WILL
-C          CONTROL THE VECTOR E = (E(I)) OF ESTIMATED LOCAL ERRORS
-C          IN Y, ACCORDING TO AN INEQUALITY OF THE FORM
-C                      RMS-NORM OF ( E(I)/EWT(I) )   .LE.   1,
-C          WHERE       EWT(I) = RTOL(I)*ABS(Y(I)) + ATOL(I),
-C          AND THE RMS-NORM (ROOT-MEAN-SQUARE NORM) HERE IS
-C          RMS-NORM(V) = SQRT(SUM V(I)**2 / NEQ).  HERE EWT = (EWT(I))
-C          IS A VECTOR OF WEIGHTS WHICH MUST ALWAYS BE POSITIVE, AND
-C          THE VALUES OF RTOL AND ATOL SHOULD ALL BE NON-NEGATIVE.
-C          THE FOLLOWING TABLE GIVES THE TYPES (SCALAR/ARRAY) OF
-C          RTOL AND ATOL, AND THE CORRESPONDING FORM OF EWT(I).
+C              Normally, NEQ is a scalar, and it is generally referred
+C              to as a scalar in this user interface description.
+C              However, NEQ may be an array, with NEQ(1) set to the
+C              system size.  (The DLSODE package accesses only NEQ(1).)
+C              In either case, this parameter is passed as the NEQ
+C              argument in all calls to F and JAC.  Hence, if it is an
+C              array, locations NEQ(2),... may be used to store other
+C              integer data and pass it to F and/or JAC.  Subroutines
+C              F and/or JAC must include NEQ in a DIMENSION statement
+C              in that case.
 C
-C             ITOL    RTOL       ATOL          EWT(I)
-C              1     SCALAR     SCALAR     RTOL*ABS(Y(I)) + ATOL
-C              2     SCALAR     ARRAY      RTOL*ABS(Y(I)) + ATOL(I)
-C              3     ARRAY      SCALAR     RTOL(I)*ABS(Y(I)) + ATOL
-C              4     ARRAY      ARRAY      RTOL(I)*ABS(Y(I)) + ATOL(I)
+C     Y        A real array for the vector of dependent variables, of
+C              length NEQ or more.  Used for both input and output on
+C              the first call (ISTATE = 1), and only for output on
+C              other calls.  On the first call, Y must contain the
+C              vector of initial values.  On output, Y contains the
+C              computed solution vector, evaluated at T. If desired,
+C              the Y array may be used for other purposes between
+C              calls to the solver.
+C
+C              This array is passed as the Y argument in all calls to F
+C              and JAC.  Hence its length may exceed NEQ, and locations
+C              Y(NEQ+1),... may be used to store other real data and
+C              pass it to F and/or JAC.  (The DLSODE package accesses
+C              only Y(1),...,Y(NEQ).)
 C
-C          WHEN EITHER OF THESE PARAMETERS IS A SCALAR, IT NEED NOT
-C          BE DIMENSIONED IN THE USER-S CALLING PROGRAM.
+C     T        The independent variable.  On input, T is used only on
+C              the first call, as the initial point of the integration.
+C              On output, after each call, T is the value at which a
+C              computed solution Y is evaluated (usually the same as
+C              TOUT).  On an error return, T is the farthest point
+C              reached.
 C
-C          IF NONE OF THE ABOVE CHOICES (WITH ITOL, RTOL, AND ATOL
-C          FIXED THROUGHOUT THE PROBLEM) IS SUITABLE, MORE GENERAL
-C          ERROR CONTROLS CAN BE OBTAINED BY SUBSTITUTING
-C          USER-SUPPLIED ROUTINES FOR THE SETTING OF EWT AND/OR FOR
-C          THE NORM CALCULATION.  SEE PART IV BELOW.
+C     TOUT     The next value of T at which a computed solution is
+C              desired.  Used only for input.
 C
-C          IF GLOBAL ERRORS ARE TO BE ESTIMATED BY MAKING A REPEATED
-C          RUN ON THE SAME PROBLEM WITH SMALLER TOLERANCES, THEN ALL
-C          COMPONENTS OF RTOL AND ATOL (I.E. OF EWT) SHOULD BE SCALED
-C          DOWN UNIFORMLY.
+C              When starting the problem (ISTATE = 1), TOUT may be equal
+C              to T for one call, then should not equal T for the next
+C              call.  For the initial T, an input value of TOUT .NE. T
+C              is used in order to determine the direction of the
+C              integration (i.e., the algebraic sign of the step sizes)
+C              and the rough scale of the problem.  Integration in
+C              either direction (forward or backward in T) is permitted.
 C
-C ITASK  = AN INDEX SPECIFYING THE TASK TO BE PERFORMED.
-C          INPUT ONLY.  ITASK HAS THE FOLLOWING VALUES AND MEANINGS.
-C          1  MEANS NORMAL COMPUTATION OF OUTPUT VALUES OF Y(T) AT
-C             T = TOUT (BY OVERSHOOTING AND INTERPOLATING).
-C          2  MEANS TAKE ONE STEP ONLY AND RETURN.
-C          3  MEANS STOP AT THE FIRST INTERNAL MESH POINT AT OR
-C             BEYOND T = TOUT AND RETURN.
-C          4  MEANS NORMAL COMPUTATION OF OUTPUT VALUES OF Y(T) AT
-C             T = TOUT BUT WITHOUT OVERSHOOTING T = TCRIT.
-C             TCRIT MUST BE INPUT AS RWORK(1).  TCRIT MAY BE EQUAL TO
-C             OR BEYOND TOUT, BUT NOT BEHIND IT IN THE DIRECTION OF
-C             INTEGRATION.  THIS OPTION IS USEFUL IF THE PROBLEM
-C             HAS A SINGULARITY AT OR BEYOND T = TCRIT.
-C          5  MEANS TAKE ONE STEP, WITHOUT PASSING TCRIT, AND RETURN.
-C             TCRIT MUST BE INPUT AS RWORK(1).
+C              If ITASK = 2 or 5 (one-step modes), TOUT is ignored
+C              after the first call (i.e., the first call with
+C              TOUT .NE. T).  Otherwise, TOUT is required on every call.
+C
+C              If ITASK = 1, 3, or 4, the values of TOUT need not be
+C              monotone, but a value of TOUT which backs up is limited
+C              to the current internal T interval, whose endpoints are
+C              TCUR - HU and TCUR.  (See "Optional Outputs" below for
+C              TCUR and HU.)
+C
+C
+C     ITOL     An indicator for the type of error control.  See
+C              description below under ATOL.  Used only for input.
+C
+C     RTOL     A relative error tolerance parameter, either a scalar or
+C              an array of length NEQ.  See description below under
+C              ATOL.  Input only.
+C
+C     ATOL     An absolute error tolerance parameter, either a scalar or
+C              an array of length NEQ.  Input only.
 C
-C          NOTE..  IF ITASK = 4 OR 5 AND THE SOLVER REACHES TCRIT
-C          (WITHIN ROUNDOFF), IT WILL RETURN T = TCRIT (EXACTLY) TO
-C          INDICATE THIS (UNLESS ITASK = 4 AND TOUT COMES BEFORE TCRIT,
-C          IN WHICH CASE ANSWERS AT T = TOUT ARE RETURNED FIRST).
+C              The input parameters ITOL, RTOL, and ATOL determine the
+C              error control performed by the solver.  The solver will
+C              control the vector e = (e(i)) of estimated local errors
+C              in Y, according to an inequality of the form
+C
+C                 rms-norm of ( e(i)/EWT(i) ) <= 1,
+C
+C              where
 C
-C ISTATE = AN INDEX USED FOR INPUT AND OUTPUT TO SPECIFY THE
-C          THE STATE OF THE CALCULATION.
+C                 EWT(i) = RTOL(i)*ABS(Y(i)) + ATOL(i),
+C
+C              and the rms-norm (root-mean-square norm) here is
+C
+C                 rms-norm(v) = SQRT(sum v(i)**2 / NEQ).
+C
+C              Here EWT = (EWT(i)) is a vector of weights which must
+C              always be positive, and the values of RTOL and ATOL
+C              should all be nonnegative.  The following table gives the
+C              types (scalar/array) of RTOL and ATOL, and the
+C              corresponding form of EWT(i).
 C
-C          ON INPUT, THE VALUES OF ISTATE ARE AS FOLLOWS.
-C          1  MEANS THIS IS THE FIRST CALL FOR THE PROBLEM
-C             (INITIALIZATIONS WILL BE DONE).  SEE NOTE BELOW.
-C          2  MEANS THIS IS NOT THE FIRST CALL, AND THE CALCULATION
-C             IS TO CONTINUE NORMALLY, WITH NO CHANGE IN ANY INPUT
-C             PARAMETERS EXCEPT POSSIBLY TOUT AND ITASK.
-C             (IF ITOL, RTOL, AND/OR ATOL ARE CHANGED BETWEEN CALLS
-C             WITH ISTATE = 2, THE NEW VALUES WILL BE USED BUT NOT
-C             TESTED FOR LEGALITY.)
-C          3  MEANS THIS IS NOT THE FIRST CALL, AND THE
-C             CALCULATION IS TO CONTINUE NORMALLY, BUT WITH
-C             A CHANGE IN INPUT PARAMETERS OTHER THAN
-C             TOUT AND ITASK.  CHANGES ARE ALLOWED IN
-C             NEQ, ITOL, RTOL, ATOL, IOPT, LRW, LIW, MF, ML, MU,
-C             AND ANY OF THE OPTIONAL INPUTS EXCEPT H0.
-C             (SEE IWORK DESCRIPTION FOR ML AND MU.)
-C          NOTE..  A PRELIMINARY CALL WITH TOUT = T IS NOT COUNTED
-C          AS A FIRST CALL HERE, AS NO INITIALIZATION OR CHECKING OF
-C          INPUT IS DONE.  (SUCH A CALL IS SOMETIMES USEFUL FOR THE
-C          PURPOSE OF OUTPUTTING THE INITIAL CONDITIONS.)
-C          THUS THE FIRST CALL FOR WHICH TOUT .NE. T REQUIRES
-C          ISTATE = 1 ON INPUT.
+C              ITOL    RTOL      ATOL      EWT(i)
+C              ----    ------    ------    -----------------------------
+C              1       scalar    scalar    RTOL*ABS(Y(i)) + ATOL
+C              2       scalar    array     RTOL*ABS(Y(i)) + ATOL(i)
+C              3       array     scalar    RTOL(i)*ABS(Y(i)) + ATOL
+C              4       array     array     RTOL(i)*ABS(Y(i)) + ATOL(i)
+C
+C              When either of these parameters is a scalar, it need not
+C              be dimensioned in the user's calling program.
+C
+C              If none of the above choices (with ITOL, RTOL, and ATOL
+C              fixed throughout the problem) is suitable, more general
+C              error controls can be obtained by substituting
+C              user-supplied routines for the setting of EWT and/or for
+C              the norm calculation.  See Part 4 below.
+C
+C              If global errors are to be estimated by making a repeated
+C              run on the same problem with smaller tolerances, then all
+C              components of RTOL and ATOL (i.e., of EWT) should be
+C              scaled down uniformly.
 C
-C          ON OUTPUT, ISTATE HAS THE FOLLOWING VALUES AND MEANINGS.
-C           1  MEANS NOTHING WAS DONE, AS TOUT WAS EQUAL TO T WITH
-C              ISTATE = 1 ON INPUT.  (HOWEVER, AN INTERNAL COUNTER WAS
-C              SET TO DETECT AND PREVENT REPEATED CALLS OF THIS TYPE.)
-C           2  MEANS THE INTEGRATION WAS PERFORMED SUCCESSFULLY.
-C          -1  MEANS AN EXCESSIVE AMOUNT OF WORK (MORE THAN MXSTEP
-C              STEPS) WAS DONE ON THIS CALL, BEFORE COMPLETING THE
-C              REQUESTED TASK, BUT THE INTEGRATION WAS OTHERWISE
-C              SUCCESSFUL AS FAR AS T.  (MXSTEP IS AN OPTIONAL INPUT
-C              AND IS NORMALLY 500.)  TO CONTINUE, THE USER MAY
-C              SIMPLY RESET ISTATE TO A VALUE .GT. 1 AND CALL AGAIN
-C              (THE EXCESS WORK STEP COUNTER WILL BE RESET TO 0).
-C              IN ADDITION, THE USER MAY INCREASE MXSTEP TO AVOID
-C              THIS ERROR RETURN (SEE BELOW ON OPTIONAL INPUTS).
-C          -2  MEANS TOO MUCH ACCURACY WAS REQUESTED FOR THE PRECISION
-C              OF THE MACHINE BEING USED.  THIS WAS DETECTED BEFORE
-C              COMPLETING THE REQUESTED TASK, BUT THE INTEGRATION
-C              WAS SUCCESSFUL AS FAR AS T.  TO CONTINUE, THE TOLERANCE
-C              PARAMETERS MUST BE RESET, AND ISTATE MUST BE SET
-C              TO 3.  THE OPTIONAL OUTPUT TOLSF MAY BE USED FOR THIS
-C              PURPOSE.  (NOTE.. IF THIS CONDITION IS DETECTED BEFORE
-C              TAKING ANY STEPS, THEN AN ILLEGAL INPUT RETURN
-C              (ISTATE = -3) OCCURS INSTEAD.)
-C          -3  MEANS ILLEGAL INPUT WAS DETECTED, BEFORE TAKING ANY
-C              INTEGRATION STEPS.  SEE WRITTEN MESSAGE FOR DETAILS.
-C              NOTE..  IF THE SOLVER DETECTS AN INFINITE LOOP OF CALLS
-C              TO THE SOLVER WITH ILLEGAL INPUT, IT WILL CAUSE
-C              THE RUN TO STOP.
-C          -4  MEANS THERE WERE REPEATED ERROR TEST FAILURES ON
-C              ONE ATTEMPTED STEP, BEFORE COMPLETING THE REQUESTED
-C              TASK, BUT THE INTEGRATION WAS SUCCESSFUL AS FAR AS T.
-C              THE PROBLEM MAY HAVE A SINGULARITY, OR THE INPUT
-C              MAY BE INAPPROPRIATE.
-C          -5  MEANS THERE WERE REPEATED CONVERGENCE TEST FAILURES ON
-C              ONE ATTEMPTED STEP, BEFORE COMPLETING THE REQUESTED
-C              TASK, BUT THE INTEGRATION WAS SUCCESSFUL AS FAR AS T.
-C              THIS MAY BE CAUSED BY AN INACCURATE JACOBIAN MATRIX,
-C              IF ONE IS BEING USED.
-C          -6  MEANS EWT(I) BECAME ZERO FOR SOME I DURING THE
-C              INTEGRATION.  PURE RELATIVE ERROR CONTROL (ATOL(I)=0.0)
-C              WAS REQUESTED ON A VARIABLE WHICH HAS NOW VANISHED.
-C              THE INTEGRATION WAS SUCCESSFUL AS FAR AS T.
+C     ITASK    An index specifying the task to be performed.  Input
+C              only.  ITASK has the following values and meanings:
+C              1   Normal computation of output values of y(t) at
+C                  t = TOUT (by overshooting and interpolating).
+C              2   Take one step only and return.
+C              3   Stop at the first internal mesh point at or beyond
+C                  t = TOUT and return.
+C              4   Normal computation of output values of y(t) at
+C                  t = TOUT but without overshooting t = TCRIT.  TCRIT
+C                  must be input as RWORK(1).  TCRIT may be equal to or
+C                  beyond TOUT, but not behind it in the direction of
+C                  integration.  This option is useful if the problem
+C                  has a singularity at or beyond t = TCRIT.
+C              5   Take one step, without passing TCRIT, and return.
+C                  TCRIT must be input as RWORK(1).
+C
+C              Note:  If ITASK = 4 or 5 and the solver reaches TCRIT
+C              (within roundoff), it will return T = TCRIT (exactly) to
+C              indicate this (unless ITASK = 4 and TOUT comes before
+C              TCRIT, in which case answers at T = TOUT are returned
+C              first).
 C
-C          NOTE..  SINCE THE NORMAL OUTPUT VALUE OF ISTATE IS 2,
-C          IT DOES NOT NEED TO BE RESET FOR NORMAL CONTINUATION.
-C          ALSO, SINCE A NEGATIVE INPUT VALUE OF ISTATE WILL BE
-C          REGARDED AS ILLEGAL, A NEGATIVE OUTPUT VALUE REQUIRES THE
-C          USER TO CHANGE IT, AND POSSIBLY OTHER INPUTS, BEFORE
-C          CALLING THE SOLVER AGAIN.
+C     ISTATE   An index used for input and output to specify the state
+C              of the calculation.
 C
-C IOPT   = AN INTEGER FLAG TO SPECIFY WHETHER OR NOT ANY OPTIONAL
-C          INPUTS ARE BEING USED ON THIS CALL.  INPUT ONLY.
-C          THE OPTIONAL INPUTS ARE LISTED SEPARATELY BELOW.
-C          IOPT = 0 MEANS NO OPTIONAL INPUTS ARE BEING USED.
-C                   DEFAULT VALUES WILL BE USED IN ALL CASES.
-C          IOPT = 1 MEANS ONE OR MORE OPTIONAL INPUTS ARE BEING USED.
+C              On input, the values of ISTATE are as follows:
+C              1   This is the first call for the problem
+C                  (initializations will be done).  See "Note" below.
+C              2   This is not the first call, and the calculation is to
+C                  continue normally, with no change in any input
+C                  parameters except possibly TOUT and ITASK.  (If ITOL,
+C                  RTOL, and/or ATOL are changed between calls with
+C                  ISTATE = 2, the new values will be used but not
+C                  tested for legality.)
+C              3   This is not the first call, and the calculation is to
+C                  continue normally, but with a change in input
+C                  parameters other than TOUT and ITASK.  Changes are
+C                  allowed in NEQ, ITOL, RTOL, ATOL, IOPT, LRW, LIW, MF,
+C                  ML, MU, and any of the optional inputs except H0.
+C                  (See IWORK description for ML and MU.)
+C
+C              Note:  A preliminary call with TOUT = T is not counted as
+C              a first call here, as no initialization or checking of
+C              input is done.  (Such a call is sometimes useful for the
+C              purpose of outputting the initial conditions.)  Thus the
+C              first call for which TOUT .NE. T requires ISTATE = 1 on
+C              input.
 C
-C RWORK  = A REAL WORKING ARRAY (DOUBLE PRECISION).
-C          THE LENGTH OF RWORK MUST BE AT LEAST
-C             20 + NYH*(MAXORD + 1) + 3*NEQ + LWM    WHERE
-C          NYH    = THE INITIAL VALUE OF NEQ,
-C          MAXORD = 12 (IF METH = 1) OR 5 (IF METH = 2) (UNLESS A
-C                   SMALLER VALUE IS GIVEN AS AN OPTIONAL INPUT),
-C          LWM   = 0             IF MITER = 0,
-C          LWM   = NEQ**2 + 2    IF MITER IS 1 OR 2,
-C          LWM   = NEQ + 2       IF MITER = 3, AND
-C          LWM   = (2*ML+MU+1)*NEQ + 2 IF MITER IS 4 OR 5.
-C          (SEE THE MF DESCRIPTION FOR METH AND MITER.)
-C          THUS IF MAXORD HAS ITS DEFAULT VALUE AND NEQ IS CONSTANT,
-C          THIS LENGTH IS..
-C             20 + 16*NEQ                  FOR MF = 10,
-C             22 + 16*NEQ + NEQ**2         FOR MF = 11 OR 12,
-C             22 + 17*NEQ                  FOR MF = 13,
-C             22 + 17*NEQ + (2*ML+MU)*NEQ  FOR MF = 14 OR 15,
-C             20 +  9*NEQ                  FOR MF = 20,
-C             22 +  9*NEQ + NEQ**2         FOR MF = 21 OR 22,
-C             22 + 10*NEQ                  FOR MF = 23,
-C             22 + 10*NEQ + (2*ML+MU)*NEQ  FOR MF = 24 OR 25.
-C          THE FIRST 20 WORDS OF RWORK ARE RESERVED FOR CONDITIONAL
-C          AND OPTIONAL INPUTS AND OPTIONAL OUTPUTS.
+C              On output, ISTATE has the following values and meanings:
+C               1  Nothing was done, as TOUT was equal to T with
+C                  ISTATE = 1 on input.
+C               2  The integration was performed successfully.
+C              -1  An excessive amount of work (more than MXSTEP steps)
+C                  was done on this call, before completing the
+C                  requested task, but the integration was otherwise
+C                  successful as far as T. (MXSTEP is an optional input
+C                  and is normally 500.)  To continue, the user may
+C                  simply reset ISTATE to a value >1 and call again (the
+C                  excess work step counter will be reset to 0).  In
+C                  addition, the user may increase MXSTEP to avoid this
+C                  error return; see "Optional Inputs" below.
+C              -2  Too much accuracy was requested for the precision of
+C                  the machine being used.  This was detected before
+C                  completing the requested task, but the integration
+C                  was successful as far as T. To continue, the
+C                  tolerance parameters must be reset, and ISTATE must
+C                  be set to 3. The optional output TOLSF may be used
+C                  for this purpose.  (Note:  If this condition is
+C                  detected before taking any steps, then an illegal
+C                  input return (ISTATE = -3) occurs instead.)
+C              -3  Illegal input was detected, before taking any
+C                  integration steps.  See written message for details.
+C                  (Note:  If the solver detects an infinite loop of
+C                  calls to the solver with illegal input, it will cause
+C                  the run to stop.)
+C              -4  There were repeated error-test failures on one
+C                  attempted step, before completing the requested task,
+C                  but the integration was successful as far as T.  The
+C                  problem may have a singularity, or the input may be
+C                  inappropriate.
+C              -5  There were repeated convergence-test failures on one
+C                  attempted step, before completing the requested task,
+C                  but the integration was successful as far as T. This
+C                  may be caused by an inaccurate Jacobian matrix, if
+C                  one is being used.
+C              -6  EWT(i) became zero for some i during the integration.
+C                  Pure relative error control (ATOL(i)=0.0) was
+C                  requested on a variable which has now vanished.  The
+C                  integration was successful as far as T.
 C
-C          THE FOLLOWING WORD IN RWORK IS A CONDITIONAL INPUT..
-C            RWORK(1) = TCRIT = CRITICAL VALUE OF T WHICH THE SOLVER
-C                       IS NOT TO OVERSHOOT.  REQUIRED IF ITASK IS
-C                       4 OR 5, AND IGNORED OTHERWISE.  (SEE ITASK.)
+C              Note:  Since the normal output value of ISTATE is 2, it
+C              does not need to be reset for normal continuation.  Also,
+C              since a negative input value of ISTATE will be regarded
+C              as illegal, a negative output value requires the user to
+C              change it, and possibly other inputs, before calling the
+C              solver again.
 C
-C LRW    = THE LENGTH OF THE ARRAY RWORK, AS DECLARED BY THE USER.
-C          (THIS WILL BE CHECKED BY THE SOLVER.)
+C     IOPT     An integer flag to specify whether any optional inputs
+C              are being used on this call.  Input only.  The optional
+C              inputs are listed under a separate heading below.
+C              0   No optional inputs are being used.  Default values
+C                  will be used in all cases.
+C              1   One or more optional inputs are being used.
+C
+C     RWORK    A real working array (double precision).  The length of
+C              RWORK must be at least
 C
-C IWORK  = AN INTEGER WORK ARRAY.  THE LENGTH OF IWORK MUST BE AT LEAST
-C             20        IF MITER = 0 OR 3 (MF = 10, 13, 20, 23), OR
-C             20 + NEQ  OTHERWISE (MF = 11, 12, 14, 15, 21, 22, 24, 25).
-C          THE FIRST FEW WORDS OF IWORK ARE USED FOR CONDITIONAL AND
-C          OPTIONAL INPUTS AND OPTIONAL OUTPUTS.
+C                 20 + NYH*(MAXORD + 1) + 3*NEQ + LWM
+C
+C              where
+C                 NYH = the initial value of NEQ,
+C              MAXORD = 12 (if METH = 1) or 5 (if METH = 2) (unless a
+C                       smaller value is given as an optional input),
+C                 LWM = 0           if MITER = 0,
+C                 LWM = NEQ**2 + 2  if MITER = 1 or 2,
+C                 LWM = NEQ + 2     if MITER = 3, and
+C                 LWM = (2*ML + MU + 1)*NEQ + 2
+C                                   if MITER = 4 or 5.
+C              (See the MF description below for METH and MITER.)
 C
-C          THE FOLLOWING 2 WORDS IN IWORK ARE CONDITIONAL INPUTS..
-C            IWORK(1) = ML     THESE ARE THE LOWER AND UPPER
-C            IWORK(2) = MU     HALF-BANDWIDTHS, RESPECTIVELY, OF THE
-C                       BANDED JACOBIAN, EXCLUDING THE MAIN DIAGONAL.
-C                       THE BAND IS DEFINED BY THE MATRIX LOCATIONS
-C                       (I,J) WITH I-ML .LE. J .LE. I+MU.  ML AND MU
-C                       MUST SATISFY  0 .LE.  ML,MU  .LE. NEQ-1.
-C                       THESE ARE REQUIRED IF MITER IS 4 OR 5, AND
-C                       IGNORED OTHERWISE.  ML AND MU MAY IN FACT BE
-C                       THE BAND PARAMETERS FOR A MATRIX TO WHICH
-C                       DF/DY IS ONLY APPROXIMATELY EQUAL.
+C              Thus if MAXORD has its default value and NEQ is constant,
+C              this length is:
+C              20 + 16*NEQ                    for MF = 10,
+C              22 + 16*NEQ + NEQ**2           for MF = 11 or 12,
+C              22 + 17*NEQ                    for MF = 13,
+C              22 + 17*NEQ + (2*ML + MU)*NEQ  for MF = 14 or 15,
+C              20 +  9*NEQ                    for MF = 20,
+C              22 +  9*NEQ + NEQ**2           for MF = 21 or 22,
+C              22 + 10*NEQ                    for MF = 23,
+C              22 + 10*NEQ + (2*ML + MU)*NEQ  for MF = 24 or 25.
+C
+C              The first 20 words of RWORK are reserved for conditional
+C              and optional inputs and optional outputs.
 C
-C LIW    = THE LENGTH OF THE ARRAY IWORK, AS DECLARED BY THE USER.
-C          (THIS WILL BE CHECKED BY THE SOLVER.)
+C              The following word in RWORK is a conditional input:
+C              RWORK(1) = TCRIT, the critical value of t which the
+C                         solver is not to overshoot.  Required if ITASK
+C                         is 4 or 5, and ignored otherwise.  See ITASK.
 C
-C NOTE..  THE WORK ARRAYS MUST NOT BE ALTERED BETWEEN CALLS TO LSODE
-C FOR THE SAME PROBLEM, EXCEPT POSSIBLY FOR THE CONDITIONAL AND
-C OPTIONAL INPUTS, AND EXCEPT FOR THE LAST 3*NEQ WORDS OF RWORK.
-C THE LATTER SPACE IS USED FOR INTERNAL SCRATCH SPACE, AND SO IS
-C AVAILABLE FOR USE BY THE USER OUTSIDE LSODE BETWEEN CALLS, IF
-C DESIRED (BUT NOT FOR USE BY F OR JAC).
+C     LRW      The length of the array RWORK, as declared by the user.
+C              (This will be checked by the solver.)
+C
+C     IWORK    An integer work array.  Its length must be at least
+C              20       if MITER = 0 or 3 (MF = 10, 13, 20, 23), or
+C              20 + NEQ otherwise (MF = 11, 12, 14, 15, 21, 22, 24, 25).
+C              (See the MF description below for MITER.)  The first few
+C              words of IWORK are used for conditional and optional
+C              inputs and optional outputs.
 C
-C JAC    = THE NAME OF THE USER-SUPPLIED ROUTINE (MITER = 1 OR 4) TO
-C          COMPUTE THE JACOBIAN MATRIX, DF/DY, AS A FUNCTION OF
-C          THE SCALAR T AND THE VECTOR Y.  IT IS TO HAVE THE FORM
-C               SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
-C               DIMENSION Y(1), PD(NROWPD,1)
-C          WHERE NEQ, T, Y, ML, MU, AND NROWPD ARE INPUT AND THE ARRAY
-C          PD IS TO BE LOADED WITH PARTIAL DERIVATIVES (ELEMENTS OF
-C          THE JACOBIAN MATRIX) ON OUTPUT.  PD MUST BE GIVEN A FIRST
-C          DIMENSION OF NROWPD.  T AND Y HAVE THE SAME MEANING AS IN
-C          SUBROUTINE F.  (IN THE DIMENSION STATEMENT ABOVE, 1 IS A
-C          DUMMY DIMENSION.. IT CAN BE REPLACED BY ANY VALUE.)
-C               IN THE FULL MATRIX CASE (MITER = 1), ML AND MU ARE
-C          IGNORED, AND THE JACOBIAN IS TO BE LOADED INTO PD IN
-C          COLUMNWISE MANNER, WITH DF(I)/DY(J) LOADED INTO PD(I,J).
-C               IN THE BAND MATRIX CASE (MITER = 4), THE ELEMENTS
-C          WITHIN THE BAND ARE TO BE LOADED INTO PD IN COLUMNWISE
-C          MANNER, WITH DIAGONAL LINES OF DF/DY LOADED INTO THE ROWS
-C          OF PD.  THUS DF(I)/DY(J) IS TO BE LOADED INTO PD(I-J+MU+1,J).
-C          ML AND MU ARE THE HALF-BANDWIDTH PARAMETERS (SEE IWORK).
-C          THE LOCATIONS IN PD IN THE TWO TRIANGULAR AREAS WHICH
-C          CORRESPOND TO NONEXISTENT MATRIX ELEMENTS CAN BE IGNORED
-C          OR LOADED ARBITRARILY, AS THEY ARE OVERWRITTEN BY LSODE.
-C               JAC NEED NOT PROVIDE DF/DY EXACTLY.  A CRUDE
-C          APPROXIMATION (POSSIBLY WITH A SMALLER BANDWIDTH) WILL DO.
-C               IN EITHER CASE, PD IS PRESET TO ZERO BY THE SOLVER,
-C          SO THAT ONLY THE NONZERO ELEMENTS NEED BE LOADED BY JAC.
-C          EACH CALL TO JAC IS PRECEDED BY A CALL TO F WITH THE SAME
-C          ARGUMENTS NEQ, T, AND Y.  THUS TO GAIN SOME EFFICIENCY,
-C          INTERMEDIATE QUANTITIES SHARED BY BOTH CALCULATIONS MAY BE
-C          SAVED IN A USER COMMON BLOCK BY F AND NOT RECOMPUTED BY JAC,
-C          IF DESIRED.  ALSO, JAC MAY ALTER THE Y ARRAY, IF DESIRED.
-C          JAC MUST BE DECLARED EXTERNAL IN THE CALLING PROGRAM.
-C               SUBROUTINE JAC MAY ACCESS USER-DEFINED QUANTITIES IN
-C          NEQ(2),... AND/OR IN Y(NEQ(1)+1),... IF NEQ IS AN ARRAY
-C          (DIMENSIONED IN JAC) AND/OR Y HAS LENGTH EXCEEDING NEQ(1).
-C          SEE THE DESCRIPTIONS OF NEQ AND Y ABOVE.
+C              The following two words in IWORK are conditional inputs:
+C              IWORK(1) = ML   These are the lower and upper half-
+C              IWORK(2) = MU   bandwidths, respectively, of the banded
+C                              Jacobian, excluding the main diagonal.
+C                         The band is defined by the matrix locations
+C                         (i,j) with i - ML <= j <= i + MU. ML and MU
+C                         must satisfy 0 <= ML,MU <= NEQ - 1. These are
+C                         required if MITER is 4 or 5, and ignored
+C                         otherwise.  ML and MU may in fact be the band
+C                         parameters for a matrix to which df/dy is only
+C                         approximately equal.
+C
+C     LIW      The length of the array IWORK, as declared by the user.
+C              (This will be checked by the solver.)
+C
+C     Note:  The work arrays must not be altered between calls to DLSODE
+C     for the same problem, except possibly for the conditional and
+C     optional inputs, and except for the last 3*NEQ words of RWORK.
+C     The latter space is used for internal scratch space, and so is
+C     available for use by the user outside DLSODE between calls, if
+C     desired (but not for use by F or JAC).
+C
+C     JAC      The name of the user-supplied routine (MITER = 1 or 4) to
+C              compute the Jacobian matrix, df/dy, as a function of the
+C              scalar t and the vector y.  (See the MF description below
+C              for MITER.)  It is to have the form
+C
+C                 SUBROUTINE JAC (NEQ, T, Y, ML, MU, PD, NROWPD)
+C                 DOUBLE PRECISION T, Y(*), PD(NROWPD,*)
+C
+C              where NEQ, T, Y, ML, MU, and NROWPD are input and the
+C              array PD is to be loaded with partial derivatives
+C              (elements of the Jacobian matrix) on output.  PD must be
+C              given a first dimension of NROWPD.  T and Y have the same
+C              meaning as in subroutine F.
+C
+C              In the full matrix case (MITER = 1), ML and MU are
+C              ignored, and the Jacobian is to be loaded into PD in
+C              columnwise manner, with df(i)/dy(j) loaded into PD(i,j).
+C
+C              In the band matrix case (MITER = 4), the elements within
+C              the band are to be loaded into PD in columnwise manner,
+C              with diagonal lines of df/dy loaded into the rows of PD.
+C              Thus df(i)/dy(j) is to be loaded into PD(i-j+MU+1,j).  ML
+C              and MU are the half-bandwidth parameters (see IWORK).
+C              The locations in PD in the two triangular areas which
+C              correspond to nonexistent matrix elements can be ignored
+C              or loaded arbitrarily, as they are overwritten by DLSODE.
+C
+C              JAC need not provide df/dy exactly. A crude approximation
+C              (possibly with a smaller bandwidth) will do.
+C
+C              In either case, PD is preset to zero by the solver, so
+C              that only the nonzero elements need be loaded by JAC.
+C              Each call to JAC is preceded by a call to F with the same
+C              arguments NEQ, T, and Y. Thus to gain some efficiency,
+C              intermediate quantities shared by both calculations may
+C              be saved in a user COMMON block by F and not recomputed
+C              by JAC, if desired.  Also, JAC may alter the Y array, if
+C              desired.  JAC must be declared EXTERNAL in the calling
+C              program.
+C
+C              Subroutine JAC may access user-defined quantities in
+C              NEQ(2),... and/or in Y(NEQ(1)+1),... if NEQ is an array
+C              (dimensioned in JAC) and/or Y has length exceeding
+C              NEQ(1).  See the descriptions of NEQ and Y above.
+C
+C     MF       The method flag.  Used only for input.  The legal values
+C              of MF are 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24,
+C              and 25.  MF has decimal digits METH and MITER:
+C                 MF = 10*METH + MITER .
 C
-C MF     = THE METHOD FLAG.  USED ONLY FOR INPUT.  THE LEGAL VALUES OF
-C          MF ARE 10, 11, 12, 13, 14, 15, 20, 21, 22, 23, 24, AND 25.
-C          MF HAS DECIMAL DIGITS METH AND MITER.. MF = 10*METH + MITER.
-C          METH INDICATES THE BASIC LINEAR MULTISTEP METHOD..
-C            METH = 1 MEANS THE IMPLICIT ADAMS METHOD.
-C            METH = 2 MEANS THE METHOD BASED ON BACKWARD
-C                     DIFFERENTIATION FORMULAS (BDF-S).
-C          MITER INDICATES THE CORRECTOR ITERATION METHOD..
-C            MITER = 0 MEANS FUNCTIONAL ITERATION (NO JACOBIAN MATRIX
-C                      IS INVOLVED).
-C            MITER = 1 MEANS CHORD ITERATION WITH A USER-SUPPLIED
-C                      FULL (NEQ BY NEQ) JACOBIAN.
-C            MITER = 2 MEANS CHORD ITERATION WITH AN INTERNALLY
-C                      GENERATED (DIFFERENCE QUOTIENT) FULL JACOBIAN
-C                      (USING NEQ EXTRA CALLS TO F PER DF/DY VALUE).
-C            MITER = 3 MEANS CHORD ITERATION WITH AN INTERNALLY
-C                      GENERATED DIAGONAL JACOBIAN APPROXIMATION.
-C                      (USING 1 EXTRA CALL TO F PER DF/DY EVALUATION).
-C            MITER = 4 MEANS CHORD ITERATION WITH A USER-SUPPLIED
-C                      BANDED JACOBIAN.
-C            MITER = 5 MEANS CHORD ITERATION WITH AN INTERNALLY
-C                      GENERATED BANDED JACOBIAN (USING ML+MU+1 EXTRA
-C                      CALLS TO F PER DF/DY EVALUATION).
-C          IF MITER = 1 OR 4, THE USER MUST SUPPLY A SUBROUTINE JAC
-C          (THE NAME IS ARBITRARY) AS DESCRIBED ABOVE UNDER JAC.
-C          FOR OTHER VALUES OF MITER, A DUMMY ARGUMENT CAN BE USED.
-C-----------------------------------------------------------------------
-C OPTIONAL INPUTS.
+C              METH indicates the basic linear multistep method:
+C              1   Implicit Adams method.
+C              2   Method based on backward differentiation formulas
+C                  (BDF's).
 C
-C THE FOLLOWING IS A LIST OF THE OPTIONAL INPUTS PROVIDED FOR IN THE
-C CALL SEQUENCE.  (SEE ALSO PART II.)  FOR EACH SUCH INPUT VARIABLE,
-C THIS TABLE LISTS ITS NAME AS USED IN THIS DOCUMENTATION, ITS
-C LOCATION IN THE CALL SEQUENCE, ITS MEANING, AND THE DEFAULT VALUE.
-C THE USE OF ANY OF THESE INPUTS REQUIRES IOPT = 1, AND IN THAT
-C CASE ALL OF THESE INPUTS ARE EXAMINED.  A VALUE OF ZERO FOR ANY
-C OF THESE OPTIONAL INPUTS WILL CAUSE THE DEFAULT VALUE TO BE USED.
-C THUS TO USE A SUBSET OF THE OPTIONAL INPUTS, SIMPLY PRELOAD
-C LOCATIONS 5 TO 10 IN RWORK AND IWORK TO 0.0 AND 0 RESPECTIVELY, AND
-C THEN SET THOSE OF INTEREST TO NONZERO VALUES.
+C              MITER indicates the corrector iteration method:
+C              0   Functional iteration (no Jacobian matrix is
+C                  involved).
+C              1   Chord iteration with a user-supplied full (NEQ by
+C                  NEQ) Jacobian.
+C              2   Chord iteration with an internally generated
+C                  (difference quotient) full Jacobian (using NEQ
+C                  extra calls to F per df/dy value).
+C              3   Chord iteration with an internally generated
+C                  diagonal Jacobian approximation (using one extra call
+C                  to F per df/dy evaluation).
+C              4   Chord iteration with a user-supplied banded Jacobian.
+C              5   Chord iteration with an internally generated banded
+C                  Jacobian (using ML + MU + 1 extra calls to F per
+C                  df/dy evaluation).
 C
-C NAME    LOCATION      MEANING AND DEFAULT VALUE
+C              If MITER = 1 or 4, the user must supply a subroutine JAC
+C              (the name is arbitrary) as described above under JAC.
+C              For other values of MITER, a dummy argument can be used.
+C
+C     Optional Inputs
+C     ---------------
+C     The following is a list of the optional inputs provided for in the
+C     call sequence.  (See also Part 2.)  For each such input variable,
+C     this table lists its name as used in this documentation, its
+C     location in the call sequence, its meaning, and the default value.
+C     The use of any of these inputs requires IOPT = 1, and in that case
+C     all of these inputs are examined.  A value of zero for any of
+C     these optional inputs will cause the default value to be used.
+C     Thus to use a subset of the optional inputs, simply preload
+C     locations 5 to 10 in RWORK and IWORK to 0.0 and 0 respectively,
+C     and then set those of interest to nonzero values.
 C
-C H0      RWORK(5)  THE STEP SIZE TO BE ATTEMPTED ON THE FIRST STEP.
-C                   THE DEFAULT VALUE IS DETERMINED BY THE SOLVER.
-C
-C HMAX    RWORK(6)  THE MAXIMUM ABSOLUTE STEP SIZE ALLOWED.
-C                   THE DEFAULT VALUE IS INFINITE.
-C
-C HMIN    RWORK(7)  THE MINIMUM ABSOLUTE STEP SIZE ALLOWED.
-C                   THE DEFAULT VALUE IS 0.  (THIS LOWER BOUND IS NOT
-C                   ENFORCED ON THE FINAL STEP BEFORE REACHING TCRIT
-C                   WHEN ITASK = 4 OR 5.)
-C
-C MAXORD  IWORK(5)  THE MAXIMUM ORDER TO BE ALLOWED.  THE DEFAULT
-C                   VALUE IS 12 IF METH = 1, AND 5 IF METH = 2.
-C                   IF MAXORD EXCEEDS THE DEFAULT VALUE, IT WILL
-C                   BE REDUCED TO THE DEFAULT VALUE.
-C                   IF MAXORD IS CHANGED DURING THE PROBLEM, IT MAY
-C                   CAUSE THE CURRENT ORDER TO BE REDUCED.
+C     Name    Location   Meaning and default value
+C     ------  ---------  -----------------------------------------------
+C     H0      RWORK(5)   Step size to be attempted on the first step.
+C                        The default value is determined by the solver.
+C     HMAX    RWORK(6)   Maximum absolute step size allowed.  The
+C                        default value is infinite.
+C     HMIN    RWORK(7)   Minimum absolute step size allowed.  The
+C                        default value is 0.  (This lower bound is not
+C                        enforced on the final step before reaching
+C                        TCRIT when ITASK = 4 or 5.)
+C     MAXORD  IWORK(5)   Maximum order to be allowed.  The default value
+C                        is 12 if METH = 1, and 5 if METH = 2. (See the
+C                        MF description above for METH.)  If MAXORD
+C                        exceeds the default value, it will be reduced
+C                        to the default value.  If MAXORD is changed
+C                        during the problem, it may cause the current
+C                        order to be reduced.
+C     MXSTEP  IWORK(6)   Maximum number of (internally defined) steps
+C                        allowed during one call to the solver.  The
+C                        default value is 500.
+C     MXHNIL  IWORK(7)   Maximum number of messages printed (per
+C                        problem) warning that T + H = T on a step
+C                        (H = step size).  This must be positive to
+C                        result in a nondefault value.  The default
+C                        value is 10.
 C
-C MXSTEP  IWORK(6)  MAXIMUM NUMBER OF (INTERNALLY DEFINED) STEPS
-C                   ALLOWED DURING ONE CALL TO THE SOLVER.
-C                   THE DEFAULT VALUE IS 500.
-C
-C MXHNIL  IWORK(7)  MAXIMUM NUMBER OF MESSAGES PRINTED (PER PROBLEM)
-C                   WARNING THAT T + H = T ON A STEP (H = STEP SIZE).
-C                   THIS MUST BE POSITIVE TO RESULT IN A NON-DEFAULT
-C                   VALUE.  THE DEFAULT VALUE IS 10.
-C-----------------------------------------------------------------------
-C OPTIONAL OUTPUTS.
-C
-C AS OPTIONAL ADDITIONAL OUTPUT FROM LSODE, THE VARIABLES LISTED
-C BELOW ARE QUANTITIES RELATED TO THE PERFORMANCE OF LSODE
-C WHICH ARE AVAILABLE TO THE USER.  THESE ARE COMMUNICATED BY WAY OF
-C THE WORK ARRAYS, BUT ALSO HAVE INTERNAL MNEMONIC NAMES AS SHOWN.
-C EXCEPT WHERE STATED OTHERWISE, ALL OF THESE OUTPUTS ARE DEFINED
-C ON ANY SUCCESSFUL RETURN FROM LSODE, AND ON ANY RETURN WITH
-C ISTATE = -1, -2, -4, -5, OR -6.  ON AN ILLEGAL INPUT RETURN
-C (ISTATE = -3), THEY WILL BE UNCHANGED FROM THEIR EXISTING VALUES
-C (IF ANY), EXCEPT POSSIBLY FOR TOLSF, LENRW, AND LENIW.
-C ON ANY ERROR RETURN, OUTPUTS RELEVANT TO THE ERROR WILL BE DEFINED,
-C AS NOTED BELOW.
-C
-C NAME    LOCATION      MEANING
+C     Optional Outputs
+C     ----------------
+C     As optional additional output from DLSODE, the variables listed
+C     below are quantities related to the performance of DLSODE which 
+C     are available to the user.  These are communicated by way of the
+C     work arrays, but also have internal mnemonic names as shown. 
+C     Except where stated otherwise, all of these outputs are defined on
+C     any successful return from DLSODE, and on any return with ISTATE =
+C     -1, -2, -4, -5, or -6.  On an illegal input return (ISTATE = -3),
+C     they will be unchanged from their existing values (if any), except
+C     possibly for TOLSF, LENRW, and LENIW.  On any error return,
+C     outputs relevant to the error will be defined, as noted below.
 C
-C HU      RWORK(11) THE STEP SIZE IN T LAST USED (SUCCESSFULLY).
-C
-C HCUR    RWORK(12) THE STEP SIZE TO BE ATTEMPTED ON THE NEXT STEP.
-C
-C TCUR    RWORK(13) THE CURRENT VALUE OF THE INDEPENDENT VARIABLE
-C                   WHICH THE SOLVER HAS ACTUALLY REACHED, I.E. THE
-C                   CURRENT INTERNAL MESH POINT IN T.  ON OUTPUT, TCUR
-C                   WILL ALWAYS BE AT LEAST AS FAR AS THE ARGUMENT
-C                   T, BUT MAY BE FARTHER (IF INTERPOLATION WAS DONE).
-C
-C TOLSF   RWORK(14) A TOLERANCE SCALE FACTOR, GREATER THAN 1.0,
-C                   COMPUTED WHEN A REQUEST FOR TOO MUCH ACCURACY WAS
-C                   DETECTED (ISTATE = -3 IF DETECTED AT THE START OF
-C                   THE PROBLEM, ISTATE = -2 OTHERWISE).  IF ITOL IS
-C                   LEFT UNALTERED BUT RTOL AND ATOL ARE UNIFORMLY
-C                   SCALED UP BY A FACTOR OF TOLSF FOR THE NEXT CALL,
-C                   THEN THE SOLVER IS DEEMED LIKELY TO SUCCEED.
-C                   (THE USER MAY ALSO IGNORE TOLSF AND ALTER THE
-C                   TOLERANCE PARAMETERS IN ANY OTHER WAY APPROPRIATE.)
-C
-C NST     IWORK(11) THE NUMBER OF STEPS TAKEN FOR THE PROBLEM SO FAR.
-C
-C NFE     IWORK(12) THE NUMBER OF F EVALUATIONS FOR THE PROBLEM SO FAR.
+C     Name   Location   Meaning
+C     -----  ---------  ------------------------------------------------
+C     HU     RWORK(11)  Step size in t last used (successfully).
+C     HCUR   RWORK(12)  Step size to be attempted on the next step.
+C     TCUR   RWORK(13)  Current value of the independent variable which
+C                       the solver has actually reached, i.e., the
+C                       current internal mesh point in t. On output,
+C                       TCUR will always be at least as far as the
+C                       argument T, but may be farther (if interpolation
+C                       was done).
+C     TOLSF  RWORK(14)  Tolerance scale factor, greater than 1.0,
+C                       computed when a request for too much accuracy
+C                       was detected (ISTATE = -3 if detected at the
+C                       start of the problem, ISTATE = -2 otherwise).
+C                       If ITOL is left unaltered but RTOL and ATOL are
+C                       uniformly scaled up by a factor of TOLSF for the
+C                       next call, then the solver is deemed likely to
+C                       succeed.  (The user may also ignore TOLSF and
+C                       alter the tolerance parameters in any other way
+C                       appropriate.)
+C     NST    IWORK(11)  Number of steps taken for the problem so far.
+C     NFE    IWORK(12)  Number of F evaluations for the problem so far.
+C     NJE    IWORK(13)  Number of Jacobian evaluations (and of matrix LU
+C                       decompositions) for the problem so far.
+C     NQU    IWORK(14)  Method order last used (successfully).
+C     NQCUR  IWORK(15)  Order to be attempted on the next step.
+C     IMXER  IWORK(16)  Index of the component of largest magnitude in
+C                       the weighted local error vector ( e(i)/EWT(i) ),
+C                       on an error return with ISTATE = -4 or -5.
+C     LENRW  IWORK(17)  Length of RWORK actually required.  This is
+C                       defined on normal returns and on an illegal
+C                       input return for insufficient storage.
+C     LENIW  IWORK(18)  Length of IWORK actually required.  This is
+C                       defined on normal returns and on an illegal
+C                       input return for insufficient storage.
 C
-C NJE     IWORK(13) THE NUMBER OF JACOBIAN EVALUATIONS (AND OF MATRIX
-C                   LU DECOMPOSITIONS) FOR THE PROBLEM SO FAR.
-C
-C NQU     IWORK(14) THE METHOD ORDER LAST USED (SUCCESSFULLY).
-C
-C NQCUR   IWORK(15) THE ORDER TO BE ATTEMPTED ON THE NEXT STEP.
-C
-C IMXER   IWORK(16) THE INDEX OF THE COMPONENT OF LARGEST MAGNITUDE IN
-C                   THE WEIGHTED LOCAL ERROR VECTOR ( E(I)/EWT(I) ),
-C                   ON AN ERROR RETURN WITH ISTATE = -4 OR -5.
+C     The following two arrays are segments of the RWORK array which may
+C     also be of interest to the user as optional outputs.  For each
+C     array, the table below gives its internal name, its base address
+C     in RWORK, and its description.
 C
-C LENRW   IWORK(17) THE LENGTH OF RWORK ACTUALLY REQUIRED.
-C                   THIS IS DEFINED ON NORMAL RETURNS AND ON AN ILLEGAL
-C                   INPUT RETURN FOR INSUFFICIENT STORAGE.
+C     Name  Base address  Description
+C     ----  ------------  ----------------------------------------------
+C     YH    21            The Nordsieck history array, of size NYH by
+C                         (NQCUR + 1), where NYH is the initial value of
+C                         NEQ.  For j = 0,1,...,NQCUR, column j + 1 of
+C                         YH contains HCUR**j/factorial(j) times the jth
+C                         derivative of the interpolating polynomial
+C                         currently representing the solution, evaluated
+C                         at t = TCUR.
+C     ACOR  LENRW-NEQ+1   Array of size NEQ used for the accumulated
+C                         corrections on each step, scaled on output to
+C                         represent the estimated local error in Y on
+C                         the last step.  This is the vector e in the
+C                         description of the error control.  It is
+C                         defined only on successful return from DLSODE.
 C
-C LENIW   IWORK(18) THE LENGTH OF IWORK ACTUALLY REQUIRED.
-C                   THIS IS DEFINED ON NORMAL RETURNS AND ON AN ILLEGAL
-C                   INPUT RETURN FOR INSUFFICIENT STORAGE.
 C
-C THE FOLLOWING TWO ARRAYS ARE SEGMENTS OF THE RWORK ARRAY WHICH
-C MAY ALSO BE OF INTEREST TO THE USER AS OPTIONAL OUTPUTS.
-C FOR EACH ARRAY, THE TABLE BELOW GIVES ITS INTERNAL NAME,
-C ITS BASE ADDRESS IN RWORK, AND ITS DESCRIPTION.
+C                    Part 2.  Other Callable Routines
+C                    --------------------------------
 C
-C NAME    BASE ADDRESS      DESCRIPTION
+C     The following are optional calls which the user may make to gain
+C     additional capabilities in conjunction with DLSODE.
 C
-C YH      21             THE NORDSIECK HISTORY ARRAY, OF SIZE NYH BY
-C                        (NQCUR + 1), WHERE NYH IS THE INITIAL VALUE
-C                        OF NEQ.  FOR J = 0,1,...,NQCUR, COLUMN J+1
-C                        OF YH CONTAINS HCUR**J/FACTORIAL(J) TIMES
-C                        THE J-TH DERIVATIVE OF THE INTERPOLATING
-C                        POLYNOMIAL CURRENTLY REPRESENTING THE SOLUTION,
-C                        EVALUATED AT T = TCUR.
+C     Form of call              Function
+C     ------------------------  ----------------------------------------
+C     CALL XSETUN(LUN)          Set the logical unit number, LUN, for
+C                               output of messages from DLSODE, if the
+C                               default is not desired.  The default
+C                               value of LUN is 6. This call may be made
+C                               at any time and will take effect
+C                               immediately.
+C     CALL XSETF(MFLAG)         Set a flag to control the printing of
+C                               messages by DLSODE.  MFLAG = 0 means do
+C                               not print.  (Danger:  this risks losing
+C                               valuable information.)  MFLAG = 1 means
+C                               print (the default).  This call may be
+C                               made at any time and will take effect
+C                               immediately.
+C     CALL DSRCOM(RSAV,ISAV,JOB)  Saves and restores the contents of the
+C                               internal COMMON blocks used by DLSODE
+C                               (see Part 3 below).  RSAV must be a
+C                               real array of length 218 or more, and
+C                               ISAV must be an integer array of length
+C                               37 or more.  JOB = 1 means save COMMON
+C                               into RSAV/ISAV.  JOB = 2 means restore
+C                               COMMON from same.  DSRCOM is useful if
+C                               one is interrupting a run and restarting
+C                               later, or alternating between two or
+C                               more problems solved with DLSODE.
+C     CALL DINTDY(,,,,,)        Provide derivatives of y, of various
+C     (see below)               orders, at a specified point t, if
+C                               desired.  It may be called only after a
+C                               successful return from DLSODE.  Detailed
+C                               instructions follow.
 C
-C ACOR     LENRW-NEQ+1   ARRAY OF SIZE NEQ USED FOR THE ACCUMULATED
-C                        CORRECTIONS ON EACH STEP, SCALED ON OUTPUT
-C                        TO REPRESENT THE ESTIMATED LOCAL ERROR IN Y
-C                        ON THE LAST STEP.  THIS IS THE VECTOR E IN
-C                        THE DESCRIPTION OF THE ERROR CONTROL.  IT IS
-C                        DEFINED ONLY ON A SUCCESSFUL RETURN FROM LSODE.
-C
-C-----------------------------------------------------------------------
-C PART II.  OTHER ROUTINES CALLABLE.
+C     Detailed instructions for using DINTDY
+C     --------------------------------------
+C     The form of the CALL is:
 C
-C THE FOLLOWING ARE OPTIONAL CALLS WHICH THE USER MAY MAKE TO
-C GAIN ADDITIONAL CAPABILITIES IN CONJUNCTION WITH LSODE.
-C (THE ROUTINES XSETUN AND XSETF ARE DESIGNED TO CONFORM TO THE
-C SLATEC ERROR HANDLING PACKAGE.)
-C
-C     FORM OF CALL                  FUNCTION
-C   CALL XSETUN(LUN)          SET THE LOGICAL UNIT NUMBER, LUN, FOR
-C                             OUTPUT OF MESSAGES FROM LSODE, IF
-C                             THE DEFAULT IS NOT DESIRED.
-C                             THE DEFAULT VALUE OF LUN IS 6.
+C           CALL DINTDY (T, K, RWORK(21), NYH, DKY, IFLAG)
 C
-C   CALL XSETF(MFLAG)         SET A FLAG TO CONTROL THE PRINTING OF
-C                             MESSAGES BY LSODE.
-C                             MFLAG = 0 MEANS DO NOT PRINT. (DANGER..
-C                             THIS RISKS LOSING VALUABLE INFORMATION.)
-C                             MFLAG = 1 MEANS PRINT (THE DEFAULT).
+C     The input parameters are:
 C
-C                             EITHER OF THE ABOVE CALLS MAY BE MADE AT
-C                             ANY TIME AND WILL TAKE EFFECT IMMEDIATELY.
+C     T          Value of independent variable where answers are
+C                desired (normally the same as the T last returned by
+C                DLSODE).  For valid results, T must lie between
+C                TCUR - HU and TCUR.  (See "Optional Outputs" above
+C                for TCUR and HU.)
+C     K          Integer order of the derivative desired.  K must
+C                satisfy 0 <= K <= NQCUR, where NQCUR is the current
+C                order (see "Optional Outputs").  The capability
+C                corresponding to K = 0, i.e., computing y(t), is
+C                already provided by DLSODE directly.  Since
+C                NQCUR >= 1, the first derivative dy/dt is always
+C                available with DINTDY.
+C     RWORK(21)  The base address of the history array YH.
+C     NYH        Column length of YH, equal to the initial value of NEQ.
+C
+C     The output parameters are:
 C
-C   CALL SRCOM(RSAV,ISAV,JOB) SAVES AND RESTORES THE CONTENTS OF
-C                             THE INTERNAL COMMON BLOCKS USED BY
-C                             LSODE (SEE PART III BELOW).
-C                             RSAV MUST BE A REAL ARRAY OF LENGTH 218
-C                             OR MORE, AND ISAV MUST BE AN INTEGER
-C                             ARRAY OF LENGTH 41 OR MORE.
-C                             JOB=1 MEANS SAVE COMMON INTO RSAV/ISAV.
-C                             JOB=2 MEANS RESTORE COMMON FROM RSAV/ISAV.
-C                                SRCOM IS USEFUL IF ONE IS
-C                             INTERRUPTING A RUN AND RESTARTING
-C                             LATER, OR ALTERNATING BETWEEN TWO OR
-C                             MORE PROBLEMS SOLVED WITH LSODE.
+C     DKY        Real array of length NEQ containing the computed value
+C                of the Kth derivative of y(t).
+C     IFLAG      Integer flag, returned as 0 if K and T were legal,
+C                -1 if K was illegal, and -2 if T was illegal.
+C                On an error return, a message is also written.
+C
+C
+C                          Part 3.  Common Blocks
+C                          ----------------------
 C
-C   CALL INTDY(,,,,,)         PROVIDE DERIVATIVES OF Y, OF VARIOUS
-C        (SEE BELOW)          ORDERS, AT A SPECIFIED POINT T, IF
-C                             DESIRED.  IT MAY BE CALLED ONLY AFTER
-C                             A SUCCESSFUL RETURN FROM LSODE.
+C     If DLSODE is to be used in an overlay situation, the user must
+C     declare, in the primary overlay, the variables in:
+C     (1) the call sequence to DLSODE,
+C     (2) the internal COMMON block /DLS001/, of length 255 
+C         (218 double precision words followed by 37 integer words).
 C
-C THE DETAILED INSTRUCTIONS FOR USING INTDY ARE AS FOLLOWS.
-C THE FORM OF THE CALL IS..
-C
-C   CALL INTDY (T, K, RWORK(21), NYH, DKY, IFLAG)
-C
-C THE INPUT PARAMETERS ARE..
+C     If DLSODE is used on a system in which the contents of internal
+C     COMMON blocks are not preserved between calls, the user should
+C     declare the above COMMON block in his main program to insure that
+C     its contents are preserved.
 C
-C T         = VALUE OF INDEPENDENT VARIABLE WHERE ANSWERS ARE DESIRED
-C             (NORMALLY THE SAME AS THE T LAST RETURNED BY LSODE).
-C             FOR VALID RESULTS, T MUST LIE BETWEEN TCUR - HU AND TCUR.
-C             (SEE OPTIONAL OUTPUTS FOR TCUR AND HU.)
-C K         = INTEGER ORDER OF THE DERIVATIVE DESIRED.  K MUST SATISFY
-C             0 .LE. K .LE. NQCUR, WHERE NQCUR IS THE CURRENT ORDER
-C             (SEE OPTIONAL OUTPUTS).  THE CAPABILITY CORRESPONDING
-C             TO K = 0, I.E. COMPUTING Y(T), IS ALREADY PROVIDED
-C             BY LSODE DIRECTLY.  SINCE NQCUR .GE. 1, THE FIRST
-C             DERIVATIVE DY/DT IS ALWAYS AVAILABLE WITH INTDY.
-C RWORK(21) = THE BASE ADDRESS OF THE HISTORY ARRAY YH.
-C NYH       = COLUMN LENGTH OF YH, EQUAL TO THE INITIAL VALUE OF NEQ.
+C     If the solution of a given problem by DLSODE is to be interrupted
+C     and then later continued, as when restarting an interrupted run or
+C     alternating between two or more problems, the user should save,
+C     following the return from the last DLSODE call prior to the
+C     interruption, the contents of the call sequence variables and the
+C     internal COMMON block, and later restore these values before the
+C     next DLSODE call for that problem.   In addition, if XSETUN and/or
+C     XSETF was called for non-default handling of error messages, then
+C     these calls must be repeated.  To save and restore the COMMON
+C     block, use subroutine DSRCOM (see Part 2 above).
+C
+C
+C              Part 4.  Optionally Replaceable Solver Routines
+C              -----------------------------------------------
 C
-C THE OUTPUT PARAMETERS ARE..
+C     Below are descriptions of two routines in the DLSODE package which
+C     relate to the measurement of errors.  Either routine can be
+C     replaced by a user-supplied version, if desired.  However, since
+C     such a replacement may have a major impact on performance, it
+C     should be done only when absolutely necessary, and only with great
+C     caution.  (Note:  The means by which the package version of a
+C     routine is superseded by the user's version may be system-
+C     dependent.)
 C
-C DKY       = A REAL ARRAY OF LENGTH NEQ CONTAINING THE COMPUTED VALUE
-C             OF THE K-TH DERIVATIVE OF Y(T).
-C IFLAG     = INTEGER FLAG, RETURNED AS 0 IF K AND T WERE LEGAL,
-C             -1 IF K WAS ILLEGAL, AND -2 IF T WAS ILLEGAL.
-C             ON AN ERROR RETURN, A MESSAGE IS ALSO WRITTEN.
-C-----------------------------------------------------------------------
-C PART III.  COMMON BLOCKS.
+C     DEWSET
+C     ------
+C     The following subroutine is called just before each internal
+C     integration step, and sets the array of error weights, EWT, as
+C     described under ITOL/RTOL/ATOL above:
+C
+C           SUBROUTINE DEWSET (NEQ, ITOL, RTOL, ATOL, YCUR, EWT)
+C
+C     where NEQ, ITOL, RTOL, and ATOL are as in the DLSODE call
+C     sequence, YCUR contains the current dependent variable vector,
+C     and EWT is the array of weights set by DEWSET.
 C
-C IF LSODE IS TO BE USED IN AN OVERLAY SITUATION, THE USER
-C MUST DECLARE, IN THE PRIMARY OVERLAY, THE VARIABLES IN..
-C   (1) THE CALL SEQUENCE TO LSODE,
-C   (2) THE INTERNAL COMMON BLOCK
-C         /LS0001/  OF LENGTH  257  (218 DOUBLE PRECISION WORDS
-C                         FOLLOWED BY 39 INTEGER WORDS),
-C
-C IF LSODE IS USED ON A SYSTEM IN WHICH THE CONTENTS OF INTERNAL
-C COMMON BLOCKS ARE NOT PRESERVED BETWEEN CALLS, THE USER SHOULD
-C DECLARE THE ABOVE TWO COMMON BLOCKS IN HIS MAIN PROGRAM TO INSURE
-C THAT THEIR CONTENTS ARE PRESERVED.
+C     If the user supplies this subroutine, it must return in EWT(i)
+C     (i = 1,...,NEQ) a positive quantity suitable for comparing errors
+C     in Y(i) to.  The EWT array returned by DEWSET is passed to the
+C     DVNORM routine (see below), and also used by DLSODE in the
+C     computation of the optional output IMXER, the diagonal Jacobian
+C     approximation, and the increments for difference quotient
+C     Jacobians.
 C
-C IF THE SOLUTION OF A GIVEN PROBLEM BY LSODE IS TO BE INTERRUPTED
-C AND THEN LATER CONTINUED, SUCH AS WHEN RESTARTING AN INTERRUPTED RUN
-C OR ALTERNATING BETWEEN TWO OR MORE PROBLEMS, THE USER SHOULD SAVE,
-C FOLLOWING THE RETURN FROM THE LAST LSODE CALL PRIOR TO THE
-C INTERRUPTION, THE CONTENTS OF THE CALL SEQUENCE VARIABLES AND THE
-C INTERNAL COMMON BLOCKS, AND LATER RESTORE THESE VALUES BEFORE THE
-C NEXT LSODE CALL FOR THAT PROBLEM.  TO SAVE AND RESTORE THE COMMON
-C BLOCKS, USE SUBROUTINE SRCOM (SEE PART II ABOVE).
+C     In the user-supplied version of DEWSET, it may be desirable to use
+C     the current values of derivatives of y. Derivatives up to order NQ
+C     are available from the history array YH, described above under
+C     optional outputs.  In DEWSET, YH is identical to the YCUR array,
+C     extended to NQ + 1 columns with a column length of NYH and scale
+C     factors of H**j/factorial(j).  On the first call for the problem,
+C     given by NST = 0, NQ is 1 and H is temporarily set to 1.0.
+C     NYH is the initial value of NEQ.  The quantities NQ, H, and NST
+C     can be obtained by including in SEWSET the statements:
+C           DOUBLE PRECISION RLS
+C           COMMON /DLS001/ RLS(218),ILS(37)
+C           NQ = ILS(33)
+C           NST = ILS(34)
+C           H = RLS(212)
+C     Thus, for example, the current value of dy/dt can be obtained as
+C     YCUR(NYH+i)/H (i=1,...,NEQ) (and the division by H is unnecessary
+C     when NST = 0).
 C
-C-----------------------------------------------------------------------
-C PART IV.  OPTIONALLY REPLACEABLE SOLVER ROUTINES.
+C     DVNORM
+C     ------
+C     DVNORM is a real function routine which computes the weighted
+C     root-mean-square norm of a vector v:
+C
+C        d = DVNORM (n, v, w)
 C
-C BELOW ARE DESCRIPTIONS OF TWO ROUTINES IN THE LSODE PACKAGE WHICH
-C RELATE TO THE MEASUREMENT OF ERRORS.  EITHER ROUTINE CAN BE
-C REPLACED BY A USER-SUPPLIED VERSION, IF DESIRED.  HOWEVER, SINCE SUCH
-C A REPLACEMENT MAY HAVE A MAJOR IMPACT ON PERFORMANCE, IT SHOULD BE
-C DONE ONLY WHEN ABSOLUTELY NECESSARY, AND ONLY WITH GREAT CAUTION.
-C (NOTE.. THE MEANS BY WHICH THE PACKAGE VERSION OF A ROUTINE IS
-C SUPERSEDED BY THE USER-S VERSION MAY BE SYSTEM-DEPENDENT.)
+C     where:
+C     n = the length of the vector,
+C     v = real array of length n containing the vector,
+C     w = real array of length n containing weights,
+C     d = SQRT( (1/n) * sum(v(i)*w(i))**2 ).
+C
+C     DVNORM is called with n = NEQ and with w(i) = 1.0/EWT(i), where
+C     EWT is as set by subroutine DEWSET.
 C
-C (A) EWSET.
-C THE FOLLOWING SUBROUTINE IS CALLED JUST BEFORE EACH INTERNAL
-C INTEGRATION STEP, AND SETS THE ARRAY OF ERROR WEIGHTS, EWT, AS
-C DESCRIBED UNDER ITOL/RTOL/ATOL ABOVE..
-C     SUBROUTINE EWSET (NEQ, ITOL, RTOL, ATOL, YCUR, EWT)
-C WHERE NEQ, ITOL, RTOL, AND ATOL ARE AS IN THE LSODE CALL SEQUENCE,
-C YCUR CONTAINS THE CURRENT DEPENDENT VARIABLE VECTOR, AND
-C EWT IS THE ARRAY OF WEIGHTS SET BY EWSET.
-C
-C IF THE USER SUPPLIES THIS SUBROUTINE, IT MUST RETURN IN EWT(I)
-C (I = 1,...,NEQ) A POSITIVE QUANTITY SUITABLE FOR COMPARING ERRORS
-C IN Y(I) TO.  THE EWT ARRAY RETURNED BY EWSET IS PASSED TO THE
-C VNORM ROUTINE (SEE BELOW), AND ALSO USED BY LSODE IN THE COMPUTATION
-C OF THE OPTIONAL OUTPUT IMXER, THE DIAGONAL JACOBIAN APPROXIMATION,
-C AND THE INCREMENTS FOR DIFFERENCE QUOTIENT JACOBIANS.
-C
-C IN THE USER-SUPPLIED VERSION OF EWSET, IT MAY BE DESIRABLE TO USE
-C THE CURRENT VALUES OF DERIVATIVES OF Y.  DERIVATIVES UP TO ORDER NQ
-C ARE AVAILABLE FROM THE HISTORY ARRAY YH, DESCRIBED ABOVE UNDER
-C OPTIONAL OUTPUTS.  IN EWSET, YH IS IDENTICAL TO THE YCUR ARRAY,
-C EXTENDED TO NQ + 1 COLUMNS WITH A COLUMN LENGTH OF NYH AND SCALE
-C FACTORS OF H**J/FACTORIAL(J).  ON THE FIRST CALL FOR THE PROBLEM,
-C GIVEN BY NST = 0, NQ IS 1 AND H IS TEMPORARILY SET TO 1.0.
-C THE QUANTITIES NQ, NYH, H, AND NST CAN BE OBTAINED BY INCLUDING
-C IN EWSET THE STATEMENTS..
-C     DOUBLE PRECISION H, RLS
-C     COMMON /LS0001/ RLS(218),ILS(39)
-C     NQ = ILS(35)
-C     NYH = ILS(14)
-C     NST = ILS(36)
-C     H = RLS(212)
-C THUS, FOR EXAMPLE, THE CURRENT VALUE OF DY/DT CAN BE OBTAINED AS
-C YCUR(NYH+I)/H  (I=1,...,NEQ)  (AND THE DIVISION BY H IS
-C UNNECESSARY WHEN NST = 0).
+C     If the user supplies this function, it should return a nonnegative
+C     value of DVNORM suitable for use in the error control in DLSODE.
+C     None of the arguments should be altered by DVNORM.  For example, a
+C     user-supplied DVNORM routine might:
+C     - Substitute a max-norm of (v(i)*w(i)) for the rms-norm, or
+C     - Ignore some components of v in the norm, with the effect of
+C       suppressing the error control on those components of Y.
+C  ---------------------------------------------------------------------
+C***ROUTINES CALLED  DEWSET, DINTDY, D1MACH, DSTODE, DVNORM, XERRWD
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYYYMMDD)
+C 19791129  DATE WRITTEN
+C 19791213  Minor changes to declarations; DELP init. in STODE.
+C 19800118  Treat NEQ as array; integer declarations added throughout;
+C           minor changes to prologue.
+C 19800306  Corrected TESCO(1,NQP1) setting in CFODE.
+C 19800519  Corrected access of YH on forced order reduction;
+C           numerous corrections to prologues and other comments.
+C 19800617  In main driver, added loading of SQRT(UROUND) in RWORK;
+C           minor corrections to main prologue.
+C 19800923  Added zero initialization of HU and NQU.
+C 19801218  Revised XERRWD routine; minor corrections to main prologue.
+C 19810401  Minor changes to comments and an error message.
+C 19810814  Numerous revisions: replaced EWT by 1/EWT; used flags
+C           JCUR, ICF, IERPJ, IERSL between STODE and subordinates;
+C           added tuning parameters CCMAX, MAXCOR, MSBP, MXNCF;
+C           reorganized returns from STODE; reorganized type decls.;
+C           fixed message length in XERRWD; changed default LUNIT to 6;
+C           changed Common lengths; changed comments throughout.
+C 19870330  Major update by ACH: corrected comments throughout;
+C           removed TRET from Common; rewrote EWSET with 4 loops;
+C           fixed t test in INTDY; added Cray directives in STODE;
+C           in STODE, fixed DELP init. and logic around PJAC call;
+C           combined routines to save/restore Common;
+C           passed LEVEL = 0 in error message calls (except run abort).
+C 19890426  Modified prologue to SLATEC/LDOC format.  (FNF)
+C 19890501  Many improvements to prologue.  (FNF)
+C 19890503  A few final corrections to prologue.  (FNF)
+C 19890504  Minor cosmetic changes.  (FNF)
+C 19890510  Corrected description of Y in Arguments section.  (FNF)
+C 19890517  Minor corrections to prologue.  (FNF)
+C 19920514  Updated with prologue edited 891025 by G. Shaw for manual.
+C 19920515  Converted source lines to upper case.  (FNF)
+C 19920603  Revised XERRWD calls using mixed upper-lower case.  (ACH)
+C 19920616  Revised prologue comment regarding CFT.  (ACH)
+C 19921116  Revised prologue comments regarding Common.  (ACH).
+C 19930326  Added comment about non-reentrancy.  (FNF)
+C 19930723  Changed D1MACH to DUMACH. (FNF)
+C 19930801  Removed ILLIN and NTREP from Common (affects driver logic);
+C           minor changes to prologue and internal comments;
+C           changed Hollerith strings to quoted strings; 
+C           changed internal comments to mixed case;
+C           replaced XERRWD with new version using character type;
+C           changed dummy dimensions from 1 to *. (ACH)
+C 19930809  Changed to generic intrinsic names; changed names of
+C           subprograms and Common blocks to DLSODE etc. (ACH)
+C 19930929  Eliminated use of REAL intrinsic; other minor changes. (ACH)
+C 20010412  Removed all 'own' variables from Common block /DLS001/
+C           (affects declarations in 6 routines). (ACH)
+C 20010509  Minor corrections to prologue. (ACH)
+C 20031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C 20031112  Added SAVE statements for data-loaded constants.
 C
-C (B) VNORM.
-C THE FOLLOWING IS A REAL FUNCTION ROUTINE WHICH COMPUTES THE WEIGHTED
-C ROOT-MEAN-SQUARE NORM OF A VECTOR V..
-C     D = VNORM (N, V, W)
-C WHERE..
-C   N = THE LENGTH OF THE VECTOR,
-C   V = REAL ARRAY OF LENGTH N CONTAINING THE VECTOR,
-C   W = REAL ARRAY OF LENGTH N CONTAINING WEIGHTS,
-C   D = SQRT( (1/N) * SUM(V(I)*W(I))**2 ).
-C VNORM IS CALLED WITH N = NEQ AND WITH W(I) = 1.0/EWT(I), WHERE
-C EWT IS AS SET BY SUBROUTINE EWSET.
+C***END PROLOGUE  DLSODE
+C
+C*Internal Notes:
+C
+C Other Routines in the DLSODE Package.
 C
-C IF THE USER SUPPLIES THIS FUNCTION, IT SHOULD RETURN A NON-NEGATIVE
-C VALUE OF VNORM SUITABLE FOR USE IN THE ERROR CONTROL IN LSODE.
-C NONE OF THE ARGUMENTS SHOULD BE ALTERED BY VNORM.
-C FOR EXAMPLE, A USER-SUPPLIED VNORM ROUTINE MIGHT..
-C   -SUBSTITUTE A MAX-NORM OF (V(I)*W(I)) FOR THE RMS-NORM, OR
-C   -IGNORE SOME COMPONENTS OF V IN THE NORM, WITH THE EFFECT OF
-C    SUPPRESSING THE ERROR CONTROL ON THOSE COMPONENTS OF Y.
-C-----------------------------------------------------------------------
-C-----------------------------------------------------------------------
-C OTHER ROUTINES IN THE LSODE PACKAGE.
-C
-C IN ADDITION TO SUBROUTINE LSODE, THE LSODE PACKAGE INCLUDES THE
-C FOLLOWING SUBROUTINES AND FUNCTION ROUTINES..
-C  INTDY    COMPUTES AN INTERPOLATED VALUE OF THE Y VECTOR AT T = TOUT.
-C  STODE    IS THE CORE INTEGRATOR, WHICH DOES ONE STEP OF THE
-C           INTEGRATION AND THE ASSOCIATED ERROR CONTROL.
-C  CFODE    SETS ALL METHOD COEFFICIENTS AND TEST CONSTANTS.
-C  PREPJ    COMPUTES AND PREPROCESSES THE JACOBIAN MATRIX J = DF/DY
-C           AND THE NEWTON ITERATION MATRIX P = I - H*L0*J.
-C  SOLSY    MANAGES SOLUTION OF LINEAR SYSTEM IN CHORD ITERATION.
-C  EWSET    SETS THE ERROR WEIGHT VECTOR EWT BEFORE EACH STEP.
-C  VNORM    COMPUTES THE WEIGHTED R.M.S. NORM OF A VECTOR.
-C  SRCOM    IS A USER-CALLABLE ROUTINE TO SAVE AND RESTORE
-C           THE CONTENTS OF THE INTERNAL COMMON BLOCKS.
+C In addition to Subroutine DLSODE, the DLSODE package includes the
+C following subroutines and function routines:
+C  DINTDY   computes an interpolated value of the y vector at t = TOUT.
+C  DSTODE   is the core integrator, which does one step of the
+C           integration and the associated error control.
+C  DCFODE   sets all method coefficients and test constants.
+C  DPREPJ   computes and preprocesses the Jacobian matrix J = df/dy
+C           and the Newton iteration matrix P = I - h*l0*J.
+C  DSOLSY   manages solution of linear system in chord iteration.
+C  DEWSET   sets the error weight vector EWT before each step.
+C  DVNORM   computes the weighted R.M.S. norm of a vector.
+C  DSRCOM   is a user-callable routine to save and restore
+C           the contents of the internal Common block.
 C  DGETRF AND DGETRS   ARE ROUTINES FROM LAPACK FOR SOLVING FULL
 C           SYSTEMS OF LINEAR ALGEBRAIC EQUATIONS.
 C  DGBTRF AND DGBTRS   ARE ROUTINES FROM LAPACK FOR SOLVING BANDED
 C           LINEAR SYSTEMS.
-C  DAXPY, DSCAL, IDAMAX, AND DDOT   ARE BASIC LINEAR ALGEBRA MODULES
-C           (BLAS) USED BY THE ABOVE LINPACK ROUTINES.
-C  D1MACH   COMPUTES THE UNIT ROUNDOFF IN A MACHINE-INDEPENDENT MANNER.
-C  XERRWD, XSETUN, AND XSETF   HANDLE THE PRINTING OF ALL ERROR
-C           MESSAGES AND WARNINGS.  XERRWD IS MACHINE-DEPENDENT.
-C NOTE..  VNORM, IDAMAX, DDOT, AND D1MACH ARE FUNCTION ROUTINES.
-C ALL THE OTHERS ARE SUBROUTINES.
+C  D1MACH   computes the unit roundoff in a machine-independent manner.
+C  XERRWD, XSETUN, XSETF, IXSAV, IUMACH   handle the printing of all
+C           error messages and warnings.  XERRWD is machine-dependent.
+C Note: DVNORM, DUMACH, IXSAV, and IUMACH are function routines.
+C All the others are subroutines.
 C
-C THE INTRINSIC AND EXTERNAL ROUTINES USED BY LSODE ARE..
-C DABS, DMAX1, DMIN1, DBLE, MAX0, MIN0, MOD, DSIGN, DSQRT, AND WRITE.
-C
-C A BLOCK DATA SUBPROGRAM IS ALSO INCLUDED WITH THE PACKAGE,
-C FOR LOADING SOME OF THE VARIABLES IN INTERNAL COMMON.
+C**End
 C
-C-----------------------------------------------------------------------
-C THE FOLLOWING CARD IS FOR OPTIMIZED COMPILATION ON LLNL COMPILERS.
-CLLL. OPTIMIZE
-C-----------------------------------------------------------------------
-      EXTERNAL PREPJ, SOLSY
+C  Declare externals.
+      EXTERNAL DPREPJ, DSOLSY
+      DOUBLE PRECISION D1MACH, DVNORM
+C
+C  Declare all other variables.
       INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
      1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
      2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
@@ -954,25 +1216,22 @@
       DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
      1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
       DOUBLE PRECISION ATOLI, AYI, BIG, EWTI, H0, HMAX, HMX, RH, RTOLI,
-     1   TCRIT, TDIST, TNEXT, TOL, TOLSF, TP, SIZE, SUM, W0,
-     2   D1MACH, VNORM
+     1   TCRIT, TDIST, TNEXT, TOL, TOLSF, TP, SIZE, SUM, W0
       DIMENSION MORD(2)
       LOGICAL IHIT
+      CHARACTER*80 MSG
+      SAVE MORD, MXSTP0, MXHNL0
 C-----------------------------------------------------------------------
-C THE FOLLOWING INTERNAL COMMON BLOCK CONTAINS
-C (A) VARIABLES WHICH ARE LOCAL TO ANY SUBROUTINE BUT WHOSE VALUES MUST
-C     BE PRESERVED BETWEEN CALLS TO THE ROUTINE (OWN VARIABLES), AND
-C (B) VARIABLES WHICH ARE COMMUNICATED BETWEEN SUBROUTINES.
-C THE STRUCTURE OF THE BLOCK IS AS FOLLOWS..  ALL REAL VARIABLES ARE
-C LISTED FIRST, FOLLOWED BY ALL INTEGERS.  WITHIN EACH TYPE, THE
-C VARIABLES ARE GROUPED WITH THOSE LOCAL TO SUBROUTINE LSODE FIRST,
-C THEN THOSE LOCAL TO SUBROUTINE STODE, AND FINALLY THOSE USED
-C FOR COMMUNICATION.  THE BLOCK IS DECLARED IN SUBROUTINES
-C LSODE, INTDY, STODE, PREPJ, AND SOLSY.  GROUPS OF VARIABLES ARE
-C REPLACED BY DUMMY ARRAYS IN THE COMMON DECLARATIONS IN ROUTINES
-C WHERE THOSE VARIABLES ARE NOT USED.
+C The following internal Common block contains
+C (a) variables which are local to any subroutine but whose values must
+C     be preserved between calls to the routine ("own" variables), and
+C (b) variables which are communicated between subroutines.
+C The block DLS001 is declared in subroutines DLSODE, DINTDY, DSTODE,
+C DPREPJ, and DSOLSY.
+C Groups of variables are replaced by dummy arrays in the Common
+C declarations in routines where those variables are not used.
 C-----------------------------------------------------------------------
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
      1   HOLD, RMAX, TESCO(3,12),
      1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
      2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
@@ -983,13 +1242,15 @@
 C
       DATA  MORD(1),MORD(2)/12,5/, MXSTP0/500/, MXHNL0/10/
 C-----------------------------------------------------------------------
-C BLOCK A.
-C THIS CODE BLOCK IS EXECUTED ON EVERY CALL.
-C IT TESTS ISTATE AND ITASK FOR LEGALITY AND BRANCHES APPROPRIATELY.
-C IF ISTATE .GT. 1 BUT THE FLAG INIT SHOWS THAT INITIALIZATION HAS
-C NOT YET BEEN DONE, AN ERROR RETURN OCCURS.
-C IF ISTATE = 1 AND TOUT = T, JUMP TO BLOCK G AND RETURN IMMEDIATELY.
+C Block A.
+C This code block is executed on every call.
+C It tests ISTATE and ITASK for legality and branches appropriately.
+C If ISTATE .GT. 1 but the flag INIT shows that initialization has
+C not yet been done, an error return occurs.
+C If ISTATE = 1 and TOUT = T, return immediately.
 C-----------------------------------------------------------------------
+C
+C***FIRST EXECUTABLE STATEMENT  DLSODE
       IF (ISTATE .LT. 1 .OR. ISTATE .GT. 3) GO TO 601
       IF (ITASK .LT. 1 .OR. ITASK .GT. 5) GO TO 602
       IF (ISTATE .EQ. 1) GO TO 10
@@ -997,18 +1258,17 @@
       IF (ISTATE .EQ. 2) GO TO 200
       GO TO 20
  10   INIT = 0
-      IF (TOUT .EQ. T) GO TO 430
- 20   NTREP = 0
+      IF (TOUT .EQ. T) RETURN
 C-----------------------------------------------------------------------
-C BLOCK B.
-C THE NEXT CODE BLOCK IS EXECUTED FOR THE INITIAL CALL (ISTATE = 1),
-C OR FOR A CONTINUATION CALL WITH PARAMETER CHANGES (ISTATE = 3).
-C IT CONTAINS CHECKING OF ALL INPUTS AND VARIOUS INITIALIZATIONS.
+C Block B.
+C The next code block is executed for the initial call (ISTATE = 1),
+C or for a continuation call with parameter changes (ISTATE = 3).
+C It contains checking of all inputs and various initializations.
 C
-C FIRST CHECK LEGALITY OF THE NON-OPTIONAL INPUTS NEQ, ITOL, IOPT,
-C MF, ML, AND MU.
+C First check legality of the non-optional inputs NEQ, ITOL, IOPT,
+C MF, ML, and MU.
 C-----------------------------------------------------------------------
-      IF (NEQ(1) .LE. 0) GO TO 604
+ 20   IF (NEQ(1) .LE. 0) GO TO 604
       IF (ISTATE .EQ. 1) GO TO 25
       IF (NEQ(1) .GT. N) GO TO 605
  25   N = NEQ(1)
@@ -1024,7 +1284,7 @@
       IF (ML .LT. 0 .OR. ML .GE. N) GO TO 609
       IF (MU .LT. 0 .OR. MU .GE. N) GO TO 610
  30   CONTINUE
-C NEXT PROCESS AND CHECK THE OPTIONAL INPUTS. --------------------------
+C Next process and check the optional inputs. --------------------------
       IF (IOPT .EQ. 1) GO TO 40
       MAXORD = MORD(METH)
       MXSTEP = MXSTP0
@@ -1036,7 +1296,7 @@
  40   MAXORD = IWORK(5)
       IF (MAXORD .LT. 0) GO TO 611
       IF (MAXORD .EQ. 0) MAXORD = 100
-      MAXORD = MIN0(MAXORD,MORD(METH))
+      MAXORD = MIN(MAXORD,MORD(METH))
       MXSTEP = IWORK(6)
       IF (MXSTEP .LT. 0) GO TO 612
       IF (MXSTEP .EQ. 0) MXSTEP = MXSTP0
@@ -1053,10 +1313,10 @@
       HMIN = RWORK(7)
       IF (HMIN .LT. 0.0D0) GO TO 616
 C-----------------------------------------------------------------------
-C SET WORK ARRAY POINTERS AND CHECK LENGTHS LRW AND LIW.
-C POINTERS TO SEGMENTS OF RWORK AND IWORK ARE NAMED BY PREFIXING L TO
-C THE NAME OF THE SEGMENT.  E.G., THE SEGMENT YH STARTS AT RWORK(LYH).
-C SEGMENTS OF RWORK (IN ORDER) ARE DENOTED  YH, WM, EWT, SAVF, ACOR.
+C Set work array pointers and check lengths LRW and LIW.
+C Pointers to segments of RWORK and IWORK are named by prefixing L to
+C the name of the segment.  E.g., the segment YH starts at RWORK(LYH).
+C Segments of RWORK (in order) are denoted  YH, WM, EWT, SAVF, ACOR.
 C-----------------------------------------------------------------------
  60   LYH = 21
       IF (ISTATE .EQ. 1) NYH = N
@@ -1076,7 +1336,7 @@
       IWORK(18) = LENIW
       IF (LENRW .GT. LRW) GO TO 617
       IF (LENIW .GT. LIW) GO TO 618
-C CHECK RTOL AND ATOL FOR LEGALITY. ------------------------------------
+C Check RTOL and ATOL for legality. ------------------------------------
       RTOLI = RTOL(1)
       ATOLI = ATOL(1)
       DO 70 I = 1,N
@@ -1086,16 +1346,16 @@
         IF (ATOLI .LT. 0.0D0) GO TO 620
  70     CONTINUE
       IF (ISTATE .EQ. 1) GO TO 100
-C IF ISTATE = 3, SET FLAG TO SIGNAL PARAMETER CHANGES TO STODE. --------
+C If ISTATE = 3, set flag to signal parameter changes to DSTODE. -------
       JSTART = -1
       IF (NQ .LE. MAXORD) GO TO 90
-C MAXORD WAS REDUCED BELOW NQ.  COPY YH(*,MAXORD+2) INTO SAVF. ---------
+C MAXORD was reduced below NQ.  Copy YH(*,MAXORD+2) into SAVF. ---------
       DO 80 I = 1,N
  80     RWORK(I+LSAVF-1) = RWORK(I+LWM-1)
-C RELOAD WM(1) = RWORK(LWM), SINCE LWM MAY HAVE CHANGED. ---------------
- 90   IF (MITER .GT. 0) RWORK(LWM) = DSQRT(UROUND)
+C Reload WM(1) = RWORK(LWM), since LWM may have changed. ---------------
+ 90   IF (MITER .GT. 0) RWORK(LWM) = SQRT(UROUND)
       IF (N .EQ. NYH) GO TO 200
-C NEQ WAS REDUCED.  ZERO PART OF YH TO AVOID UNDEFINED REFERENCES. -----
+C NEQ was reduced.  Zero part of YH to avoid undefined references. -----
       I1 = LYH + L*NYH
       I2 = LYH + (MAXORD + 1)*NYH - 1
       IF (I1 .GT. I2) GO TO 200
@@ -1103,11 +1363,11 @@
  95     RWORK(I) = 0.0D0
       GO TO 200
 C-----------------------------------------------------------------------
-C BLOCK C.
-C THE NEXT BLOCK IS FOR THE INITIAL CALL ONLY (ISTATE = 1).
-C IT CONTAINS ALL REMAINING INITIALIZATIONS, THE INITIAL CALL TO F,
-C AND THE CALCULATION OF THE INITIAL STEP SIZE.
-C THE ERROR WEIGHTS IN EWT ARE INVERTED AFTER BEING LOADED.
+C Block C.
+C The next block is for the initial call only (ISTATE = 1).
+C It contains all remaining initializations, the initial call to F,
+C and the calculation of the initial step size.
+C The error weights in EWT are inverted after being loaded.
 C-----------------------------------------------------------------------
  100  UROUND = D1MACH(4)
       TN = T
@@ -1117,7 +1377,7 @@
       IF (H0 .NE. 0.0D0 .AND. (T + H0 - TCRIT)*H0 .GT. 0.0D0)
      1   H0 = TCRIT - T
  110  JSTART = 0
-      IF (MITER .GT. 0) RWORK(LWM) = DSQRT(UROUND)
+      IF (MITER .GT. 0) RWORK(LWM) = SQRT(UROUND)
       NHNIL = 0
       NST = 0
       NJE = 0
@@ -1128,80 +1388,75 @@
       MAXCOR = 3
       MSBP = 20
       MXNCF = 10
-C INITIAL CALL TO F.  (LF0 POINTS TO YH(*,2).) -------------------------
+C Initial call to F.  (LF0 points to YH(*,2).) -------------------------
       LF0 = LYH + NYH
-      IERR = 0
-      CALL F (NEQ, T, Y, RWORK(LF0), IERR)
-      IF (IERR .LT. 0) THEN
-        ISTATE = -13
-        RETURN
-      ENDIF
+      CALL F (NEQ, T, Y, RWORK(LF0))
       NFE = 1
-C LOAD THE INITIAL VALUE VECTOR IN YH. ---------------------------------
+C Load the initial value vector in YH. ---------------------------------
       DO 115 I = 1,N
  115    RWORK(I+LYH-1) = Y(I)
-C LOAD AND INVERT THE EWT ARRAY.  (H IS TEMPORARILY SET TO 1.0.) -------
+C Load and invert the EWT array.  (H is temporarily set to 1.0.) -------
       NQ = 1
       H = 1.0D0
-      CALL EWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT))
+      CALL DEWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT))
       DO 120 I = 1,N
         IF (RWORK(I+LEWT-1) .LE. 0.0D0) GO TO 621
  120    RWORK(I+LEWT-1) = 1.0D0/RWORK(I+LEWT-1)
 C-----------------------------------------------------------------------
-C THE CODING BELOW COMPUTES THE STEP SIZE, H0, TO BE ATTEMPTED ON THE
-C FIRST STEP, UNLESS THE USER HAS SUPPLIED A VALUE FOR THIS.
-C FIRST CHECK THAT TOUT - T DIFFERS SIGNIFICANTLY FROM ZERO.
-C A SCALAR TOLERANCE QUANTITY TOL IS COMPUTED, AS MAX(RTOL(I))
-C IF THIS IS POSITIVE, OR MAX(ATOL(I)/ABS(Y(I))) OTHERWISE, ADJUSTED
-C SO AS TO BE BETWEEN 100*UROUND AND 1.0E-3.
-C THEN THE COMPUTED VALUE H0 IS GIVEN BY..
+C The coding below computes the step size, H0, to be attempted on the
+C first step, unless the user has supplied a value for this.
+C First check that TOUT - T differs significantly from zero.
+C A scalar tolerance quantity TOL is computed, as MAX(RTOL(I))
+C if this is positive, or MAX(ATOL(I)/ABS(Y(I))) otherwise, adjusted
+C so as to be between 100*UROUND and 1.0E-3.
+C Then the computed value H0 is given by..
 C                                      NEQ
-C   H0**2 = TOL / ( W0**-2 + (1/NEQ) * SUM ( F(I)/YWT(I) )**2  )
+C   H0**2 = TOL / ( w0**-2 + (1/NEQ) * SUM ( f(i)/ywt(i) )**2  )
 C                                       1
-C WHERE   W0     = MAX ( ABS(T), ABS(TOUT) ),
-C         F(I)   = I-TH COMPONENT OF INITIAL VALUE OF F,
-C         YWT(I) = EWT(I)/TOL  (A WEIGHT FOR Y(I)).
-C THE SIGN OF H0 IS INFERRED FROM THE INITIAL VALUES OF TOUT AND T.
+C where   w0     = MAX ( ABS(T), ABS(TOUT) ),
+C         f(i)   = i-th component of initial value of f,
+C         ywt(i) = EWT(i)/TOL  (a weight for y(i)).
+C The sign of H0 is inferred from the initial values of TOUT and T.
 C-----------------------------------------------------------------------
       IF (H0 .NE. 0.0D0) GO TO 180
-      TDIST = DABS(TOUT - T)
-      W0 = DMAX1(DABS(T),DABS(TOUT))
+      TDIST = ABS(TOUT - T)
+      W0 = MAX(ABS(T),ABS(TOUT))
       IF (TDIST .LT. 2.0D0*UROUND*W0) GO TO 622
       TOL = RTOL(1)
       IF (ITOL .LE. 2) GO TO 140
       DO 130 I = 1,N
- 130    TOL = DMAX1(TOL,RTOL(I))
+ 130    TOL = MAX(TOL,RTOL(I))
  140  IF (TOL .GT. 0.0D0) GO TO 160
       ATOLI = ATOL(1)
       DO 150 I = 1,N
         IF (ITOL .EQ. 2 .OR. ITOL .EQ. 4) ATOLI = ATOL(I)
-        AYI = DABS(Y(I))
-        IF (AYI .NE. 0.0D0) TOL = DMAX1(TOL,ATOLI/AYI)
+        AYI = ABS(Y(I))
+        IF (AYI .NE. 0.0D0) TOL = MAX(TOL,ATOLI/AYI)
  150    CONTINUE
- 160  TOL = DMAX1(TOL,100.0D0*UROUND)
-      TOL = DMIN1(TOL,0.001D0)
-      SUM = VNORM (N, RWORK(LF0), RWORK(LEWT))
+ 160  TOL = MAX(TOL,100.0D0*UROUND)
+      TOL = MIN(TOL,0.001D0)
+      SUM = DVNORM (N, RWORK(LF0), RWORK(LEWT))
       SUM = 1.0D0/(TOL*W0*W0) + TOL*SUM**2
-      H0 = 1.0D0/DSQRT(SUM)
-      H0 = DMIN1(H0,TDIST)
-      H0 = DSIGN(H0,TOUT-T)
-C ADJUST H0 IF NECESSARY TO MEET HMAX BOUND. ---------------------------
- 180  RH = DABS(H0)*HMXI
+      H0 = 1.0D0/SQRT(SUM)
+      H0 = MIN(H0,TDIST)
+      H0 = SIGN(H0,TOUT-T)
+C Adjust H0 if necessary to meet HMAX bound. ---------------------------
+ 180  RH = ABS(H0)*HMXI
       IF (RH .GT. 1.0D0) H0 = H0/RH
-C LOAD H WITH H0 AND SCALE YH(*,2) BY H0. ------------------------------
+C Load H with H0 and scale YH(*,2) by H0. ------------------------------
       H = H0
       DO 190 I = 1,N
  190    RWORK(I+LF0-1) = H0*RWORK(I+LF0-1)
       GO TO 270
 C-----------------------------------------------------------------------
-C BLOCK D.
-C THE NEXT CODE BLOCK IS FOR CONTINUATION CALLS ONLY (ISTATE = 2 OR 3)
-C AND IS TO CHECK STOP CONDITIONS BEFORE TAKING A STEP.
+C Block D.
+C The next code block is for continuation calls only (ISTATE = 2 or 3)
+C and is to check stop conditions before taking a step.
 C-----------------------------------------------------------------------
  200  NSLAST = NST
       GO TO (210, 250, 220, 230, 240), ITASK
  210  IF ((TN - TOUT)*H .LT. 0.0D0) GO TO 250
-      CALL INTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
+      CALL DINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
       IF (IFLAG .NE. 0) GO TO 627
       T = TOUT
       GO TO 420
@@ -1213,37 +1468,37 @@
       IF ((TN - TCRIT)*H .GT. 0.0D0) GO TO 624
       IF ((TCRIT - TOUT)*H .LT. 0.0D0) GO TO 625
       IF ((TN - TOUT)*H .LT. 0.0D0) GO TO 245
-      CALL INTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
+      CALL DINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
       IF (IFLAG .NE. 0) GO TO 627
       T = TOUT
       GO TO 420
  240  TCRIT = RWORK(1)
       IF ((TN - TCRIT)*H .GT. 0.0D0) GO TO 624
- 245  HMX = DABS(TN) + DABS(H)
-      IHIT = DABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
+ 245  HMX = ABS(TN) + ABS(H)
+      IHIT = ABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
       IF (IHIT) GO TO 400
       TNEXT = TN + H*(1.0D0 + 4.0D0*UROUND)
       IF ((TNEXT - TCRIT)*H .LE. 0.0D0) GO TO 250
       H = (TCRIT - TN)*(1.0D0 - 4.0D0*UROUND)
       IF (ISTATE .EQ. 2) JSTART = -2
 C-----------------------------------------------------------------------
-C BLOCK E.
-C THE NEXT BLOCK IS NORMALLY EXECUTED FOR ALL CALLS AND CONTAINS
-C THE CALL TO THE ONE-STEP CORE INTEGRATOR STODE.
+C Block E.
+C The next block is normally executed for all calls and contains
+C the call to the one-step core integrator DSTODE.
 C
-C THIS IS A LOOPING POINT FOR THE INTEGRATION STEPS.
+C This is a looping point for the integration steps.
 C
-C FIRST CHECK FOR TOO MANY STEPS BEING TAKEN, UPDATE EWT (IF NOT AT
-C START OF PROBLEM), CHECK FOR TOO MUCH ACCURACY BEING REQUESTED, AND
-C CHECK FOR H BELOW THE ROUNDOFF LEVEL IN T.
+C First check for too many steps being taken, update EWT (if not at
+C start of problem), check for too much accuracy being requested, and
+C check for H below the roundoff level in T.
 C-----------------------------------------------------------------------
  250  CONTINUE
       IF ((NST-NSLAST) .GE. MXSTEP) GO TO 500
-      CALL EWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT))
+      CALL DEWSET (N, ITOL, RTOL, ATOL, RWORK(LYH), RWORK(LEWT))
       DO 260 I = 1,N
         IF (RWORK(I+LEWT-1) .LE. 0.0D0) GO TO 510
  260    RWORK(I+LEWT-1) = 1.0D0/RWORK(I+LEWT-1)
- 270  TOLSF = UROUND*VNORM (N, RWORK(LYH), RWORK(LEWT))
+ 270  TOLSF = UROUND*DVNORM (N, RWORK(LYH), RWORK(LEWT))
       IF (TOLSF .LE. 1.0D0) GO TO 280
       TOLSF = TOLSF*2.0D0
       IF (NST .EQ. 0) GO TO 626
@@ -1251,71 +1506,63 @@
  280  IF ((TN + H) .NE. TN) GO TO 290
       NHNIL = NHNIL + 1
       IF (NHNIL .GT. MXHNIL) GO TO 290
-      CALL XERRWD('LSODE--  WARNING..INTERNAL T (=R1) AND H (=R2) ARE',
-     1   50, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD(
-     1  '      SUCH THAT IN THE MACHINE, T + H = T ON THE NEXT STEP  ',
-     1   60, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      (H = STEP SIZE). SOLVER WILL CONTINUE ANYWAY',
-     1   50, 101, 0, 0, 0, 0, 2, TN, H)
+      MSG = 'DLSODE-  Warning..internal T (=R1) and H (=R2) are'
+      CALL XERRWD (MSG, 50, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG='      such that in the machine, T + H = T on the next step  '
+      CALL XERRWD (MSG, 60, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      (H = step size). Solver will continue anyway'
+      CALL XERRWD (MSG, 50, 101, 0, 0, 0, 0, 2, TN, H)
       IF (NHNIL .LT. MXHNIL) GO TO 290
-      CALL XERRWD('LSODE--  ABOVE WARNING HAS BEEN ISSUED I1 TIMES.  ',
-     1   50, 102, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      IT WILL NOT BE ISSUED AGAIN FOR THIS PROBLEM',
-     1   50, 102, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
+      MSG = 'DLSODE-  Above warning has been issued I1 times.  '
+      CALL XERRWD (MSG, 50, 102, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      It will not be issued again for this problem'
+      CALL XERRWD (MSG, 50, 102, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
  290  CONTINUE
 C-----------------------------------------------------------------------
-C     CALL STODE(NEQ,Y,YH,NYH,YH,EWT,SAVF,ACOR,WM,IWM,F,JAC,PREPJ,SOLSY)
+C  CALL DSTODE(NEQ,Y,YH,NYH,YH,EWT,SAVF,ACOR,WM,IWM,F,JAC,DPREPJ,DSOLSY)
 C-----------------------------------------------------------------------
-      IERR = 0
-      CALL STODE (NEQ, Y, RWORK(LYH), NYH, RWORK(LYH), RWORK(LEWT),
+      CALL DSTODE (NEQ, Y, RWORK(LYH), NYH, RWORK(LYH), RWORK(LEWT),
      1   RWORK(LSAVF), RWORK(LACOR), RWORK(LWM), IWORK(LIWM),
-     2   F, JAC, PREPJ, SOLSY, IERR)
-      IF (IERR .LT. 0) THEN
-        ISTATE = -13
-        RETURN
-      ENDIF
+     2   F, JAC, DPREPJ, DSOLSY)
       KGO = 1 - KFLAG
       GO TO (300, 530, 540), KGO
 C-----------------------------------------------------------------------
-C BLOCK F.
-C THE FOLLOWING BLOCK HANDLES THE CASE OF A SUCCESSFUL RETURN FROM THE
-C CORE INTEGRATOR (KFLAG = 0).  TEST FOR STOP CONDITIONS.
+C Block F.
+C The following block handles the case of a successful return from the
+C core integrator (KFLAG = 0).  Test for stop conditions.
 C-----------------------------------------------------------------------
  300  INIT = 1
       GO TO (310, 400, 330, 340, 350), ITASK
-C ITASK = 1.  IF TOUT HAS BEEN REACHED, INTERPOLATE. -------------------
+C ITASK = 1.  If TOUT has been reached, interpolate. -------------------
  310  IF ((TN - TOUT)*H .LT. 0.0D0) GO TO 250
-      CALL INTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
+      CALL DINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
       T = TOUT
       GO TO 420
-C ITASK = 3.  JUMP TO EXIT IF TOUT WAS REACHED. ------------------------
+C ITASK = 3.  Jump to exit if TOUT was reached. ------------------------
  330  IF ((TN - TOUT)*H .GE. 0.0D0) GO TO 400
       GO TO 250
-C ITASK = 4.  SEE IF TOUT OR TCRIT WAS REACHED.  ADJUST H IF NECESSARY.
+C ITASK = 4.  See if TOUT or TCRIT was reached.  Adjust H if necessary.
  340  IF ((TN - TOUT)*H .LT. 0.0D0) GO TO 345
-      CALL INTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
+      CALL DINTDY (TOUT, 0, RWORK(LYH), NYH, Y, IFLAG)
       T = TOUT
       GO TO 420
- 345  HMX = DABS(TN) + DABS(H)
-      IHIT = DABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
+ 345  HMX = ABS(TN) + ABS(H)
+      IHIT = ABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
       IF (IHIT) GO TO 400
       TNEXT = TN + H*(1.0D0 + 4.0D0*UROUND)
       IF ((TNEXT - TCRIT)*H .LE. 0.0D0) GO TO 250
       H = (TCRIT - TN)*(1.0D0 - 4.0D0*UROUND)
       JSTART = -2
       GO TO 250
-C ITASK = 5.  SEE IF TCRIT WAS REACHED AND JUMP TO EXIT. ---------------
- 350  HMX = DABS(TN) + DABS(H)
-      IHIT = DABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
+C ITASK = 5.  See if TCRIT was reached and jump to exit. ---------------
+ 350  HMX = ABS(TN) + ABS(H)
+      IHIT = ABS(TN - TCRIT) .LE. 100.0D0*UROUND*HMX
 C-----------------------------------------------------------------------
-C BLOCK G.
-C THE FOLLOWING BLOCK HANDLES ALL SUCCESSFUL RETURNS FROM LSODE.
-C IF ITASK .NE. 1, Y IS LOADED FROM YH AND T IS SET ACCORDINGLY.
-C ISTATE IS SET TO 2, THE ILLEGAL INPUT COUNTER IS ZEROED, AND THE
-C OPTIONAL OUTPUTS ARE LOADED INTO THE WORK ARRAYS BEFORE RETURNING.
-C IF ISTATE = 1 AND TOUT = T, THERE IS A RETURN WITH NO ACTION TAKEN,
-C EXCEPT THAT IF THIS HAS HAPPENED REPEATEDLY, THE RUN IS TERMINATED.
+C Block G.
+C The following block handles all successful returns from DLSODE.
+C If ITASK .NE. 1, Y is loaded from YH and T is set accordingly.
+C ISTATE is set to 2, and the optional outputs are loaded into the
+C work arrays before returning.
 C-----------------------------------------------------------------------
  400  DO 410 I = 1,N
  410    Y(I) = RWORK(I+LYH-1)
@@ -1323,83 +1570,6 @@
       IF (ITASK .NE. 4 .AND. ITASK .NE. 5) GO TO 420
       IF (IHIT) T = TCRIT
  420  ISTATE = 2
-      ILLIN = 0
-      RWORK(11) = HU
-      RWORK(12) = H
-      RWORK(13) = TN
-      IWORK(11) = NST
-      IWORK(12) = NFE
-      IWORK(13) = NJE
-      IWORK(14) = NQU
-      IWORK(15) = NQ
-      RETURN
-C
- 430  NTREP = NTREP + 1
-      IF (NTREP .LT. 5) RETURN
-      CALL XERRWD(
-     1  'LSODE--  REPEATED CALLS WITH ISTATE = 1 AND TOUT = T (=R1)  ',
-     1   60, 301, 0, 0, 0, 0, 1, T, 0.0D0)
-      GO TO 800
-C-----------------------------------------------------------------------
-C BLOCK H.
-C THE FOLLOWING BLOCK HANDLES ALL UNSUCCESSFUL RETURNS OTHER THAN
-C THOSE FOR ILLEGAL INPUT.  FIRST THE ERROR MESSAGE ROUTINE IS CALLED.
-C IF THERE WAS AN ERROR TEST OR CONVERGENCE TEST FAILURE, IMXER IS SET.
-C THEN Y IS LOADED FROM YH, T IS SET TO TN, AND THE ILLEGAL INPUT
-C COUNTER ILLIN IS SET TO 0.  THE OPTIONAL OUTPUTS ARE LOADED INTO
-C THE WORK ARRAYS BEFORE RETURNING.
-C-----------------------------------------------------------------------
-C THE MAXIMUM NUMBER OF STEPS WAS TAKEN BEFORE REACHING TOUT. ----------
- 500  CALL XERRWD('LSODE--  AT CURRENT T (=R1), MXSTEP (=I1) STEPS   ',
-     1   50, 201, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      TAKEN ON THIS CALL BEFORE REACHING TOUT     ',
-     1   50, 201, 0, 1, MXSTEP, 0, 1, TN, 0.0D0)
-      ISTATE = -1
-      GO TO 580
-C EWT(I) .LE. 0.0 FOR SOME I (NOT AT START OF PROBLEM). ----------------
- 510  EWTI = RWORK(LEWT+I-1)
-      CALL XERRWD('LSODE--  AT T (=R1), EWT(I1) HAS BECOME R2 .LE. 0.',
-     1   50, 202, 0, 1, I, 0, 2, TN, EWTI)
-      ISTATE = -6
-      GO TO 580
-C TOO MUCH ACCURACY REQUESTED FOR MACHINE PRECISION. -------------------
- 520  CALL XERRWD('LSODE--  AT T (=R1), TOO MUCH ACCURACY REQUESTED  ',
-     1   50, 203, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      FOR PRECISION OF MACHINE..  SEE TOLSF (=R2) ',
-     1   50, 203, 0, 0, 0, 0, 2, TN, TOLSF)
-      RWORK(14) = TOLSF
-      ISTATE = -2
-      GO TO 580
-C KFLAG = -1.  ERROR TEST FAILED REPEATEDLY OR WITH ABS(H) = HMIN. -----
- 530  CALL XERRWD('LSODE--  AT T(=R1) AND STEP SIZE H(=R2), THE ERROR',
-     1   50, 204, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      TEST FAILED REPEATEDLY OR WITH ABS(H) = HMIN',
-     1   50, 204, 0, 0, 0, 0, 2, TN, H)
-      ISTATE = -4
-      GO TO 560
-C KFLAG = -2.  CONVERGENCE FAILED REPEATEDLY OR WITH ABS(H) = HMIN. ----
- 540  CALL XERRWD('LSODE--  AT T (=R1) AND STEP SIZE H (=R2), THE    ',
-     1   50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      CORRECTOR CONVERGENCE FAILED REPEATEDLY     ',
-     1   50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      OR WITH ABS(H) = HMIN   ',
-     1   30, 205, 0, 0, 0, 0, 2, TN, H)
-      ISTATE = -5
-C COMPUTE IMXER IF RELEVANT. -------------------------------------------
- 560  BIG = 0.0D0
-      IMXER = 1
-      DO 570 I = 1,N
-        SIZE = DABS(RWORK(I+LACOR-1)*RWORK(I+LEWT-1))
-        IF (BIG .GE. SIZE) GO TO 570
-        BIG = SIZE
-        IMXER = I
- 570    CONTINUE
-      IWORK(16) = IMXER
-C SET Y VECTOR, T, ILLIN, AND OPTIONAL OUTPUTS. ------------------------
- 580  DO 590 I = 1,N
- 590    Y(I) = RWORK(I+LYH-1)
-      T = TN
-      ILLIN = 0
       RWORK(11) = HU
       RWORK(12) = H
       RWORK(13) = TN
@@ -1410,116 +1580,178 @@
       IWORK(15) = NQ
       RETURN
 C-----------------------------------------------------------------------
-C BLOCK I.
-C THE FOLLOWING BLOCK HANDLES ALL ERROR RETURNS DUE TO ILLEGAL INPUT
-C (ISTATE = -3), AS DETECTED BEFORE CALLING THE CORE INTEGRATOR.
-C FIRST THE ERROR MESSAGE ROUTINE IS CALLED.  THEN IF THERE HAVE BEEN
-C 5 CONSECUTIVE SUCH RETURNS JUST BEFORE THIS CALL TO THE SOLVER,
-C THE RUN IS HALTED.
+C Block H.
+C The following block handles all unsuccessful returns other than
+C those for illegal input.  First the error message routine is called.
+C If there was an error test or convergence test failure, IMXER is set.
+C Then Y is loaded from YH and T is set to TN.  The optional outputs
+C are loaded into the work arrays before returning.
 C-----------------------------------------------------------------------
- 601  CALL XERRWD('LSODE--  ISTATE (=I1) ILLEGAL ',
-     1   30, 1, 0, 1, ISTATE, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 602  CALL XERRWD('LSODE--  ITASK (=I1) ILLEGAL  ',
-     1   30, 2, 0, 1, ITASK, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 603  CALL XERRWD('LSODE--  ISTATE .GT. 1 BUT LSODE NOT INITIALIZED  ',
-     1   50, 3, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 604  CALL XERRWD('LSODE--  NEQ (=I1) .LT. 1     ',
-     1   30, 4, 0, 1, NEQ(1), 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 605  CALL XERRWD('LSODE--  ISTATE = 3 AND NEQ INCREASED (I1 TO I2)  ',
-     1   50, 5, 0, 2, N, NEQ(1), 0, 0.0D0, 0.0D0)
-      GO TO 700
- 606  CALL XERRWD('LSODE--  ITOL (=I1) ILLEGAL   ',
-     1   30, 6, 0, 1, ITOL, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 607  CALL XERRWD('LSODE--  IOPT (=I1) ILLEGAL   ',
-     1   30, 7, 0, 1, IOPT, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 608  CALL XERRWD('LSODE--  MF (=I1) ILLEGAL     ',
-     1   30, 8, 0, 1, MF, 0, 0, 0.0D0, 0.0D0)
-      GO TO 700
- 609  CALL XERRWD('LSODE--  ML (=I1) ILLEGAL.. .LT.0 OR .GE.NEQ (=I2)',
-     1   50, 9, 0, 2, ML, NEQ(1), 0, 0.0D0, 0.0D0)
+C The maximum number of steps was taken before reaching TOUT. ----------
+ 500  MSG = 'DLSODE-  At current T (=R1), MXSTEP (=I1) steps   '
+      CALL XERRWD (MSG, 50, 201, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      taken on this call before reaching TOUT     '
+      CALL XERRWD (MSG, 50, 201, 0, 1, MXSTEP, 0, 1, TN, 0.0D0)
+      ISTATE = -1
+      GO TO 580
+C EWT(I) .LE. 0.0 for some I (not at start of problem). ----------------
+ 510  EWTI = RWORK(LEWT+I-1)
+      MSG = 'DLSODE-  At T (=R1), EWT(I1) has become R2 .LE. 0.'
+      CALL XERRWD (MSG, 50, 202, 0, 1, I, 0, 2, TN, EWTI)
+      ISTATE = -6
+      GO TO 580
+C Too much accuracy requested for machine precision. -------------------
+ 520  MSG = 'DLSODE-  At T (=R1), too much accuracy requested  '
+      CALL XERRWD (MSG, 50, 203, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      for precision of machine..  see TOLSF (=R2) '
+      CALL XERRWD (MSG, 50, 203, 0, 0, 0, 0, 2, TN, TOLSF)
+      RWORK(14) = TOLSF
+      ISTATE = -2
+      GO TO 580
+C KFLAG = -1.  Error test failed repeatedly or with ABS(H) = HMIN. -----
+ 530  MSG = 'DLSODE-  At T(=R1) and step size H(=R2), the error'
+      CALL XERRWD (MSG, 50, 204, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      test failed repeatedly or with ABS(H) = HMIN'
+      CALL XERRWD (MSG, 50, 204, 0, 0, 0, 0, 2, TN, H)
+      ISTATE = -4
+      GO TO 560
+C KFLAG = -2.  Convergence failed repeatedly or with ABS(H) = HMIN. ----
+ 540  MSG = 'DLSODE-  At T (=R1) and step size H (=R2), the    '
+      CALL XERRWD (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      corrector convergence failed repeatedly     '
+      CALL XERRWD (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG = '      or with ABS(H) = HMIN   '
+      CALL XERRWD (MSG, 30, 205, 0, 0, 0, 0, 2, TN, H)
+      ISTATE = -5
+C Compute IMXER if relevant. -------------------------------------------
+ 560  BIG = 0.0D0
+      IMXER = 1
+      DO 570 I = 1,N
+        SIZE = ABS(RWORK(I+LACOR-1)*RWORK(I+LEWT-1))
+        IF (BIG .GE. SIZE) GO TO 570
+        BIG = SIZE
+        IMXER = I
+ 570    CONTINUE
+      IWORK(16) = IMXER
+C Set Y vector, T, and optional outputs. -------------------------------
+ 580  DO 590 I = 1,N
+ 590    Y(I) = RWORK(I+LYH-1)
+      T = TN
+      RWORK(11) = HU
+      RWORK(12) = H
+      RWORK(13) = TN
+      IWORK(11) = NST
+      IWORK(12) = NFE
+      IWORK(13) = NJE
+      IWORK(14) = NQU
+      IWORK(15) = NQ
+      RETURN
+C-----------------------------------------------------------------------
+C Block I.
+C The following block handles all error returns due to illegal input
+C (ISTATE = -3), as detected before calling the core integrator.
+C First the error message routine is called.  If the illegal input 
+C is a negative ISTATE, the run is aborted (apparent infinite loop).
+C-----------------------------------------------------------------------
+ 601  MSG = 'DLSODE-  ISTATE (=I1) illegal '
+      CALL XERRWD (MSG, 30, 1, 0, 1, ISTATE, 0, 0, 0.0D0, 0.0D0)
+      IF (ISTATE .LT. 0) GO TO 800
       GO TO 700
- 610  CALL XERRWD('LSODE--  MU (=I1) ILLEGAL.. .LT.0 OR .GE.NEQ (=I2)',
-     1   50, 10, 0, 2, MU, NEQ(1), 0, 0.0D0, 0.0D0)
+ 602  MSG = 'DLSODE-  ITASK (=I1) illegal  '
+      CALL XERRWD (MSG, 30, 2, 0, 1, ITASK, 0, 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 603  MSG = 'DLSODE-  ISTATE .GT. 1 but DLSODE not initialized '
+      CALL XERRWD (MSG, 50, 3, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 611  CALL XERRWD('LSODE--  MAXORD (=I1) .LT. 0  ',
-     1   30, 11, 0, 1, MAXORD, 0, 0, 0.0D0, 0.0D0)
+ 604  MSG = 'DLSODE-  NEQ (=I1) .LT. 1     '
+      CALL XERRWD (MSG, 30, 4, 0, 1, NEQ(1), 0, 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 605  MSG = 'DLSODE-  ISTATE = 3 and NEQ increased (I1 to I2)  '
+      CALL XERRWD (MSG, 50, 5, 0, 2, N, NEQ(1), 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 606  MSG = 'DLSODE-  ITOL (=I1) illegal   '
+      CALL XERRWD (MSG, 30, 6, 0, 1, ITOL, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 612  CALL XERRWD('LSODE--  MXSTEP (=I1) .LT. 0  ',
-     1   30, 12, 0, 1, MXSTEP, 0, 0, 0.0D0, 0.0D0)
+ 607  MSG = 'DLSODE-  IOPT (=I1) illegal   '
+      CALL XERRWD (MSG, 30, 7, 0, 1, IOPT, 0, 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 608  MSG = 'DLSODE-  MF (=I1) illegal     '
+      CALL XERRWD (MSG, 30, 8, 0, 1, MF, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 613  CALL XERRWD('LSODE--  MXHNIL (=I1) .LT. 0  ',
-     1   30, 13, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
+ 609  MSG = 'DLSODE-  ML (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)'
+      CALL XERRWD (MSG, 50, 9, 0, 2, ML, NEQ(1), 0, 0.0D0, 0.0D0)
       GO TO 700
- 614  CALL XERRWD('LSODE--  TOUT (=R1) BEHIND T (=R2)      ',
-     1   40, 14, 0, 0, 0, 0, 2, TOUT, T)
-      CALL XERRWD('      INTEGRATION DIRECTION IS GIVEN BY H0 (=R1)  ',
-     1   50, 14, 0, 0, 0, 0, 1, H0, 0.0D0)
+ 610  MSG = 'DLSODE-  MU (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)'
+      CALL XERRWD (MSG, 50, 10, 0, 2, MU, NEQ(1), 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 611  MSG = 'DLSODE-  MAXORD (=I1) .LT. 0  '
+      CALL XERRWD (MSG, 30, 11, 0, 1, MAXORD, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 615  CALL XERRWD('LSODE--  HMAX (=R1) .LT. 0.0  ',
-     1   30, 15, 0, 0, 0, 0, 1, HMAX, 0.0D0)
+ 612  MSG = 'DLSODE-  MXSTEP (=I1) .LT. 0  '
+      CALL XERRWD (MSG, 30, 12, 0, 1, MXSTEP, 0, 0, 0.0D0, 0.0D0)
+      GO TO 700
+ 613  MSG = 'DLSODE-  MXHNIL (=I1) .LT. 0  '
+      CALL XERRWD (MSG, 30, 13, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
       GO TO 700
- 616  CALL XERRWD('LSODE--  HMIN (=R1) .LT. 0.0  ',
-     1   30, 16, 0, 0, 0, 0, 1, HMIN, 0.0D0)
+ 614  MSG = 'DLSODE-  TOUT (=R1) behind T (=R2)      '
+      CALL XERRWD (MSG, 40, 14, 0, 0, 0, 0, 2, TOUT, T)
+      MSG = '      Integration direction is given by H0 (=R1)  '
+      CALL XERRWD (MSG, 50, 14, 0, 0, 0, 0, 1, H0, 0.0D0)
       GO TO 700
- 617  CALL XERRWD(
-     1  'LSODE--  RWORK LENGTH NEEDED, LENRW (=I1), EXCEEDS LRW (=I2)',
-     1   60, 17, 0, 2, LENRW, LRW, 0, 0.0D0, 0.0D0)
+ 615  MSG = 'DLSODE-  HMAX (=R1) .LT. 0.0  '
+      CALL XERRWD (MSG, 30, 15, 0, 0, 0, 0, 1, HMAX, 0.0D0)
       GO TO 700
- 618  CALL XERRWD(
-     1  'LSODE--  IWORK LENGTH NEEDED, LENIW (=I1), EXCEEDS LIW (=I2)',
-     1   60, 18, 0, 2, LENIW, LIW, 0, 0.0D0, 0.0D0)
+ 616  MSG = 'DLSODE-  HMIN (=R1) .LT. 0.0  '
+      CALL XERRWD (MSG, 30, 16, 0, 0, 0, 0, 1, HMIN, 0.0D0)
+      GO TO 700
+ 617  CONTINUE
+      MSG='DLSODE-  RWORK length needed, LENRW (=I1), exceeds LRW (=I2)'
+      CALL XERRWD (MSG, 60, 17, 0, 2, LENRW, LRW, 0, 0.0D0, 0.0D0)
       GO TO 700
- 619  CALL XERRWD('LSODE--  RTOL(I1) IS R1 .LT. 0.0        ',
-     1   40, 19, 0, 1, I, 0, 1, RTOLI, 0.0D0)
+ 618  CONTINUE
+      MSG='DLSODE-  IWORK length needed, LENIW (=I1), exceeds LIW (=I2)'
+      CALL XERRWD (MSG, 60, 18, 0, 2, LENIW, LIW, 0, 0.0D0, 0.0D0)
       GO TO 700
- 620  CALL XERRWD('LSODE--  ATOL(I1) IS R1 .LT. 0.0        ',
-     1   40, 20, 0, 1, I, 0, 1, ATOLI, 0.0D0)
+ 619  MSG = 'DLSODE-  RTOL(I1) is R1 .LT. 0.0        '
+      CALL XERRWD (MSG, 40, 19, 0, 1, I, 0, 1, RTOLI, 0.0D0)
+      GO TO 700
+ 620  MSG = 'DLSODE-  ATOL(I1) is R1 .LT. 0.0        '
+      CALL XERRWD (MSG, 40, 20, 0, 1, I, 0, 1, ATOLI, 0.0D0)
       GO TO 700
  621  EWTI = RWORK(LEWT+I-1)
-      CALL XERRWD('LSODE--  EWT(I1) IS R1 .LE. 0.0         ',
-     1   40, 21, 0, 1, I, 0, 1, EWTI, 0.0D0)
+      MSG = 'DLSODE-  EWT(I1) is R1 .LE. 0.0         '
+      CALL XERRWD (MSG, 40, 21, 0, 1, I, 0, 1, EWTI, 0.0D0)
       GO TO 700
- 622  CALL XERRWD(
-     1  'LSODE--  TOUT (=R1) TOO CLOSE TO T(=R2) TO START INTEGRATION',
-     1   60, 22, 0, 0, 0, 0, 2, TOUT, T)
+ 622  CONTINUE
+      MSG='DLSODE-  TOUT (=R1) too close to T(=R2) to start integration'
+      CALL XERRWD (MSG, 60, 22, 0, 0, 0, 0, 2, TOUT, T)
       GO TO 700
- 623  CALL XERRWD(
-     1  'LSODE--  ITASK = I1 AND TOUT (=R1) BEHIND TCUR - HU (= R2)  ',
-     1   60, 23, 0, 1, ITASK, 0, 2, TOUT, TP)
+ 623  CONTINUE
+      MSG='DLSODE-  ITASK = I1 and TOUT (=R1) behind TCUR - HU (= R2)  '
+      CALL XERRWD (MSG, 60, 23, 0, 1, ITASK, 0, 2, TOUT, TP)
       GO TO 700
- 624  CALL XERRWD(
-     1  'LSODE--  ITASK = 4 OR 5 AND TCRIT (=R1) BEHIND TCUR (=R2)   ',
-     1   60, 24, 0, 0, 0, 0, 2, TCRIT, TN)
+ 624  CONTINUE
+      MSG='DLSODE-  ITASK = 4 OR 5 and TCRIT (=R1) behind TCUR (=R2)   '
+      CALL XERRWD (MSG, 60, 24, 0, 0, 0, 0, 2, TCRIT, TN)
       GO TO 700
- 625  CALL XERRWD(
-     1  'LSODE--  ITASK = 4 OR 5 AND TCRIT (=R1) BEHIND TOUT (=R2)   ',
-     1   60, 25, 0, 0, 0, 0, 2, TCRIT, TOUT)
+ 625  CONTINUE
+      MSG='DLSODE-  ITASK = 4 or 5 and TCRIT (=R1) behind TOUT (=R2)   '
+      CALL XERRWD (MSG, 60, 25, 0, 0, 0, 0, 2, TCRIT, TOUT)
       GO TO 700
- 626  CALL XERRWD('LSODE--  AT START OF PROBLEM, TOO MUCH ACCURACY   ',
-     1   50, 26, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD(
-     1  '      REQUESTED FOR PRECISION OF MACHINE..  SEE TOLSF (=R1) ',
-     1   60, 26, 0, 0, 0, 0, 1, TOLSF, 0.0D0)
+ 626  MSG = 'DLSODE-  At start of problem, too much accuracy   '
+      CALL XERRWD (MSG, 50, 26, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+      MSG='      requested for precision of machine..  See TOLSF (=R1) '
+      CALL XERRWD (MSG, 60, 26, 0, 0, 0, 0, 1, TOLSF, 0.0D0)
       RWORK(14) = TOLSF
       GO TO 700
- 627  CALL XERRWD('LSODE--  TROUBLE FROM INTDY. ITASK = I1, TOUT = R1',
-     1   50, 27, 0, 1, ITASK, 0, 1, TOUT, 0.0D0)
+ 627  MSG = 'DLSODE-  Trouble in DINTDY.  ITASK = I1, TOUT = R1'
+      CALL XERRWD (MSG, 50, 27, 0, 1, ITASK, 0, 1, TOUT, 0.0D0)
 C
- 700  IF (ILLIN .EQ. 5) GO TO 710
-      ILLIN = ILLIN + 1
-      ISTATE = -3
+ 700  ISTATE = -3
       RETURN
- 710  CALL XERRWD('LSODE--  REPEATED OCCURRENCES OF ILLEGAL INPUT    ',
-     1   50, 302, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
 C
- 800  CALL XERRWD('LSODE--  RUN ABORTED.. APPARENT INFINITE LOOP     ',
-     1   50, 303, 2, 0, 0, 0, 0, 0.0D0, 0.0D0)
+ 800  MSG = 'DLSODE-  Run aborted.. apparent infinite loop     '
+      CALL XERRWD (MSG, 50, 303, 2, 0, 0, 0, 0, 0.0D0, 0.0D0)
       RETURN
-C----------------------- END OF SUBROUTINE LSODE -----------------------
+C----------------------- END OF SUBROUTINE DLSODE ----------------------
       END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dprepj.f	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,196 @@
+      SUBROUTINE DPREPJ (NEQ, Y, YH, NYH, EWT, FTEM, SAVF, WM, IWM,
+     1   F, JAC)
+C***BEGIN PROLOGUE  DPREPJ
+C***SUBSIDIARY
+C***PURPOSE  Compute and process Newton iteration matrix.
+C***TYPE      DOUBLE PRECISION (SPREPJ-S, DPREPJ-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  DPREPJ is called by DSTODE to compute and process the matrix
+C  P = I - h*el(1)*J , where J is an approximation to the Jacobian.
+C  Here J is computed by the user-supplied routine JAC if
+C  MITER = 1 or 4, or by finite differencing if MITER = 2, 3, or 5.
+C  If MITER = 3, a diagonal approximation to J is used.
+C  J is stored in WM and replaced by P.  If MITER .ne. 3, P is then
+C  subjected to LU decomposition in preparation for later solution
+C  of linear systems with P as coefficient matrix.  This is done
+C  by DGETRF if MITER = 1 or 2, and by DGBTRF if MITER = 4 or 5.
+C
+C  In addition to variables described in DSTODE and DLSODE prologues,
+C  communication with DPREPJ uses the following:
+C  Y     = array containing predicted values on entry.
+C  FTEM  = work array of length N (ACOR in DSTODE).
+C  SAVF  = array containing f evaluated at predicted y.
+C  WM    = real work space for matrices.  On output it contains the
+C          inverse diagonal matrix if MITER = 3 and the LU decomposition
+C          of P if MITER is 1, 2 , 4, or 5.
+C          Storage of matrix elements starts at WM(3).
+C          WM also contains the following matrix-related data:
+C          WM(1) = SQRT(UROUND), used in numerical Jacobian increments.
+C          WM(2) = H*EL0, saved for later use if MITER = 3.
+C  IWM   = integer work space containing pivot information, starting at
+C          IWM(21), if MITER is 1, 2, 4, or 5.  IWM also contains band
+C          parameters ML = IWM(1) and MU = IWM(2) if MITER is 4 or 5.
+C  EL0   = EL(1) (input).
+C  IERPJ = output error flag,  = 0 if no trouble, .gt. 0 if
+C          P matrix found to be singular.
+C  JCUR  = output flag = 1 to indicate that the Jacobian matrix
+C          (or approximation) is now current.
+C  This routine also uses the COMMON variables EL0, H, TN, UROUND,
+C  MITER, N, NFE, and NJE.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  DGBTRF, DGETRF, DVNORM
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890504  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C   010418  Reduced size of Common block /DLS001/. (ACH)
+C   031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C***END PROLOGUE  DPREPJ
+C**End
+      EXTERNAL F, JAC
+      INTEGER NEQ, NYH, IWM
+      DOUBLE PRECISION Y, YH, EWT, FTEM, SAVF, WM
+      DIMENSION NEQ(*), Y(*), YH(NYH,*), EWT(*), FTEM(*), SAVF(*),
+     1   WM(*), IWM(*)
+      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
+      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
+     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
+     1   HOLD, RMAX, TESCO(3,12),
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
+     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
+     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER I, I1, I2, IER, II, J, J1, JJ, LENP,
+     1   MBA, MBAND, MEB1, MEBAND, ML, ML3, MU, NP1
+      DOUBLE PRECISION CON, DI, FAC, HL0, R, R0, SRUR, YI, YJ, YJJ,
+     1   DVNORM
+C
+C***FIRST EXECUTABLE STATEMENT  DPREPJ
+      NJE = NJE + 1
+      IERPJ = 0
+      JCUR = 1
+      HL0 = H*EL0
+      GO TO (100, 200, 300, 400, 500), MITER
+C If MITER = 1, call JAC and multiply by scalar. -----------------------
+ 100  LENP = N*N
+      DO 110 I = 1,LENP
+ 110    WM(I+2) = 0.0D0
+      CALL JAC (NEQ, TN, Y, 0, 0, WM(3), N)
+      CON = -HL0
+      DO 120 I = 1,LENP
+ 120    WM(I+2) = WM(I+2)*CON
+      GO TO 240
+C If MITER = 2, make N calls to F to approximate J. --------------------
+ 200  FAC = DVNORM (N, SAVF, EWT)
+      R0 = 1000.0D0*ABS(H)*UROUND*N*FAC
+      IF (R0 .EQ. 0.0D0) R0 = 1.0D0
+      SRUR = WM(1)
+      J1 = 2
+      DO 230 J = 1,N
+        YJ = Y(J)
+        R = MAX(SRUR*ABS(YJ),R0/EWT(J))
+        Y(J) = Y(J) + R
+        FAC = -HL0/R
+        CALL F (NEQ, TN, Y, FTEM)
+        DO 220 I = 1,N
+ 220      WM(I+J1) = (FTEM(I) - SAVF(I))*FAC
+        Y(J) = YJ
+        J1 = J1 + N
+ 230    CONTINUE
+      NFE = NFE + N
+C Add identity matrix. -------------------------------------------------
+ 240  J = 3
+      NP1 = N + 1
+      DO 250 I = 1,N
+        WM(J) = WM(J) + 1.0D0
+ 250    J = J + NP1
+C Do LU decomposition on P. --------------------------------------------
+      CALL DGETRF ( N, N, WM(3), N, IWM(21), IER)
+      IF (IER .NE. 0) IERPJ = 1
+      RETURN
+C If MITER = 3, construct a diagonal approximation to J and P. ---------
+ 300  WM(2) = HL0
+      R = EL0*0.1D0
+      DO 310 I = 1,N
+ 310    Y(I) = Y(I) + R*(H*SAVF(I) - YH(I,2))
+      CALL F (NEQ, TN, Y, WM(3))
+      NFE = NFE + 1
+      DO 320 I = 1,N
+        R0 = H*SAVF(I) - YH(I,2)
+        DI = 0.1D0*R0 - H*(WM(I+2) - SAVF(I))
+        WM(I+2) = 1.0D0
+        IF (ABS(R0) .LT. UROUND/EWT(I)) GO TO 320
+        IF (ABS(DI) .EQ. 0.0D0) GO TO 330
+        WM(I+2) = 0.1D0*R0/DI
+ 320    CONTINUE
+      RETURN
+ 330  IERPJ = 1
+      RETURN
+C If MITER = 4, call JAC and multiply by scalar. -----------------------
+ 400  ML = IWM(1)
+      MU = IWM(2)
+      ML3 = ML + 3
+      MBAND = ML + MU + 1
+      MEBAND = MBAND + ML
+      LENP = MEBAND*N
+      DO 410 I = 1,LENP
+ 410    WM(I+2) = 0.0D0
+      CALL JAC (NEQ, TN, Y, ML, MU, WM(ML3), MEBAND)
+      CON = -HL0
+      DO 420 I = 1,LENP
+ 420    WM(I+2) = WM(I+2)*CON
+      GO TO 570
+C If MITER = 5, make MBAND calls to F to approximate J. ----------------
+ 500  ML = IWM(1)
+      MU = IWM(2)
+      MBAND = ML + MU + 1
+      MBA = MIN(MBAND,N)
+      MEBAND = MBAND + ML
+      MEB1 = MEBAND - 1
+      SRUR = WM(1)
+      FAC = DVNORM (N, SAVF, EWT)
+      R0 = 1000.0D0*ABS(H)*UROUND*N*FAC
+      IF (R0 .EQ. 0.0D0) R0 = 1.0D0
+      DO 560 J = 1,MBA
+        DO 530 I = J,N,MBAND
+          YI = Y(I)
+          R = MAX(SRUR*ABS(YI),R0/EWT(I))
+ 530      Y(I) = Y(I) + R
+        CALL F (NEQ, TN, Y, FTEM)
+        DO 550 JJ = J,N,MBAND
+          Y(JJ) = YH(JJ,1)
+          YJJ = Y(JJ)
+          R = MAX(SRUR*ABS(YJJ),R0/EWT(JJ))
+          FAC = -HL0/R
+          I1 = MAX(JJ-MU,1)
+          I2 = MIN(JJ+ML,N)
+          II = JJ*MEB1 - ML + 2
+          DO 540 I = I1,I2
+ 540        WM(II+I) = (FTEM(I) - SAVF(I))*FAC
+ 550      CONTINUE
+ 560    CONTINUE
+      NFE = NFE + MBA
+C Add identity matrix. -------------------------------------------------
+ 570  II = MBAND + 2
+      DO 580 I = 1,N
+        WM(II) = WM(II) + 1.0D0
+ 580    II = II + MEBAND
+C Do LU decomposition of P. --------------------------------------------
+      CALL DGBTRF ( N, N, ML, MU, WM(3), MEBAND, IWM(21), IER)
+      IF (IER .NE. 0) IERPJ = 1
+      RETURN
+C----------------------- END OF SUBROUTINE DPREPJ ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dsolsy.f	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,95 @@
+      SUBROUTINE DSOLSY (WM, IWM, X, TEM)
+C***BEGIN PROLOGUE  DSOLSY
+C***SUBSIDIARY
+C***PURPOSE  ODEPACK linear system solver.
+C***TYPE      DOUBLE PRECISION (SSOLSY-S, DSOLSY-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  This routine manages the solution of the linear system arising from
+C  a chord iteration.  It is called if MITER .ne. 0.
+C  If MITER is 1 or 2, it calls DGETRS to accomplish this.
+C  If MITER = 3 it updates the coefficient h*EL0 in the diagonal
+C  matrix, and then computes the solution.
+C  If MITER is 4 or 5, it calls DGBTRS.
+C  Communication with DSOLSY uses the following variables:
+C  WM    = real work space containing the inverse diagonal matrix if
+C          MITER = 3 and the LU decomposition of the matrix otherwise.
+C          Storage of matrix elements starts at WM(3).
+C          WM also contains the following matrix-related data:
+C          WM(1) = SQRT(UROUND) (not used here),
+C          WM(2) = HL0, the previous value of h*EL0, used if MITER = 3.
+C  IWM   = integer work space containing pivot information, starting at
+C          IWM(21), if MITER is 1, 2, 4, or 5.  IWM also contains band
+C          parameters ML = IWM(1) and MU = IWM(2) if MITER is 4 or 5.
+C  X     = the right-hand side vector on input, and the solution vector
+C          on output, of length N.
+C  TEM   = vector of work space of length N, not used in this version.
+C  IERSL = output flag (in COMMON).  IERSL = 0 if no trouble occurred.
+C          IERSL = 1 if a singular matrix arose with MITER = 3.
+C  This routine also uses the COMMON variables EL0, H, MITER, and N.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  DGBTRS, DGETRS
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C   010418  Reduced size of Common block /DLS001/. (ACH)
+C   031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C***END PROLOGUE  DSOLSY
+C**End
+      INTEGER IWM
+      DOUBLE PRECISION WM, X, TEM
+      DIMENSION WM(*), IWM(*), X(*), TEM(*)
+      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
+     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
+      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
+     1   HOLD, RMAX, TESCO(3,12),
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
+     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
+     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
+     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER I, MEBAND, ML, MU
+      INTEGER INLPCK
+      DOUBLE PRECISION DI, HL0, PHL0, R
+C
+C***FIRST EXECUTABLE STATEMENT  DSOLSY
+      IERSL = 0
+      GO TO (100, 100, 300, 400, 400), MITER
+ 100  CALL DGETRS ( 'N', N, 1, WM(3), N, IWM(21), X, N, INLPCK)
+      RETURN
+C
+ 300  PHL0 = WM(2)
+      HL0 = H*EL0
+      WM(2) = HL0
+      IF (HL0 .EQ. PHL0) GO TO 330
+      R = HL0/PHL0
+      DO 320 I = 1,N
+        DI = 1.0D0 - R*(1.0D0 - 1.0D0/WM(I+2))
+        IF (ABS(DI) .EQ. 0.0D0) GO TO 390
+ 320    WM(I+2) = 1.0D0/DI
+ 330  DO 340 I = 1,N
+ 340    X(I) = WM(I+2)*X(I)
+      RETURN
+ 390  IERSL = 1
+      RETURN
+C
+ 400  ML = IWM(1)
+      MU = IWM(2)
+      MEBAND = 2*ML + MU + 1
+      CALL DGBTRS ( 'N', N, ML, MU, 1, WM(3), MEBAND, IWM(21), X, N,
+     * INLPCK)
+      RETURN
+C----------------------- END OF SUBROUTINE DSOLSY ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dstode.f	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,499 @@
+      SUBROUTINE DSTODE (NEQ, Y, YH, NYH, YH1, EWT, SAVF, ACOR,
+     1   WM, IWM, F, JAC, PJAC, SLVS)
+C***BEGIN PROLOGUE  DSTODE
+C***SUBSIDIARY
+C***PURPOSE  Performs one step of an ODEPACK integration.
+C***TYPE      DOUBLE PRECISION (SSTODE-S, DSTODE-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  DSTODE performs one step of the integration of an initial value
+C  problem for a system of ordinary differential equations.
+C  Note:  DSTODE is independent of the value of the iteration method
+C  indicator MITER, when this is .ne. 0, and hence is independent
+C  of the type of chord method used, or the Jacobian structure.
+C  Communication with DSTODE is done with the following variables:
+C
+C  NEQ    = integer array containing problem size in NEQ(1), and
+C           passed as the NEQ argument in all calls to F and JAC.
+C  Y      = an array of length .ge. N used as the Y argument in
+C           all calls to F and JAC.
+C  YH     = an NYH by LMAX array containing the dependent variables
+C           and their approximate scaled derivatives, where
+C           LMAX = MAXORD + 1.  YH(i,j+1) contains the approximate
+C           j-th derivative of y(i), scaled by h**j/factorial(j)
+C           (j = 0,1,...,NQ).  on entry for the first step, the first
+C           two columns of YH must be set from the initial values.
+C  NYH    = a constant integer .ge. N, the first dimension of YH.
+C  YH1    = a one-dimensional array occupying the same space as YH.
+C  EWT    = an array of length N containing multiplicative weights
+C           for local error measurements.  Local errors in Y(i) are
+C           compared to 1.0/EWT(i) in various error tests.
+C  SAVF   = an array of working storage, of length N.
+C           Also used for input of YH(*,MAXORD+2) when JSTART = -1
+C           and MAXORD .lt. the current order NQ.
+C  ACOR   = a work array of length N, used for the accumulated
+C           corrections.  On a successful return, ACOR(i) contains
+C           the estimated one-step local error in Y(i).
+C  WM,IWM = real and integer work arrays associated with matrix
+C           operations in chord iteration (MITER .ne. 0).
+C  PJAC   = name of routine to evaluate and preprocess Jacobian matrix
+C           and P = I - h*el0*JAC, if a chord method is being used.
+C  SLVS   = name of routine to solve linear system in chord iteration.
+C  CCMAX  = maximum relative change in h*el0 before PJAC is called.
+C  H      = the step size to be attempted on the next step.
+C           H is altered by the error control algorithm during the
+C           problem.  H can be either positive or negative, but its
+C           sign must remain constant throughout the problem.
+C  HMIN   = the minimum absolute value of the step size h to be used.
+C  HMXI   = inverse of the maximum absolute value of h to be used.
+C           HMXI = 0.0 is allowed and corresponds to an infinite hmax.
+C           HMIN and HMXI may be changed at any time, but will not
+C           take effect until the next change of h is considered.
+C  TN     = the independent variable. TN is updated on each step taken.
+C  JSTART = an integer used for input only, with the following
+C           values and meanings:
+C                0  perform the first step.
+C            .gt.0  take a new step continuing from the last.
+C               -1  take the next step with a new value of H, MAXORD,
+C                     N, METH, MITER, and/or matrix parameters.
+C               -2  take the next step with a new value of H,
+C                     but with other inputs unchanged.
+C           On return, JSTART is set to 1 to facilitate continuation.
+C  KFLAG  = a completion code with the following meanings:
+C                0  the step was succesful.
+C               -1  the requested error could not be achieved.
+C               -2  corrector convergence could not be achieved.
+C               -3  fatal error in PJAC or SLVS.
+C           A return with KFLAG = -1 or -2 means either
+C           abs(H) = HMIN or 10 consecutive failures occurred.
+C           On a return with KFLAG negative, the values of TN and
+C           the YH array are as of the beginning of the last
+C           step, and H is the last step size attempted.
+C  MAXORD = the maximum order of integration method to be allowed.
+C  MAXCOR = the maximum number of corrector iterations allowed.
+C  MSBP   = maximum number of steps between PJAC calls (MITER .gt. 0).
+C  MXNCF  = maximum number of convergence failures allowed.
+C  METH/MITER = the method flags.  See description in driver.
+C  N      = the number of first-order differential equations.
+C  The values of CCMAX, H, HMIN, HMXI, TN, JSTART, KFLAG, MAXORD,
+C  MAXCOR, MSBP, MXNCF, METH, MITER, and N are communicated via COMMON.
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  DCFODE, DVNORM
+C***COMMON BLOCKS    DLS001
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C   010418  Reduced size of Common block /DLS001/. (ACH)
+C   031105  Restored 'own' variables to Common block /DLS001/, to
+C           enable interrupt/restart feature. (ACH)
+C***END PROLOGUE  DSTODE
+C**End
+      EXTERNAL F, JAC, PJAC, SLVS
+      INTEGER NEQ, NYH, IWM
+      DOUBLE PRECISION Y, YH, YH1, EWT, SAVF, ACOR, WM
+      DIMENSION NEQ(*), Y(*), YH(NYH,*), YH1(*), EWT(*), SAVF(*),
+     1   ACOR(*), WM(*), IWM(*)
+      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
+      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     1   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+      INTEGER I, I1, IREDO, IRET, J, JB, M, NCF, NEWQ
+      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
+      DOUBLE PRECISION DCON, DDN, DEL, DELP, DSM, DUP, EXDN, EXSM, EXUP,
+     1   R, RH, RHDN, RHSM, RHUP, TOLD, DVNORM
+      COMMON /DLS001/ CONIT, CRATE, EL(13), ELCO(13,12),
+     1   HOLD, RMAX, TESCO(3,12),
+     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
+     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
+     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
+     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
+     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
+     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
+C
+C***FIRST EXECUTABLE STATEMENT  DSTODE
+      KFLAG = 0
+      TOLD = TN
+      NCF = 0
+      IERPJ = 0
+      IERSL = 0
+      JCUR = 0
+      ICF = 0
+      DELP = 0.0D0
+      IF (JSTART .GT. 0) GO TO 200
+      IF (JSTART .EQ. -1) GO TO 100
+      IF (JSTART .EQ. -2) GO TO 160
+C-----------------------------------------------------------------------
+C On the first call, the order is set to 1, and other variables are
+C initialized.  RMAX is the maximum ratio by which H can be increased
+C in a single step.  It is initially 1.E4 to compensate for the small
+C initial H, but then is normally equal to 10.  If a failure
+C occurs (in corrector convergence or error test), RMAX is set to 2
+C for the next increase.
+C-----------------------------------------------------------------------
+      LMAX = MAXORD + 1
+      NQ = 1
+      L = 2
+      IALTH = 2
+      RMAX = 10000.0D0
+      RC = 0.0D0
+      EL0 = 1.0D0
+      CRATE = 0.7D0
+      HOLD = H
+      MEO = METH
+      NSLP = 0
+      IPUP = MITER
+      IRET = 3
+      GO TO 140
+C-----------------------------------------------------------------------
+C The following block handles preliminaries needed when JSTART = -1.
+C IPUP is set to MITER to force a matrix update.
+C If an order increase is about to be considered (IALTH = 1),
+C IALTH is reset to 2 to postpone consideration one more step.
+C If the caller has changed METH, DCFODE is called to reset
+C the coefficients of the method.
+C If the caller has changed MAXORD to a value less than the current
+C order NQ, NQ is reduced to MAXORD, and a new H chosen accordingly.
+C If H is to be changed, YH must be rescaled.
+C If H or METH is being changed, IALTH is reset to L = NQ + 1
+C to prevent further changes in H for that many steps.
+C-----------------------------------------------------------------------
+ 100  IPUP = MITER
+      LMAX = MAXORD + 1
+      IF (IALTH .EQ. 1) IALTH = 2
+      IF (METH .EQ. MEO) GO TO 110
+      CALL DCFODE (METH, ELCO, TESCO)
+      MEO = METH
+      IF (NQ .GT. MAXORD) GO TO 120
+      IALTH = L
+      IRET = 1
+      GO TO 150
+ 110  IF (NQ .LE. MAXORD) GO TO 160
+ 120  NQ = MAXORD
+      L = LMAX
+      DO 125 I = 1,L
+ 125    EL(I) = ELCO(I,NQ)
+      NQNYH = NQ*NYH
+      RC = RC*EL(1)/EL0
+      EL0 = EL(1)
+      CONIT = 0.5D0/(NQ+2)
+      DDN = DVNORM (N, SAVF, EWT)/TESCO(1,L)
+      EXDN = 1.0D0/L
+      RHDN = 1.0D0/(1.3D0*DDN**EXDN + 0.0000013D0)
+      RH = MIN(RHDN,1.0D0)
+      IREDO = 3
+      IF (H .EQ. HOLD) GO TO 170
+      RH = MIN(RH,ABS(H/HOLD))
+      H = HOLD
+      GO TO 175
+C-----------------------------------------------------------------------
+C DCFODE is called to get all the integration coefficients for the
+C current METH.  Then the EL vector and related constants are reset
+C whenever the order NQ is changed, or at the start of the problem.
+C-----------------------------------------------------------------------
+ 140  CALL DCFODE (METH, ELCO, TESCO)
+ 150  DO 155 I = 1,L
+ 155    EL(I) = ELCO(I,NQ)
+      NQNYH = NQ*NYH
+      RC = RC*EL(1)/EL0
+      EL0 = EL(1)
+      CONIT = 0.5D0/(NQ+2)
+      GO TO (160, 170, 200), IRET
+C-----------------------------------------------------------------------
+C If H is being changed, the H ratio RH is checked against
+C RMAX, HMIN, and HMXI, and the YH array rescaled.  IALTH is set to
+C L = NQ + 1 to prevent a change of H for that many steps, unless
+C forced by a convergence or error test failure.
+C-----------------------------------------------------------------------
+ 160  IF (H .EQ. HOLD) GO TO 200
+      RH = H/HOLD
+      H = HOLD
+      IREDO = 3
+      GO TO 175
+ 170  RH = MAX(RH,HMIN/ABS(H))
+ 175  RH = MIN(RH,RMAX)
+      RH = RH/MAX(1.0D0,ABS(H)*HMXI*RH)
+      R = 1.0D0
+      DO 180 J = 2,L
+        R = R*RH
+        DO 180 I = 1,N
+ 180      YH(I,J) = YH(I,J)*R
+      H = H*RH
+      RC = RC*RH
+      IALTH = L
+      IF (IREDO .EQ. 0) GO TO 690
+C-----------------------------------------------------------------------
+C This section computes the predicted values by effectively
+C multiplying the YH array by the Pascal Triangle matrix.
+C RC is the ratio of new to old values of the coefficient  H*EL(1).
+C When RC differs from 1 by more than CCMAX, IPUP is set to MITER
+C to force PJAC to be called, if a Jacobian is involved.
+C In any case, PJAC is called at least every MSBP steps.
+C-----------------------------------------------------------------------
+ 200  IF (ABS(RC-1.0D0) .GT. CCMAX) IPUP = MITER
+      IF (NST .GE. NSLP+MSBP) IPUP = MITER
+      TN = TN + H
+      I1 = NQNYH + 1
+      DO 215 JB = 1,NQ
+        I1 = I1 - NYH
+Cdir$ ivdep
+        DO 210 I = I1,NQNYH
+ 210      YH1(I) = YH1(I) + YH1(I+NYH)
+ 215    CONTINUE
+C-----------------------------------------------------------------------
+C Up to MAXCOR corrector iterations are taken.  A convergence test is
+C made on the R.M.S. norm of each correction, weighted by the error
+C weight vector EWT.  The sum of the corrections is accumulated in the
+C vector ACOR(i).  The YH array is not altered in the corrector loop.
+C-----------------------------------------------------------------------
+ 220  M = 0
+      DO 230 I = 1,N
+ 230    Y(I) = YH(I,1)
+      CALL F (NEQ, TN, Y, SAVF)
+      NFE = NFE + 1
+      IF (IPUP .LE. 0) GO TO 250
+C-----------------------------------------------------------------------
+C If indicated, the matrix P = I - h*el(1)*J is reevaluated and
+C preprocessed before starting the corrector iteration.  IPUP is set
+C to 0 as an indicator that this has been done.
+C-----------------------------------------------------------------------
+      CALL PJAC (NEQ, Y, YH, NYH, EWT, ACOR, SAVF, WM, IWM, F, JAC)
+      IPUP = 0
+      RC = 1.0D0
+      NSLP = NST
+      CRATE = 0.7D0
+      IF (IERPJ .NE. 0) GO TO 430
+ 250  DO 260 I = 1,N
+ 260    ACOR(I) = 0.0D0
+ 270  IF (MITER .NE. 0) GO TO 350
+C-----------------------------------------------------------------------
+C In the case of functional iteration, update Y directly from
+C the result of the last function evaluation.
+C-----------------------------------------------------------------------
+      DO 290 I = 1,N
+        SAVF(I) = H*SAVF(I) - YH(I,2)
+ 290    Y(I) = SAVF(I) - ACOR(I)
+      DEL = DVNORM (N, Y, EWT)
+      DO 300 I = 1,N
+        Y(I) = YH(I,1) + EL(1)*SAVF(I)
+ 300    ACOR(I) = SAVF(I)
+      GO TO 400
+C-----------------------------------------------------------------------
+C In the case of the chord method, compute the corrector error,
+C and solve the linear system with that as right-hand side and
+C P as coefficient matrix.
+C-----------------------------------------------------------------------
+ 350  DO 360 I = 1,N
+ 360    Y(I) = H*SAVF(I) - (YH(I,2) + ACOR(I))
+      CALL SLVS (WM, IWM, Y, SAVF)
+      IF (IERSL .LT. 0) GO TO 430
+      IF (IERSL .GT. 0) GO TO 410
+      DEL = DVNORM (N, Y, EWT)
+      DO 380 I = 1,N
+        ACOR(I) = ACOR(I) + Y(I)
+ 380    Y(I) = YH(I,1) + EL(1)*ACOR(I)
+C-----------------------------------------------------------------------
+C Test for convergence.  If M.gt.0, an estimate of the convergence
+C rate constant is stored in CRATE, and this is used in the test.
+C-----------------------------------------------------------------------
+ 400  IF (M .NE. 0) CRATE = MAX(0.2D0*CRATE,DEL/DELP)
+      DCON = DEL*MIN(1.0D0,1.5D0*CRATE)/(TESCO(2,NQ)*CONIT)
+      IF (DCON .LE. 1.0D0) GO TO 450
+      M = M + 1
+      IF (M .EQ. MAXCOR) GO TO 410
+      IF (M .GE. 2 .AND. DEL .GT. 2.0D0*DELP) GO TO 410
+      DELP = DEL
+      CALL F (NEQ, TN, Y, SAVF)
+      NFE = NFE + 1
+      GO TO 270
+C-----------------------------------------------------------------------
+C The corrector iteration failed to converge.
+C If MITER .ne. 0 and the Jacobian is out of date, PJAC is called for
+C the next try.  Otherwise the YH array is retracted to its values
+C before prediction, and H is reduced, if possible.  If H cannot be
+C reduced or MXNCF failures have occurred, exit with KFLAG = -2.
+C-----------------------------------------------------------------------
+ 410  IF (MITER .EQ. 0 .OR. JCUR .EQ. 1) GO TO 430
+      ICF = 1
+      IPUP = MITER
+      GO TO 220
+ 430  ICF = 2
+      NCF = NCF + 1
+      RMAX = 2.0D0
+      TN = TOLD
+      I1 = NQNYH + 1
+      DO 445 JB = 1,NQ
+        I1 = I1 - NYH
+Cdir$ ivdep
+        DO 440 I = I1,NQNYH
+ 440      YH1(I) = YH1(I) - YH1(I+NYH)
+ 445    CONTINUE
+      IF (IERPJ .LT. 0 .OR. IERSL .LT. 0) GO TO 680
+      IF (ABS(H) .LE. HMIN*1.00001D0) GO TO 670
+      IF (NCF .EQ. MXNCF) GO TO 670
+      RH = 0.25D0
+      IPUP = MITER
+      IREDO = 1
+      GO TO 170
+C-----------------------------------------------------------------------
+C The corrector has converged.  JCUR is set to 0
+C to signal that the Jacobian involved may need updating later.
+C The local error test is made and control passes to statement 500
+C if it fails.
+C-----------------------------------------------------------------------
+ 450  JCUR = 0
+      IF (M .EQ. 0) DSM = DEL/TESCO(2,NQ)
+      IF (M .GT. 0) DSM = DVNORM (N, ACOR, EWT)/TESCO(2,NQ)
+      IF (DSM .GT. 1.0D0) GO TO 500
+C-----------------------------------------------------------------------
+C After a successful step, update the YH array.
+C Consider changing H if IALTH = 1.  Otherwise decrease IALTH by 1.
+C If IALTH is then 1 and NQ .lt. MAXORD, then ACOR is saved for
+C use in a possible order increase on the next step.
+C If a change in H is considered, an increase or decrease in order
+C by one is considered also.  A change in H is made only if it is by a
+C factor of at least 1.1.  If not, IALTH is set to 3 to prevent
+C testing for that many steps.
+C-----------------------------------------------------------------------
+      KFLAG = 0
+      IREDO = 0
+      NST = NST + 1
+      HU = H
+      NQU = NQ
+      DO 470 J = 1,L
+        DO 470 I = 1,N
+ 470      YH(I,J) = YH(I,J) + EL(J)*ACOR(I)
+      IALTH = IALTH - 1
+      IF (IALTH .EQ. 0) GO TO 520
+      IF (IALTH .GT. 1) GO TO 700
+      IF (L .EQ. LMAX) GO TO 700
+      DO 490 I = 1,N
+ 490    YH(I,LMAX) = ACOR(I)
+      GO TO 700
+C-----------------------------------------------------------------------
+C The error test failed.  KFLAG keeps track of multiple failures.
+C Restore TN and the YH array to their previous values, and prepare
+C to try the step again.  Compute the optimum step size for this or
+C one lower order.  After 2 or more failures, H is forced to decrease
+C by a factor of 0.2 or less.
+C-----------------------------------------------------------------------
+ 500  KFLAG = KFLAG - 1
+      TN = TOLD
+      I1 = NQNYH + 1
+      DO 515 JB = 1,NQ
+        I1 = I1 - NYH
+Cdir$ ivdep
+        DO 510 I = I1,NQNYH
+ 510      YH1(I) = YH1(I) - YH1(I+NYH)
+ 515    CONTINUE
+      RMAX = 2.0D0
+      IF (ABS(H) .LE. HMIN*1.00001D0) GO TO 660
+      IF (KFLAG .LE. -3) GO TO 640
+      IREDO = 2
+      RHUP = 0.0D0
+      GO TO 540
+C-----------------------------------------------------------------------
+C Regardless of the success or failure of the step, factors
+C RHDN, RHSM, and RHUP are computed, by which H could be multiplied
+C at order NQ - 1, order NQ, or order NQ + 1, respectively.
+C In the case of failure, RHUP = 0.0 to avoid an order increase.
+C The largest of these is determined and the new order chosen
+C accordingly.  If the order is to be increased, we compute one
+C additional scaled derivative.
+C-----------------------------------------------------------------------
+ 520  RHUP = 0.0D0
+      IF (L .EQ. LMAX) GO TO 540
+      DO 530 I = 1,N
+ 530    SAVF(I) = ACOR(I) - YH(I,LMAX)
+      DUP = DVNORM (N, SAVF, EWT)/TESCO(3,NQ)
+      EXUP = 1.0D0/(L+1)
+      RHUP = 1.0D0/(1.4D0*DUP**EXUP + 0.0000014D0)
+ 540  EXSM = 1.0D0/L
+      RHSM = 1.0D0/(1.2D0*DSM**EXSM + 0.0000012D0)
+      RHDN = 0.0D0
+      IF (NQ .EQ. 1) GO TO 560
+      DDN = DVNORM (N, YH(1,L), EWT)/TESCO(1,NQ)
+      EXDN = 1.0D0/NQ
+      RHDN = 1.0D0/(1.3D0*DDN**EXDN + 0.0000013D0)
+ 560  IF (RHSM .GE. RHUP) GO TO 570
+      IF (RHUP .GT. RHDN) GO TO 590
+      GO TO 580
+ 570  IF (RHSM .LT. RHDN) GO TO 580
+      NEWQ = NQ
+      RH = RHSM
+      GO TO 620
+ 580  NEWQ = NQ - 1
+      RH = RHDN
+      IF (KFLAG .LT. 0 .AND. RH .GT. 1.0D0) RH = 1.0D0
+      GO TO 620
+ 590  NEWQ = L
+      RH = RHUP
+      IF (RH .LT. 1.1D0) GO TO 610
+      R = EL(L)/L
+      DO 600 I = 1,N
+ 600    YH(I,NEWQ+1) = ACOR(I)*R
+      GO TO 630
+ 610  IALTH = 3
+      GO TO 700
+ 620  IF ((KFLAG .EQ. 0) .AND. (RH .LT. 1.1D0)) GO TO 610
+      IF (KFLAG .LE. -2) RH = MIN(RH,0.2D0)
+C-----------------------------------------------------------------------
+C If there is a change of order, reset NQ, l, and the coefficients.
+C In any case H is reset according to RH and the YH array is rescaled.
+C Then exit from 690 if the step was OK, or redo the step otherwise.
+C-----------------------------------------------------------------------
+      IF (NEWQ .EQ. NQ) GO TO 170
+ 630  NQ = NEWQ
+      L = NQ + 1
+      IRET = 2
+      GO TO 150
+C-----------------------------------------------------------------------
+C Control reaches this section if 3 or more failures have occured.
+C If 10 failures have occurred, exit with KFLAG = -1.
+C It is assumed that the derivatives that have accumulated in the
+C YH array have errors of the wrong order.  Hence the first
+C derivative is recomputed, and the order is set to 1.  Then
+C H is reduced by a factor of 10, and the step is retried,
+C until it succeeds or H reaches HMIN.
+C-----------------------------------------------------------------------
+ 640  IF (KFLAG .EQ. -10) GO TO 660
+      RH = 0.1D0
+      RH = MAX(HMIN/ABS(H),RH)
+      H = H*RH
+      DO 645 I = 1,N
+ 645    Y(I) = YH(I,1)
+      CALL F (NEQ, TN, Y, SAVF)
+      NFE = NFE + 1
+      DO 650 I = 1,N
+ 650    YH(I,2) = H*SAVF(I)
+      IPUP = MITER
+      IALTH = 5
+      IF (NQ .EQ. 1) GO TO 200
+      NQ = 1
+      L = 2
+      IRET = 3
+      GO TO 150
+C-----------------------------------------------------------------------
+C All returns are made through this section.  H is saved in HOLD
+C to allow the caller to change H on the next step.
+C-----------------------------------------------------------------------
+ 660  KFLAG = -1
+      GO TO 720
+ 670  KFLAG = -2
+      GO TO 720
+ 680  KFLAG = -3
+      GO TO 720
+ 690  RMAX = 10.0D0
+ 700  R = 1.0D0/TESCO(2,NQU)
+      DO 710 I = 1,N
+ 710    ACOR(I) = ACOR(I)*R
+ 720  HOLD = H
+      JSTART = 1
+      RETURN
+C----------------------- END OF SUBROUTINE DSTODE ----------------------
+      END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/odepack/dvnorm.f	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,34 @@
+      DOUBLE PRECISION FUNCTION DVNORM (N, V, W)
+C***BEGIN PROLOGUE  DVNORM
+C***SUBSIDIARY
+C***PURPOSE  Weighted root-mean-square vector norm.
+C***TYPE      DOUBLE PRECISION (SVNORM-S, DVNORM-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  This function routine computes the weighted root-mean-square norm
+C  of the vector of length N contained in the array V, with weights
+C  contained in the array W of length N:
+C    DVNORM = SQRT( (1/N) * SUM( V(i)*W(i) )**2 )
+C
+C***SEE ALSO  DLSODE
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890501  Modified prologue to SLATEC/LDOC format.  (FNF)
+C   890503  Minor cosmetic changes.  (FNF)
+C   930809  Renamed to allow single/double precision versions. (ACH)
+C***END PROLOGUE  DVNORM
+C**End
+      INTEGER N,   I
+      DOUBLE PRECISION V, W,   SUM
+      DIMENSION V(N), W(N)
+C
+C***FIRST EXECUTABLE STATEMENT  DVNORM
+      SUM = 0.0D0
+      DO 10 I = 1,N
+ 10     SUM = SUM + (V(I)*W(I))**2
+      DVNORM = SQRT(SUM/N)
+      RETURN
+C----------------------- END OF FUNCTION DVNORM ------------------------
+      END
--- a/liboctave/external/odepack/ewset.f	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-      SUBROUTINE EWSET (N, ITOL, RTOL, ATOL, YCUR, EWT)
-CLLL. OPTIMIZE
-C-----------------------------------------------------------------------
-C THIS SUBROUTINE SETS THE ERROR WEIGHT VECTOR EWT ACCORDING TO
-C     EWT(I) = RTOL(I)*ABS(YCUR(I)) + ATOL(I),  I = 1,...,N,
-C WITH THE SUBSCRIPT ON RTOL AND/OR ATOL POSSIBLY REPLACED BY 1 ABOVE,
-C DEPENDING ON THE VALUE OF ITOL.
-C-----------------------------------------------------------------------
-      INTEGER N, ITOL
-      INTEGER I
-      DOUBLE PRECISION RTOL, ATOL, YCUR, EWT
-      DIMENSION RTOL(*), ATOL(*), YCUR(N), EWT(N)
-C
-      GO TO (10, 20, 30, 40), ITOL
- 10   CONTINUE
-      DO 15 I = 1,N
- 15     EWT(I) = RTOL(1)*DABS(YCUR(I)) + ATOL(1)
-      RETURN
- 20   CONTINUE
-      DO 25 I = 1,N
- 25     EWT(I) = RTOL(1)*DABS(YCUR(I)) + ATOL(I)
-      RETURN
- 30   CONTINUE
-      DO 35 I = 1,N
- 35     EWT(I) = RTOL(I)*DABS(YCUR(I)) + ATOL(1)
-      RETURN
- 40   CONTINUE
-      DO 45 I = 1,N
- 45     EWT(I) = RTOL(I)*DABS(YCUR(I)) + ATOL(I)
-      RETURN
-C----------------------- END OF SUBROUTINE EWSET -----------------------
-      END
--- a/liboctave/external/odepack/intdy.f	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-      SUBROUTINE INTDY (T, K, YH, NYH, DKY, IFLAG)
-CLLL. OPTIMIZE
-      INTEGER K, NYH, IFLAG
-      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
-      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-      INTEGER I, IC, J, JB, JB2, JJ, JJ1, JP1
-      DOUBLE PRECISION T, YH, DKY
-      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
-     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
-      DOUBLE PRECISION C, R, S, TP
-      DIMENSION YH(NYH,*), DKY(*)
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
-     1   HOLD, RMAX, TESCO(3,12),
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
-     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
-     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-C-----------------------------------------------------------------------
-C INTDY COMPUTES INTERPOLATED VALUES OF THE K-TH DERIVATIVE OF THE
-C DEPENDENT VARIABLE VECTOR Y, AND STORES IT IN DKY.  THIS ROUTINE
-C IS CALLED WITHIN THE PACKAGE WITH K = 0 AND T = TOUT, BUT MAY
-C ALSO BE CALLED BY THE USER FOR ANY K UP TO THE CURRENT ORDER.
-C (SEE DETAILED INSTRUCTIONS IN THE USAGE DOCUMENTATION.)
-C-----------------------------------------------------------------------
-C THE COMPUTED VALUES IN DKY ARE GOTTEN BY INTERPOLATION USING THE
-C NORDSIECK HISTORY ARRAY YH.  THIS ARRAY CORRESPONDS UNIQUELY TO A
-C VECTOR-VALUED POLYNOMIAL OF DEGREE NQCUR OR LESS, AND DKY IS SET
-C TO THE K-TH DERIVATIVE OF THIS POLYNOMIAL AT T.
-C THE FORMULA FOR DKY IS..
-C              Q
-C  DKY(I)  =  SUM  C(J,K) * (T - TN)**(J-K) * H**(-J) * YH(I,J+1)
-C             J=K
-C WHERE  C(J,K) = J*(J-1)*...*(J-K+1), Q = NQCUR, TN = TCUR, H = HCUR.
-C THE QUANTITIES  NQ = NQCUR, L = NQ+1, N = NEQ, TN, AND H ARE
-C COMMUNICATED BY COMMON.  THE ABOVE SUM IS DONE IN REVERSE ORDER.
-C IFLAG IS RETURNED NEGATIVE IF EITHER K OR T IS OUT OF BOUNDS.
-C-----------------------------------------------------------------------
-      IFLAG = 0
-      IF (K .LT. 0 .OR. K .GT. NQ) GO TO 80
-      TP = TN - HU -  100.0D0*UROUND*(TN + HU)
-      IF ((T-TP)*(T-TN) .GT. 0.0D0) GO TO 90
-C
-      S = (T - TN)/H
-      IC = 1
-      IF (K .EQ. 0) GO TO 15
-      JJ1 = L - K
-      DO 10 JJ = JJ1,NQ
- 10     IC = IC*JJ
- 15   C = DBLE(IC)
-      DO 20 I = 1,N
- 20     DKY(I) = C*YH(I,L)
-      IF (K .EQ. NQ) GO TO 55
-      JB2 = NQ - K
-      DO 50 JB = 1,JB2
-        J = NQ - JB
-        JP1 = J + 1
-        IC = 1
-        IF (K .EQ. 0) GO TO 35
-        JJ1 = JP1 - K
-        DO 30 JJ = JJ1,J
- 30       IC = IC*JJ
- 35     C = DBLE(IC)
-        DO 40 I = 1,N
- 40       DKY(I) = C*YH(I,JP1) + S*DKY(I)
- 50     CONTINUE
-      IF (K .EQ. 0) RETURN
- 55   R = H**(-K)
-      DO 60 I = 1,N
- 60     DKY(I) = R*DKY(I)
-      RETURN
-C
- 80   CALL XERRWD('INTDY--  K (=I1) ILLEGAL      ',
-     1   30, 51, 0, 1, K, 0, 0, 0.0D0, 0.0D0)
-      IFLAG = -1
-      RETURN
- 90   CALL XERRWD('INTDY--  T (=R1) ILLEGAL      ',
-     1   30, 52, 0, 0, 0, 0, 1, T, 0.0D0)
-      CALL XERRWD(
-     1  '      T NOT IN INTERVAL TCUR - HU (= R1) TO TCUR (=R2)      ',
-     1   60, 52, 0, 0, 0, 0, 2, TP, TN)
-      IFLAG = -2
-      RETURN
-C----------------------- END OF SUBROUTINE INTDY -----------------------
-      END
--- a/liboctave/external/odepack/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/external/odepack/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,12 +1,12 @@
 EXTERNAL_SOURCES += \
-  %reldir%/cfode.f \
+  %reldir%/dcfode.f \
+  %reldir%/dewset.f \
+  %reldir%/dintdy.f \
   %reldir%/dlsode.f \
-  %reldir%/ewset.f \
-  %reldir%/intdy.f \
-  %reldir%/prepj.f \
-  %reldir%/solsy.f \
-  %reldir%/stode.f \
-  %reldir%/vnorm.f \
+  %reldir%/dprepj.f \
+  %reldir%/dsolsy.f \
+  %reldir%/dstode.f \
+  %reldir%/dvnorm.f \
   %reldir%/scfode.f \
   %reldir%/sewset.f \
   %reldir%/sintdy.f \
--- a/liboctave/external/odepack/prepj.f	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-      SUBROUTINE PREPJ (NEQ, Y, YH, NYH, EWT, FTEM, SAVF, WM, IWM,
-     1   F, JAC, IERR)
-CLLL. OPTIMIZE
-      EXTERNAL F, JAC
-      INTEGER NEQ, NYH, IWM
-      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
-      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-      INTEGER I, I1, I2, IER, II, J, J1, JJ, LENP,
-     1   MBA, MBAND, MEB1, MEBAND, ML, ML3, MU, NP1
-      DOUBLE PRECISION Y, YH, EWT, FTEM, SAVF, WM
-      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
-     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
-      DOUBLE PRECISION CON, DI, FAC, HL0, R, R0, SRUR, YI, YJ, YJJ,
-     1   VNORM
-      DIMENSION NEQ(*), Y(*), YH(NYH,*), EWT(*), FTEM(*), SAVF(*),
-     1   WM(*), IWM(*)
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
-     1   HOLD, RMAX, TESCO(3,12),
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
-     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
-     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-C-----------------------------------------------------------------------
-C PREPJ IS CALLED BY STODE TO COMPUTE AND PROCESS THE MATRIX
-C P = I - H*EL(1)*J , WHERE J IS AN APPROXIMATION TO THE JACOBIAN.
-C HERE J IS COMPUTED BY THE USER-SUPPLIED ROUTINE JAC IF
-C MITER = 1 OR 4, OR BY FINITE DIFFERENCING IF MITER = 2, 3, OR 5.
-C IF MITER = 3, A DIAGONAL APPROXIMATION TO J IS USED.
-C J IS STORED IN WM AND REPLACED BY P.  IF MITER .NE. 3, P IS THEN
-C SUBJECTED TO LU DECOMPOSITION IN PREPARATION FOR LATER SOLUTION
-C OF LINEAR SYSTEMS WITH P AS COEFFICIENT MATRIX. THIS IS DONE
-C BY DGETRF IF MITER = 1 OR 2, AND BY DGBTRF IF MITER = 4 OR 5.
-C
-C IN ADDITION TO VARIABLES DESCRIBED PREVIOUSLY, COMMUNICATION
-C WITH PREPJ USES THE FOLLOWING..
-C Y     = ARRAY CONTAINING PREDICTED VALUES ON ENTRY.
-C FTEM  = WORK ARRAY OF LENGTH N (ACOR IN STODE).
-C SAVF  = ARRAY CONTAINING F EVALUATED AT PREDICTED Y.
-C WM    = REAL WORK SPACE FOR MATRICES.  ON OUTPUT IT CONTAINS THE
-C         INVERSE DIAGONAL MATRIX IF MITER = 3 AND THE LU DECOMPOSITION
-C         OF P IF MITER IS 1, 2 , 4, OR 5.
-C         STORAGE OF MATRIX ELEMENTS STARTS AT WM(3).
-C         WM ALSO CONTAINS THE FOLLOWING MATRIX-RELATED DATA..
-C         WM(1) = SQRT(UROUND), USED IN NUMERICAL JACOBIAN INCREMENTS.
-C         WM(2) = H*EL0, SAVED FOR LATER USE IF MITER = 3.
-C IWM   = INTEGER WORK SPACE CONTAINING PIVOT INFORMATION, STARTING AT
-C         IWM(21), IF MITER IS 1, 2, 4, OR 5.  IWM ALSO CONTAINS BAND
-C         PARAMETERS ML = IWM(1) AND MU = IWM(2) IF MITER IS 4 OR 5.
-C EL0   = EL(1) (INPUT).
-C IERPJ = OUTPUT ERROR FLAG,  = 0 IF NO TROUBLE, .GT. 0 IF
-C         P MATRIX FOUND TO BE SINGULAR.
-C JCUR  = OUTPUT FLAG = 1 TO INDICATE THAT THE JACOBIAN MATRIX
-C         (OR APPROXIMATION) IS NOW CURRENT.
-C THIS ROUTINE ALSO USES THE COMMON VARIABLES EL0, H, TN, UROUND,
-C MITER, N, NFE, AND NJE.
-C-----------------------------------------------------------------------
-      NJE = NJE + 1
-      IERPJ = 0
-      JCUR = 1
-      HL0 = H*EL0
-      GO TO (100, 200, 300, 400, 500), MITER
-C IF MITER = 1, CALL JAC AND MULTIPLY BY SCALAR. -----------------------
- 100  LENP = N*N
-      DO 110 I = 1,LENP
- 110    WM(I+2) = 0.0D0
-      CALL JAC (NEQ, TN, Y, 0, 0, WM(3), N)
-      CON = -HL0
-      DO 120 I = 1,LENP
- 120    WM(I+2) = WM(I+2)*CON
-      GO TO 240
-C IF MITER = 2, MAKE N CALLS TO F TO APPROXIMATE J. --------------------
- 200  FAC = VNORM (N, SAVF, EWT)
-      R0 = 1000.0D0*DABS(H)*UROUND*DBLE(N)*FAC
-      IF (R0 .EQ. 0.0D0) R0 = 1.0D0
-      SRUR = WM(1)
-      J1 = 2
-      DO 230 J = 1,N
-        YJ = Y(J)
-        R = DMAX1(SRUR*DABS(YJ),R0/EWT(J))
-        Y(J) = Y(J) + R
-        FAC = -HL0/R
-        IERR = 0
-        CALL F (NEQ, TN, Y, FTEM, IERR)
-        IF (IERR .LT. 0) RETURN
-        DO 220 I = 1,N
- 220      WM(I+J1) = (FTEM(I) - SAVF(I))*FAC
-        Y(J) = YJ
-        J1 = J1 + N
- 230    CONTINUE
-      NFE = NFE + N
-C ADD IDENTITY MATRIX. -------------------------------------------------
- 240  J = 3
-      NP1 = N + 1
-      DO 250 I = 1,N
-        WM(J) = WM(J) + 1.0D0
- 250    J = J + NP1
-C DO LU DECOMPOSITION ON P. --------------------------------------------
-      CALL DGETRF ( N, N, WM(3), N, IWM(21), IER)
-      IF (IER .NE. 0) IERPJ = 1
-      RETURN
-C IF MITER = 3, CONSTRUCT A DIAGONAL APPROXIMATION TO J AND P. ---------
- 300  WM(2) = HL0
-      R = EL0*0.1D0
-      DO 310 I = 1,N
- 310    Y(I) = Y(I) + R*(H*SAVF(I) - YH(I,2))
-      IERR = 0
-      CALL F (NEQ, TN, Y, WM(3), IERR)
-      IF (IERR .LT. 0) RETURN
-      NFE = NFE + 1
-      DO 320 I = 1,N
-        R0 = H*SAVF(I) - YH(I,2)
-        DI = 0.1D0*R0 - H*(WM(I+2) - SAVF(I))
-        WM(I+2) = 1.0D0
-        IF (DABS(R0) .LT. UROUND/EWT(I)) GO TO 320
-        IF (DABS(DI) .EQ. 0.0D0) GO TO 330
-        WM(I+2) = 0.1D0*R0/DI
- 320    CONTINUE
-      RETURN
- 330  IERPJ = 1
-      RETURN
-C IF MITER = 4, CALL JAC AND MULTIPLY BY SCALAR. -----------------------
- 400  ML = IWM(1)
-      MU = IWM(2)
-      ML3 = ML + 3
-      MBAND = ML + MU + 1
-      MEBAND = MBAND + ML
-      LENP = MEBAND*N
-      DO 410 I = 1,LENP
- 410    WM(I+2) = 0.0D0
-      CALL JAC (NEQ, TN, Y, ML, MU, WM(ML3), MEBAND)
-      CON = -HL0
-      DO 420 I = 1,LENP
- 420    WM(I+2) = WM(I+2)*CON
-      GO TO 570
-C IF MITER = 5, MAKE MBAND CALLS TO F TO APPROXIMATE J. ----------------
- 500  ML = IWM(1)
-      MU = IWM(2)
-      MBAND = ML + MU + 1
-      MBA = MIN0(MBAND,N)
-      MEBAND = MBAND + ML
-      MEB1 = MEBAND - 1
-      SRUR = WM(1)
-      FAC = VNORM (N, SAVF, EWT)
-      R0 = 1000.0D0*DABS(H)*UROUND*DBLE(N)*FAC
-      IF (R0 .EQ. 0.0D0) R0 = 1.0D0
-      DO 560 J = 1,MBA
-        DO 530 I = J,N,MBAND
-          YI = Y(I)
-          R = DMAX1(SRUR*DABS(YI),R0/EWT(I))
- 530      Y(I) = Y(I) + R
-        IERR = 0
-        CALL F (NEQ, TN, Y, FTEM, IERR)
-        IF (IERR .LT. 0) RETURN
-        DO 550 JJ = J,N,MBAND
-          Y(JJ) = YH(JJ,1)
-          YJJ = Y(JJ)
-          R = DMAX1(SRUR*DABS(YJJ),R0/EWT(JJ))
-          FAC = -HL0/R
-          I1 = MAX0(JJ-MU,1)
-          I2 = MIN0(JJ+ML,N)
-          II = JJ*MEB1 - ML + 2
-          DO 540 I = I1,I2
- 540        WM(II+I) = (FTEM(I) - SAVF(I))*FAC
- 550      CONTINUE
- 560    CONTINUE
-      NFE = NFE + MBA
-C ADD IDENTITY MATRIX. -------------------------------------------------
- 570  II = MBAND + 2
-      DO 580 I = 1,N
-        WM(II) = WM(II) + 1.0D0
- 580    II = II + MEBAND
-C DO LU DECOMPOSITION OF P. --------------------------------------------
-      CALL DGBTRF ( N, N, ML, MU, WM(3), MEBAND, IWM(21), IER)
-      IF (IER .NE. 0) IERPJ = 1
-      RETURN
-C----------------------- END OF SUBROUTINE PREPJ -----------------------
-      END
--- a/liboctave/external/odepack/sintdy.f	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/external/odepack/sintdy.f	Sun May 16 09:44:35 2021 +0200
@@ -96,15 +96,14 @@
  60     DKY(I) = R*DKY(I)
       RETURN
 C
- 80   CALL XERRWD('SINTDY-  K (=I1) illegal      ',
-     1     30, 51, 0, 1, K, 0, 0, 0.0D0, 0.0D0)
+ 80   MSG = 'SINTDY-  K (=I1) illegal      '
+      CALL XERRWV (MSG, 30, 51, 0, 1, K, 0, 0, 0.0E0, 0.0E0)
       IFLAG = -1
       RETURN
- 90   CALL XERRWD('SINTDY-  T (=R1) illegal      ',
-     1     30, 52, 0, 0, 0, 0, 1, DBLE (T), 0.0D0)
-      CALL XERRWD(
-     1   '      T not in interval TCUR - HU (= R1) to TCUR (=R2)      ',
-     1    60, 52, 0, 0, 0, 0, 2, DBLE (TP), DBLE (TN))
+ 90   MSG = 'SINTDY-  T (=R1) illegal      '
+      CALL XERRWV (MSG, 30, 52, 0, 0, 0, 0, 1, T, 0.0E0)
+      MSG='      T not in interval TCUR - HU (= R1) to TCUR (=R2)      '
+      CALL XERRWV (MSG, 60, 52, 0, 0, 0, 0, 2, TP, TN)
       IFLAG = -2
       RETURN
 C----------------------- END OF SUBROUTINE SINTDY ----------------------
--- a/liboctave/external/odepack/slsode.f	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/external/odepack/slsode.f	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,3 @@
-*DECK SLSODE
       SUBROUTINE SLSODE (F, NEQ, Y, T, TOUT, ITOL, RTOL, ATOL, ITASK,
      1                  ISTATE, IOPT, RWORK, LRW, IWORK, LIW, JAC, MF)
       EXTERNAL F, JAC
@@ -1115,7 +1114,7 @@
 C     - Ignore some components of v in the norm, with the effect of
 C       suppressing the error control on those components of Y.
 C  ---------------------------------------------------------------------
-C***ROUTINES CALLED  SEWSET, SINTDY, R1MACH, SSTODE, SVNORM, XERRWD
+C***ROUTINES CALLED  SEWSET, SINTDY, R1MACH, SSTODE, SVNORM, XERRWV
 C***COMMON BLOCKS    SLS001
 C***REVISION HISTORY  (YYYYMMDD)
 C 19791129  DATE WRITTEN
@@ -1195,8 +1194,8 @@
 C  DGBTRF AND DGBTRS   ARE ROUTINES FROM LAPACK FOR SOLVING BANDED
 C           LINEAR SYSTEMS.
 C  R1MACH   computes the unit roundoff in a machine-independent manner.
-C  XERRWD, XSETUN, XSETF, IXSAV, IUMACH   handle the printing of all
-C           error messages and warnings.  XERRWD is machine-dependent.
+C  XERRWV, XSETUN, XSETF, IXSAV, IUMACH   handle the printing of all
+C           error messages and warnings.  XERRWV is machine-dependent.
 C Note: SVNORM, R1MACH, IXSAV, and IUMACH are function routines.
 C All the others are subroutines.
 C
@@ -1507,18 +1506,17 @@
  280  IF ((TN + H) .NE. TN) GO TO 290
       NHNIL = NHNIL + 1
       IF (NHNIL .GT. MXHNIL) GO TO 290
-      CALL XERRWD('SLSODE-  Warning..internal T (=R1) and H (=R2) are',
-     1     50, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD(
-     1  '      such that in the machine, T + H = T on the next step  ',
-     1     60, 101, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      (H = step size). Solver will continue anyway',
-     1     50, 101, 0, 0, 0, 0, 2, DBLE (TN), DBLE (H))
+      MSG = 'SLSODE-  Warning..internal T (=R1) and H (=R2) are'
+      CALL XERRWV (MSG, 50, 101, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG='      such that in the machine, T + H = T on the next step  '
+      CALL XERRWV (MSG, 60, 101, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      (H = step size). Solver will continue anyway'
+      CALL XERRWV (MSG, 50, 101, 0, 0, 0, 0, 2, TN, H)
       IF (NHNIL .LT. MXHNIL) GO TO 290
-      CALL XERRWD('SLSODE-  Above warning has been issued I1 times.  ',
-     1     50, 102, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      It will not be issued again for this problem',
-     1     50, 102, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
+      MSG = 'SLSODE-  Above warning has been issued I1 times.  '
+      CALL XERRWV (MSG, 50, 102, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      It will not be issued again for this problem'
+      CALL XERRWV (MSG, 50, 102, 0, 1, MXHNIL, 0, 0, 0.0E0, 0.0E0)
  290  CONTINUE
 C-----------------------------------------------------------------------
 C  CALL SSTODE(NEQ,Y,YH,NYH,YH,EWT,SAVF,ACOR,WM,IWM,F,JAC,SPREPJ,SSOLSY)
@@ -1590,40 +1588,40 @@
 C are loaded into the work arrays before returning.
 C-----------------------------------------------------------------------
 C The maximum number of steps was taken before reaching TOUT. ----------
- 500  CALL XERRWD('SLSODE-  At current T (=R1), MXSTEP (=I1) steps   ',
-     1 50, 201, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      taken on this call before reaching TOUT     ',
-     1     50, 201, 0, 1, MXSTEP, 0, 1, DBLE (TN), 0.0D0)
+ 500  MSG = 'SLSODE-  At current T (=R1), MXSTEP (=I1) steps   '
+      CALL XERRWV (MSG, 50, 201, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      taken on this call before reaching TOUT     '
+      CALL XERRWV (MSG, 50, 201, 0, 1, MXSTEP, 0, 1, TN, 0.0E0)
       ISTATE = -1
       GO TO 580
 C EWT(I) .LE. 0.0 for some I (not at start of problem). ----------------
  510  EWTI = RWORK(LEWT+I-1)
-      CALL XERRWD('SLSODE-  At T (=R1), EWT(I1) has become R2 .LE. 0.',
-     1 50, 202, 0, 1, I, 0, 2, DBLE (TN), DBLE (EWTI))
+      MSG = 'SLSODE-  At T (=R1), EWT(I1) has become R2 .LE. 0.'
+      CALL XERRWV (MSG, 50, 202, 0, 1, I, 0, 2, TN, EWTI)
       ISTATE = -6
       GO TO 580
 C Too much accuracy requested for machine precision. -------------------
- 520  CALL XERRWD('SLSODE-  At T (=R1), too much accuracy requested  ',
-     1     50, 203, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      for precision of machine..  see TOLSF (=R2) ',
-     1     50, 203, 0, 0, 0, 0, 2, DBLE (TN), DBLE (TOLSF))
+ 520  MSG = 'SLSODE-  At T (=R1), too much accuracy requested  '
+      CALL XERRWV (MSG, 50, 203, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      for precision of machine..  see TOLSF (=R2) '
+      CALL XERRWV (MSG, 50, 203, 0, 0, 0, 0, 2, TN, TOLSF)
       RWORK(14) = TOLSF
       ISTATE = -2
       GO TO 580
 C KFLAG = -1.  Error test failed repeatedly or with ABS(H) = HMIN. -----
- 530  CALL XERRWD('SLSODE-  At T(=R1) and step size H(=R2), the error',
-     1     50, 204, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      test failed repeatedly or with ABS(H) = HMIN',
-     1     50, 204, 0, 0, 0, 0, 2, DBLE (TN), DBLE (H))
+ 530  MSG = 'SLSODE-  At T(=R1) and step size H(=R2), the error'
+      CALL XERRWV (MSG, 50, 204, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      test failed repeatedly or with ABS(H) = HMIN'
+      CALL XERRWV (MSG, 50, 204, 0, 0, 0, 0, 2, TN, H)
       ISTATE = -4
       GO TO 560
 C KFLAG = -2.  Convergence failed repeatedly or with ABS(H) = HMIN. ----
- 540  CALL XERRWD('SLSODE-  At T (=R1) and step size H (=R2), the    ',
-     1     50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      corrector convergence failed repeatedly     ',
-     1     50, 205, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD('      or with ABS(H) = HMIN   ',
-     1     30, 205, 0, 0, 0, 0, 2, DBLE (TN), DBLE (H))
+ 540  MSG = 'SLSODE-  At T (=R1) and step size H (=R2), the    '
+      CALL XERRWV (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      corrector convergence failed repeatedly     '
+      CALL XERRWV (MSG, 50, 205, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG = '      or with ABS(H) = HMIN   '
+      CALL XERRWV (MSG, 30, 205, 0, 0, 0, 0, 2, TN, H)
       ISTATE = -5
 C Compute IMXER if relevant. -------------------------------------------
  560  BIG = 0.0E0
@@ -1655,106 +1653,105 @@
 C First the error message routine is called.  If the illegal input
 C is a negative ISTATE, the run is aborted (apparent infinite loop).
 C-----------------------------------------------------------------------
- 601  CALL XERRWD('SLSODE-  ISTATE (=I1) illegal ',
-     1     30, 1, 0, 1, ISTATE, 0, 0, 0.0D0, 0.0D0)
+ 601  MSG = 'SLSODE-  ISTATE (=I1) illegal '
+      CALL XERRWV (MSG, 30, 1, 0, 1, ISTATE, 0, 0, 0.0E0, 0.0E0)
       IF (ISTATE .LT. 0) GO TO 800
       GO TO 700
- 602  CALL XERRWD('SLSODE-  ITASK (=I1) illegal  ',
-     1     30, 2, 0, 1, ITASK, 0, 0, 0.0D0, 0.0D0)
+ 602  MSG = 'SLSODE-  ITASK (=I1) illegal  '
+      CALL XERRWV (MSG, 30, 2, 0, 1, ITASK, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 603  CALL XERRWD('SLSODE-  ISTATE .GT. 1 but SLSODE not initialized ',
-     1     50, 3, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
+ 603  MSG = 'SLSODE-  ISTATE .GT. 1 but SLSODE not initialized '
+      CALL XERRWV (MSG, 50, 3, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 604  CALL XERRWD('SLSODE-  NEQ (=I1) .LT. 1     ',
-     1     30, 4, 0, 1, NEQ(1), 0, 0, 0.0D0, 0.0D0)
+ 604  MSG = 'SLSODE-  NEQ (=I1) .LT. 1     '
+      CALL XERRWV (MSG, 30, 4, 0, 1, NEQ(1), 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 605  CALL XERRWD('SLSODE-  ISTATE = 3 and NEQ increased (I1 to I2)  ',
-     1     50, 5, 0, 2, N, NEQ(1), 0, 0.0D0, 0.0D0)
+ 605  MSG = 'SLSODE-  ISTATE = 3 and NEQ increased (I1 to I2)  '
+      CALL XERRWV (MSG, 50, 5, 0, 2, N, NEQ(1), 0, 0.0E0, 0.0E0)
       GO TO 700
- 606  CALL XERRWD('SLSODE-  ITOL (=I1) illegal   ',
-     1     30, 6, 0, 1, ITOL, 0, 0, 0.0D0, 0.0D0)
+ 606  MSG = 'SLSODE-  ITOL (=I1) illegal   '
+      CALL XERRWV (MSG, 30, 6, 0, 1, ITOL, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 607  CALL XERRWD('SLSODE-  IOPT (=I1) illegal   ',
-     1     30, 7, 0, 1, IOPT, 0, 0, 0.0D0, 0.0D0)
+ 607  MSG = 'SLSODE-  IOPT (=I1) illegal   '
+      CALL XERRWV (MSG, 30, 7, 0, 1, IOPT, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 608  CALL XERRWD('SLSODE-  MF (=I1) illegal     ',
-     1     30, 8, 0, 1, MF, 0, 0, 0.0D0, 0.0D0)
+ 608  MSG = 'SLSODE-  MF (=I1) illegal     '
+      CALL XERRWV (MSG, 30, 8, 0, 1, MF, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 609  CALL XERRWD('SLSODE-  ML (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)',
-     1     50, 9, 0, 2, ML, NEQ(1), 0, 0.0D0, 0.0D0)
+ 609  MSG = 'SLSODE-  ML (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)'
+      CALL XERRWV (MSG, 50, 9, 0, 2, ML, NEQ(1), 0, 0.0E0, 0.0E0)
       GO TO 700
- 610  CALL XERRWD('SLSODE-  MU (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)',
-     1     50, 10, 0, 2, MU, NEQ(1), 0, 0.0D0, 0.0D0)
+ 610  MSG = 'SLSODE-  MU (=I1) illegal.. .LT.0 or .GE.NEQ (=I2)'
+      CALL XERRWV (MSG, 50, 10, 0, 2, MU, NEQ(1), 0, 0.0E0, 0.0E0)
       GO TO 700
- 611  CALL XERRWD('SLSODE-  MAXORD (=I1) .LT. 0  ',
-     1     30, 11, 0, 1, MAXORD, 0, 0, 0.0D0, 0.0D0)
+ 611  MSG = 'SLSODE-  MAXORD (=I1) .LT. 0  '
+      CALL XERRWV (MSG, 30, 11, 0, 1, MAXORD, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 612  CALL XERRWD('SLSODE-  MXSTEP (=I1) .LT. 0  ',
-     1 30, 12, 0, 1, MXSTEP, 0, 0, 0.0D0, 0.0D0)
+ 612  MSG = 'SLSODE-  MXSTEP (=I1) .LT. 0  '
+      CALL XERRWV (MSG, 30, 12, 0, 1, MXSTEP, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 613  CALL XERRWD('SLSODE-  MXHNIL (=I1) .LT. 0  ',
-     1     30, 13, 0, 1, MXHNIL, 0, 0, 0.0D0, 0.0D0)
+ 613  MSG = 'SLSODE-  MXHNIL (=I1) .LT. 0  '
+      CALL XERRWV (MSG, 30, 13, 0, 1, MXHNIL, 0, 0, 0.0E0, 0.0E0)
       GO TO 700
- 614  CALL XERRWD('SLSODE-  TOUT (=R1) behind T (=R2)      ',
-     1     40, 14, 0, 0, 0, 0, 2, DBLE (TOUT), DBLE (T))
-      CALL XERRWD('      Integration direction is given by H0 (=R1)  ',
-     1     50, 14, 0, 0, 0, 0, 1, DBLE (H0), 0.0D0)
+ 614  MSG = 'SLSODE-  TOUT (=R1) behind T (=R2)      '
+      CALL XERRWV (MSG, 40, 14, 0, 0, 0, 0, 2, TOUT, T)
+      MSG = '      Integration direction is given by H0 (=R1)  '
+      CALL XERRWV (MSG, 50, 14, 0, 0, 0, 0, 1, H0, 0.0E0)
       GO TO 700
- 615  CALL XERRWD('SLSODE-  HMAX (=R1) .LT. 0.0  ',
-     1     30, 15, 0, 0, 0, 0, 1, DBLE (HMAX), 0.0D0)
+ 615  MSG = 'SLSODE-  HMAX (=R1) .LT. 0.0  '
+      CALL XERRWV (MSG, 30, 15, 0, 0, 0, 0, 1, HMAX, 0.0E0)
       GO TO 700
- 616  CALL XERRWD('SLSODE-  HMIN (=R1) .LT. 0.0  ',
-     1     30, 16, 0, 0, 0, 0, 1, DBLE (HMIN), 0.0D0)
+ 616  MSG = 'SLSODE-  HMIN (=R1) .LT. 0.0  '
+      CALL XERRWV (MSG, 30, 16, 0, 0, 0, 0, 1, HMIN, 0.0E0)
       GO TO 700
- 617  CALL XERRWD(
-     1  'SLSODE-  RWORK length needed, LENRW (=I1), exceeds LRW (=I2)',
-     1   60, 17, 0, 2, LENRW, LRW, 0, 0.0D0, 0.0D0)
+ 617  CONTINUE
+      MSG='SLSODE-  RWORK length needed, LENRW (=I1), exceeds LRW (=I2)'
+      CALL XERRWV (MSG, 60, 17, 0, 2, LENRW, LRW, 0, 0.0E0, 0.0E0)
       GO TO 700
- 618  CALL XERRWD(
-     1   'SLSODE-  IWORK length needed, LENIW (=I1), exceeds LIW (=I2)',
-     1    60, 18, 0, 2, LENIW, LIW, 0, 0.0D0, 0.0D0)
+ 618  CONTINUE
+      MSG='SLSODE-  IWORK length needed, LENIW (=I1), exceeds LIW (=I2)'
+      CALL XERRWV (MSG, 60, 18, 0, 2, LENIW, LIW, 0, 0.0E0, 0.0E0)
       GO TO 700
- 619  CALL XERRWD('SLSODE-  RTOL(I1) is R1 .LT. 0.0        ',
-     1     40, 19, 0, 1, I, 0, 1, DBLE (RTOLI), 0.0D0)
+ 619  MSG = 'SLSODE-  RTOL(I1) is R1 .LT. 0.0        '
+      CALL XERRWV (MSG, 40, 19, 0, 1, I, 0, 1, RTOLI, 0.0E0)
       GO TO 700
- 620  CALL XERRWD('SLSODE-  ATOL(I1) is R1 .LT. 0.0        ',
-     1     40, 20, 0, 1, I, 0, 1, DBLE (ATOLI), 0.0D0)
+ 620  MSG = 'SLSODE-  ATOL(I1) is R1 .LT. 0.0        '
+      CALL XERRWV (MSG, 40, 20, 0, 1, I, 0, 1, ATOLI, 0.0E0)
       GO TO 700
  621  EWTI = RWORK(LEWT+I-1)
-      CALL XERRWD('SLSODE-  EWT(I1) is R1 .LE. 0.0         ',
-     1     40, 21, 0, 1, I, 0, 1, DBLE (EWTI), 0.0D0)
+      MSG = 'SLSODE-  EWT(I1) is R1 .LE. 0.0         '
+      CALL XERRWV (MSG, 40, 21, 0, 1, I, 0, 1, EWTI, 0.0E0)
       GO TO 700
- 622  CALL XERRWD(
-     1   'SLSODE-  TOUT (=R1) too close to T(=R2) to start integration',
-     1     60, 22, 0, 0, 0, 0, 2, DBLE (TOUT), DBLE (T))
+ 622  CONTINUE
+      MSG='SLSODE-  TOUT (=R1) too close to T(=R2) to start integration'
+      CALL XERRWV (MSG, 60, 22, 0, 0, 0, 0, 2, TOUT, T)
       GO TO 700
- 623  CALL XERRWD(
-     1 'SLSODE-  ITASK = I1 and TOUT (=R1) behind TCUR - HU (= R2)  ',
-     1     60, 23, 0, 1, ITASK, 0, 2, DBLE (TOUT), DBLE (TP))
+ 623  CONTINUE
+      MSG='SLSODE-  ITASK = I1 and TOUT (=R1) behind TCUR - HU (= R2)  '
+      CALL XERRWV (MSG, 60, 23, 0, 1, ITASK, 0, 2, TOUT, TP)
       GO TO 700
- 624  CALL XERRWD(
-     1   'SLSODE-  ITASK = 4 OR 5 and TCRIT (=R1) behind TCUR (=R2)   ',
-     1    60, 24, 0, 0, 0, 0, 2, DBLE (TCRIT), DBLE (TN))
+ 624  CONTINUE
+      MSG='SLSODE-  ITASK = 4 OR 5 and TCRIT (=R1) behind TCUR (=R2)   '
+      CALL XERRWV (MSG, 60, 24, 0, 0, 0, 0, 2, TCRIT, TN)
       GO TO 700
- 625  CALL XERRWD(
-     1  'SLSODE-  ITASK = 4 or 5 and TCRIT (=R1) behind TOUT (=R2)   ',
-     1   60, 25, 0, 0, 0, 0, 2, DBLE (TCRIT), DBLE (TOUT))
+ 625  CONTINUE
+      MSG='SLSODE-  ITASK = 4 or 5 and TCRIT (=R1) behind TOUT (=R2)   '
+      CALL XERRWV (MSG, 60, 25, 0, 0, 0, 0, 2, TCRIT, TOUT)
       GO TO 700
- 626  CALL XERRWD('SLSODE-  At start of problem, too much accuracy   ',
-     1     50, 26, 0, 0, 0, 0, 0, 0.0D0, 0.0D0)
-      CALL XERRWD(
-     1   '      requested for precision of machine..  See TOLSF (=R1) ',
-     1    60, 26, 0, 0, 0, 0, 1, DBLE (TOLSF), 0.0D0)
+ 626  MSG = 'SLSODE-  At start of problem, too much accuracy   '
+      CALL XERRWV (MSG, 50, 26, 0, 0, 0, 0, 0, 0.0E0, 0.0E0)
+      MSG='      requested for precision of machine..  See TOLSF (=R1) '
+      CALL XERRWV (MSG, 60, 26, 0, 0, 0, 0, 1, TOLSF, 0.0E0)
       RWORK(14) = TOLSF
       GO TO 700
- 627  CALL XERRWD('SLSODE-  Trouble in SINTDY.  ITASK = I1, TOUT = R1',
-     1     50, 27, 0, 1, ITASK, 0, 1, DBLE (TOUT), 0.0D0)
+ 627  MSG = 'SLSODE-  Trouble in SINTDY.  ITASK = I1, TOUT = R1'
+      CALL XERRWV (MSG, 50, 27, 0, 1, ITASK, 0, 1, TOUT, 0.0E0)
 C
  700  ISTATE = -3
       RETURN
 C
- 800  CALL XERRWD('SLSODE-  Run aborted.. apparent infinite loop     ',
-     1     50, 303, 2, 0, 0, 0, 0, 0.0D0, 0.0D0)
+ 800  MSG = 'SLSODE-  Run aborted.. apparent infinite loop     '
+      CALL XERRWV (MSG, 50, 303, 2, 0, 0, 0, 0, 0.0E0, 0.0E0)
       RETURN
 C----------------------- END OF SUBROUTINE SLSODE ----------------------
       END
--- a/liboctave/external/odepack/solsy.f	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-      SUBROUTINE SOLSY (WM, IWM, X, TEM)
-CLLL. OPTIMIZE
-      INTEGER IWM
-      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
-     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
-      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     2   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-      INTEGER I, MEBAND, ML, MU
-      DOUBLE PRECISION WM, X, TEM
-      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
-     1   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
-      DOUBLE PRECISION DI, HL0, PHL0, R
-      DIMENSION WM(*), IWM(*), X(*), TEM(*)
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
-     1   HOLD, RMAX, TESCO(3,12),
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
-     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, NYH,
-     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
-     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-C-----------------------------------------------------------------------
-C THIS ROUTINE MANAGES THE SOLUTION OF THE LINEAR SYSTEM ARISING FROM
-C A CHORD ITERATION.  IT IS CALLED IF MITER .NE. 0.
-C IF MITER IS 1 OR 2, IT CALLS DGETRS TO ACCOMPLISH THIS.
-C IF MITER = 3 IT UPDATES THE COEFFICIENT H*EL0 IN THE DIAGONAL
-C MATRIX, AND THEN COMPUTES THE SOLUTION.
-C IF MITER IS 4 OR 5, IT CALLS DGBTRS.
-C COMMUNICATION WITH SOLSY USES THE FOLLOWING VARIABLES..
-C WM    = REAL WORK SPACE CONTAINING THE INVERSE DIAGONAL MATRIX IF
-C         MITER = 3 AND THE LU DECOMPOSITION OF THE MATRIX OTHERWISE.
-C         STORAGE OF MATRIX ELEMENTS STARTS AT WM(3).
-C         WM ALSO CONTAINS THE FOLLOWING MATRIX-RELATED DATA..
-C         WM(1) = SQRT(UROUND) (NOT USED HERE),
-C         WM(2) = HL0, THE PREVIOUS VALUE OF H*EL0, USED IF MITER = 3.
-C IWM   = INTEGER WORK SPACE CONTAINING PIVOT INFORMATION, STARTING AT
-C         IWM(21), IF MITER IS 1, 2, 4, OR 5.  IWM ALSO CONTAINS BAND
-C         PARAMETERS ML = IWM(1) AND MU = IWM(2) IF MITER IS 4 OR 5.
-C X     = THE RIGHT-HAND SIDE VECTOR ON INPUT, AND THE SOLUTION VECTOR
-C         ON OUTPUT, OF LENGTH N.
-C TEM   = VECTOR OF WORK SPACE OF LENGTH N, NOT USED IN THIS VERSION.
-C IERSL = OUTPUT FLAG (IN COMMON).  IERSL = 0 IF NO TROUBLE OCCURRED.
-C         IERSL = 1 IF A SINGULAR MATRIX AROSE WITH MITER = 3.
-C THIS ROUTINE ALSO USES THE COMMON VARIABLES EL0, H, MITER, AND N.
-C-----------------------------------------------------------------------
-      IERSL = 0
-      GO TO (100, 100, 300, 400, 400), MITER
- 100  CALL DGETRS ( 'N', N, 1, WM(3), N, IWM(21), X, N, INLPCK)
-      RETURN
-C
- 300  PHL0 = WM(2)
-      HL0 = H*EL0
-      WM(2) = HL0
-      IF (HL0 .EQ. PHL0) GO TO 330
-      R = HL0/PHL0
-      DO 320 I = 1,N
-        DI = 1.0D0 - R*(1.0D0 - 1.0D0/WM(I+2))
-        IF (DABS(DI) .EQ. 0.0D0) GO TO 390
- 320    WM(I+2) = 1.0D0/DI
- 330  DO 340 I = 1,N
- 340    X(I) = WM(I+2)*X(I)
-      RETURN
- 390  IERSL = 1
-      RETURN
-C
- 400  ML = IWM(1)
-      MU = IWM(2)
-      MEBAND = 2*ML + MU + 1
-      CALL DGBTRS ( 'N', N, ML, MU, 1, WM(3), MEBAND, IWM(21), X, N,
-     * INLPCK)
-      RETURN
-C----------------------- END OF SUBROUTINE SOLSY -----------------------
-      END
--- a/liboctave/external/odepack/ssolsy.f	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/external/odepack/ssolsy.f	Sun May 16 09:44:35 2021 +0200
@@ -61,6 +61,7 @@
      4   LYH, LEWT, LACOR, LSAVF, LWM, LIWM, METH, MITER,
      5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
       INTEGER I, MEBAND, ML, MU
+      INTEGER INLPCK
       REAL DI, HL0, PHL0, R
 C
 C***FIRST EXECUTABLE STATEMENT  SSOLSY
--- a/liboctave/external/odepack/stode.f	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,487 +0,0 @@
-      SUBROUTINE STODE (NEQ, Y, YH, NYH, YH1, EWT, SAVF, ACOR,
-     1   WM, IWM, F, JAC, PJAC, SLVS, IERR)
-CLLL. OPTIMIZE
-      EXTERNAL F, JAC, PJAC, SLVS
-      INTEGER NEQ, NYH, IWM
-      INTEGER ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     1   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     2   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP
-      INTEGER ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     1   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-      INTEGER I, I1, IREDO, IRET, J, JB, M, NCF, NEWQ
-      DOUBLE PRECISION Y, YH, YH1, EWT, SAVF, ACOR, WM
-      DOUBLE PRECISION CONIT, CRATE, EL, ELCO, HOLD, RMAX, TESCO,
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND
-      DOUBLE PRECISION DCON, DDN, DEL, DELP, DSM, DUP, EXDN, EXSM, EXUP,
-     1   R, RH, RHDN, RHSM, RHUP, TOLD, VNORM
-      DIMENSION NEQ(*), Y(*), YH(NYH,*), YH1(*), EWT(*), SAVF(*),
-     1   ACOR(*), WM(*), IWM(*)
-      COMMON /LS0001/ CONIT, CRATE, EL(13), ELCO(13,12),
-     1   HOLD, RMAX, TESCO(3,12),
-     2   CCMAX, EL0, H, HMIN, HMXI, HU, RC, TN, UROUND,
-     2   ILLIN, INIT, LYH, LEWT, LACOR, LSAVF, LWM, LIWM,
-     3   MXSTEP, MXHNIL, NHNIL, NTREP, NSLAST, CNYH,
-     3   IALTH, IPUP, LMAX, MEO, NQNYH, NSLP,
-     4   ICF, IERPJ, IERSL, JCUR, JSTART, KFLAG, L, METH, MITER,
-     5   MAXORD, MAXCOR, MSBP, MXNCF, N, NQ, NST, NFE, NJE, NQU
-C-----------------------------------------------------------------------
-C STODE PERFORMS ONE STEP OF THE INTEGRATION OF AN INITIAL VALUE
-C PROBLEM FOR A SYSTEM OF ORDINARY DIFFERENTIAL EQUATIONS.
-C NOTE.. STODE IS INDEPENDENT OF THE VALUE OF THE ITERATION METHOD
-C INDICATOR MITER, WHEN THIS IS .NE. 0, AND HENCE IS INDEPENDENT
-C OF THE TYPE OF CHORD METHOD USED, OR THE JACOBIAN STRUCTURE.
-C COMMUNICATION WITH STODE IS DONE WITH THE FOLLOWING VARIABLES..
-C
-C NEQ    = INTEGER ARRAY CONTAINING PROBLEM SIZE IN NEQ(1), AND
-C          PASSED AS THE NEQ ARGUMENT IN ALL CALLS TO F AND JAC.
-C Y      = AN ARRAY OF LENGTH .GE. N USED AS THE Y ARGUMENT IN
-C          ALL CALLS TO F AND JAC.
-C YH     = AN NYH BY LMAX ARRAY CONTAINING THE DEPENDENT VARIABLES
-C          AND THEIR APPROXIMATE SCALED DERIVATIVES, WHERE
-C          LMAX = MAXORD + 1.  YH(I,J+1) CONTAINS THE APPROXIMATE
-C          J-TH DERIVATIVE OF Y(I), SCALED BY H**J/FACTORIAL(J)
-C          (J = 0,1,...,NQ).  ON ENTRY FOR THE FIRST STEP, THE FIRST
-C          TWO COLUMNS OF YH MUST BE SET FROM THE INITIAL VALUES.
-C NYH    = A CONSTANT INTEGER .GE. N, THE FIRST DIMENSION OF YH.
-C YH1    = A ONE-DIMENSIONAL ARRAY OCCUPYING THE SAME SPACE AS YH.
-C EWT    = AN ARRAY OF LENGTH N CONTAINING MULTIPLICATIVE WEIGHTS
-C          FOR LOCAL ERROR MEASUREMENTS.  LOCAL ERRORS IN Y(I) ARE
-C          COMPARED TO 1.0/EWT(I) IN VARIOUS ERROR TESTS.
-C SAVF   = AN ARRAY OF WORKING STORAGE, OF LENGTH N.
-C          ALSO USED FOR INPUT OF YH(*,MAXORD+2) WHEN JSTART = -1
-C          AND MAXORD .LT. THE CURRENT ORDER NQ.
-C ACOR   = A WORK ARRAY OF LENGTH N, USED FOR THE ACCUMULATED
-C          CORRECTIONS.  ON A SUCCESSFUL RETURN, ACOR(I) CONTAINS
-C          THE ESTIMATED ONE-STEP LOCAL ERROR IN Y(I).
-C WM,IWM = REAL AND INTEGER WORK ARRAYS ASSOCIATED WITH MATRIX
-C          OPERATIONS IN CHORD ITERATION (MITER .NE. 0).
-C PJAC   = NAME OF ROUTINE TO EVALUATE AND PREPROCESS JACOBIAN MATRIX
-C          AND P = I - H*EL0*JAC, IF A CHORD METHOD IS BEING USED.
-C SLVS   = NAME OF ROUTINE TO SOLVE LINEAR SYSTEM IN CHORD ITERATION.
-C CCMAX  = MAXIMUM RELATIVE CHANGE IN H*EL0 BEFORE PJAC IS CALLED.
-C H      = THE STEP SIZE TO BE ATTEMPTED ON THE NEXT STEP.
-C          H IS ALTERED BY THE ERROR CONTROL ALGORITHM DURING THE
-C          PROBLEM.  H CAN BE EITHER POSITIVE OR NEGATIVE, BUT ITS
-C          SIGN MUST REMAIN CONSTANT THROUGHOUT THE PROBLEM.
-C HMIN   = THE MINIMUM ABSOLUTE VALUE OF THE STEP SIZE H TO BE USED.
-C HMXI   = INVERSE OF THE MAXIMUM ABSOLUTE VALUE OF H TO BE USED.
-C          HMXI = 0.0 IS ALLOWED AND CORRESPONDS TO AN INFINITE HMAX.
-C          HMIN AND HMXI MAY BE CHANGED AT ANY TIME, BUT WILL NOT
-C          TAKE EFFECT UNTIL THE NEXT CHANGE OF H IS CONSIDERED.
-C TN     = THE INDEPENDENT VARIABLE. TN IS UPDATED ON EACH STEP TAKEN.
-C JSTART = AN INTEGER USED FOR INPUT ONLY, WITH THE FOLLOWING
-C          VALUES AND MEANINGS..
-C               0  PERFORM THE FIRST STEP.
-C           .GT.0  TAKE A NEW STEP CONTINUING FROM THE LAST.
-C              -1  TAKE THE NEXT STEP WITH A NEW VALUE OF H, MAXORD,
-C                    N, METH, MITER, AND/OR MATRIX PARAMETERS.
-C              -2  TAKE THE NEXT STEP WITH A NEW VALUE OF H,
-C                    BUT WITH OTHER INPUTS UNCHANGED.
-C          ON RETURN, JSTART IS SET TO 1 TO FACILITATE CONTINUATION.
-C KFLAG  = A COMPLETION CODE WITH THE FOLLOWING MEANINGS..
-C               0  THE STEP WAS SUCCESFUL.
-C              -1  THE REQUESTED ERROR COULD NOT BE ACHIEVED.
-C              -2  CORRECTOR CONVERGENCE COULD NOT BE ACHIEVED.
-C              -3  FATAL ERROR IN PJAC OR SLVS.
-C          A RETURN WITH KFLAG = -1 OR -2 MEANS EITHER
-C          ABS(H) = HMIN OR 10 CONSECUTIVE FAILURES OCCURRED.
-C          ON A RETURN WITH KFLAG NEGATIVE, THE VALUES OF TN AND
-C          THE YH ARRAY ARE AS OF THE BEGINNING OF THE LAST
-C          STEP, AND H IS THE LAST STEP SIZE ATTEMPTED.
-C MAXORD = THE MAXIMUM ORDER OF INTEGRATION METHOD TO BE ALLOWED.
-C MAXCOR = THE MAXIMUM NUMBER OF CORRECTOR ITERATIONS ALLOWED.
-C MSBP   = MAXIMUM NUMBER OF STEPS BETWEEN PJAC CALLS (MITER .GT. 0).
-C MXNCF  = MAXIMUM NUMBER OF CONVERGENCE FAILURES ALLOWED.
-C METH/MITER = THE METHOD FLAGS.  SEE DESCRIPTION IN DRIVER.
-C N      = THE NUMBER OF FIRST-ORDER DIFFERENTIAL EQUATIONS.
-C IERR   = ERROR FLAG FROM USER-SUPPLIED FUNCTION
-C-----------------------------------------------------------------------
-      KFLAG = 0
-      TOLD = TN
-      NCF = 0
-      IERPJ = 0
-      IERSL = 0
-      JCUR = 0
-      ICF = 0
-      DELP = 0.0D0
-      IF (JSTART .GT. 0) GO TO 200
-      IF (JSTART .EQ. -1) GO TO 100
-      IF (JSTART .EQ. -2) GO TO 160
-C-----------------------------------------------------------------------
-C ON THE FIRST CALL, THE ORDER IS SET TO 1, AND OTHER VARIABLES ARE
-C INITIALIZED.  RMAX IS THE MAXIMUM RATIO BY WHICH H CAN BE INCREASED
-C IN A SINGLE STEP.  IT IS INITIALLY 1.E4 TO COMPENSATE FOR THE SMALL
-C INITIAL H, BUT THEN IS NORMALLY EQUAL TO 10.  IF A FAILURE
-C OCCURS (IN CORRECTOR CONVERGENCE OR ERROR TEST), RMAX IS SET AT 2
-C FOR THE NEXT INCREASE.
-C-----------------------------------------------------------------------
-      LMAX = MAXORD + 1
-      NQ = 1
-      L = 2
-      IALTH = 2
-      RMAX = 10000.0D0
-      RC = 0.0D0
-      EL0 = 1.0D0
-      CRATE = 0.7D0
-      HOLD = H
-      MEO = METH
-      NSLP = 0
-      IPUP = MITER
-      IRET = 3
-      GO TO 140
-C-----------------------------------------------------------------------
-C THE FOLLOWING BLOCK HANDLES PRELIMINARIES NEEDED WHEN JSTART = -1.
-C IPUP IS SET TO MITER TO FORCE A MATRIX UPDATE.
-C IF AN ORDER INCREASE IS ABOUT TO BE CONSIDERED (IALTH = 1),
-C IALTH IS RESET TO 2 TO POSTPONE CONSIDERATION ONE MORE STEP.
-C IF THE CALLER HAS CHANGED METH, CFODE IS CALLED TO RESET
-C THE COEFFICIENTS OF THE METHOD.
-C IF THE CALLER HAS CHANGED MAXORD TO A VALUE LESS THAN THE CURRENT
-C ORDER NQ, NQ IS REDUCED TO MAXORD, AND A NEW H CHOSEN ACCORDINGLY.
-C IF H IS TO BE CHANGED, YH MUST BE RESCALED.
-C IF H OR METH IS BEING CHANGED, IALTH IS RESET TO L = NQ + 1
-C TO PREVENT FURTHER CHANGES IN H FOR THAT MANY STEPS.
-C-----------------------------------------------------------------------
- 100  IPUP = MITER
-      LMAX = MAXORD + 1
-      IF (IALTH .EQ. 1) IALTH = 2
-      IF (METH .EQ. MEO) GO TO 110
-      CALL CFODE (METH, ELCO, TESCO)
-      MEO = METH
-      IF (NQ .GT. MAXORD) GO TO 120
-      IALTH = L
-      IRET = 1
-      GO TO 150
- 110  IF (NQ .LE. MAXORD) GO TO 160
- 120  NQ = MAXORD
-      L = LMAX
-      DO 125 I = 1,L
- 125    EL(I) = ELCO(I,NQ)
-      NQNYH = NQ*NYH
-      RC = RC*EL(1)/EL0
-      EL0 = EL(1)
-      CONIT = 0.5D0/DBLE(NQ+2)
-      DDN = VNORM (N, SAVF, EWT)/TESCO(1,L)
-      EXDN = 1.0D0/DBLE(L)
-      RHDN = 1.0D0/(1.3D0*DDN**EXDN + 0.0000013D0)
-      RH = DMIN1(RHDN,1.0D0)
-      IREDO = 3
-      IF (H .EQ. HOLD) GO TO 170
-      RH = DMIN1(RH,DABS(H/HOLD))
-      H = HOLD
-      GO TO 175
-C-----------------------------------------------------------------------
-C CFODE IS CALLED TO GET ALL THE INTEGRATION COEFFICIENTS FOR THE
-C CURRENT METH.  THEN THE EL VECTOR AND RELATED CONSTANTS ARE RESET
-C WHENEVER THE ORDER NQ IS CHANGED, OR AT THE START OF THE PROBLEM.
-C-----------------------------------------------------------------------
- 140  CALL CFODE (METH, ELCO, TESCO)
- 150  DO 155 I = 1,L
- 155    EL(I) = ELCO(I,NQ)
-      NQNYH = NQ*NYH
-      RC = RC*EL(1)/EL0
-      EL0 = EL(1)
-      CONIT = 0.5D0/DBLE(NQ+2)
-      GO TO (160, 170, 200), IRET
-C-----------------------------------------------------------------------
-C IF H IS BEING CHANGED, THE H RATIO RH IS CHECKED AGAINST
-C RMAX, HMIN, AND HMXI, AND THE YH ARRAY RESCALED.  IALTH IS SET TO
-C L = NQ + 1 TO PREVENT A CHANGE OF H FOR THAT MANY STEPS, UNLESS
-C FORCED BY A CONVERGENCE OR ERROR TEST FAILURE.
-C-----------------------------------------------------------------------
- 160  IF (H .EQ. HOLD) GO TO 200
-      RH = H/HOLD
-      H = HOLD
-      IREDO = 3
-      GO TO 175
- 170  RH = DMAX1(RH,HMIN/DABS(H))
- 175  RH = DMIN1(RH,RMAX)
-      RH = RH/DMAX1(1.0D0,DABS(H)*HMXI*RH)
-      R = 1.0D0
-      DO 180 J = 2,L
-        R = R*RH
-        DO 180 I = 1,N
- 180      YH(I,J) = YH(I,J)*R
-      H = H*RH
-      RC = RC*RH
-      IALTH = L
-      IF (IREDO .EQ. 0) GO TO 690
-C-----------------------------------------------------------------------
-C THIS SECTION COMPUTES THE PREDICTED VALUES BY EFFECTIVELY
-C MULTIPLYING THE YH ARRAY BY THE PASCAL TRIANGLE MATRIX.
-C RC IS THE RATIO OF NEW TO OLD VALUES OF THE COEFFICIENT  H*EL(1).
-C WHEN RC DIFFERS FROM 1 BY MORE THAN CCMAX, IPUP IS SET TO MITER
-C TO FORCE PJAC TO BE CALLED, IF A JACOBIAN IS INVOLVED.
-C IN ANY CASE, PJAC IS CALLED AT LEAST EVERY MSBP STEPS.
-C-----------------------------------------------------------------------
- 200  IF (DABS(RC-1.0D0) .GT. CCMAX) IPUP = MITER
-      IF (NST .GE. NSLP+MSBP) IPUP = MITER
-      TN = TN + H
-      I1 = NQNYH + 1
-      DO 215 JB = 1,NQ
-        I1 = I1 - NYH
-CDIR$ IVDEP
-        DO 210 I = I1,NQNYH
- 210      YH1(I) = YH1(I) + YH1(I+NYH)
- 215    CONTINUE
-C-----------------------------------------------------------------------
-C UP TO MAXCOR CORRECTOR ITERATIONS ARE TAKEN.  A CONVERGENCE TEST IS
-C MADE ON THE R.M.S. NORM OF EACH CORRECTION, WEIGHTED BY THE ERROR
-C WEIGHT VECTOR EWT.  THE SUM OF THE CORRECTIONS IS ACCUMULATED IN THE
-C VECTOR ACOR(I).  THE YH ARRAY IS NOT ALTERED IN THE CORRECTOR LOOP.
-C-----------------------------------------------------------------------
- 220  M = 0
-      DO 230 I = 1,N
- 230    Y(I) = YH(I,1)
-      IERR = 0
-      CALL F (NEQ, TN, Y, SAVF, IERR)
-      IF (IERR .LT. 0) RETURN
-      NFE = NFE + 1
-      IF (IPUP .LE. 0) GO TO 250
-C-----------------------------------------------------------------------
-C IF INDICATED, THE MATRIX P = I - H*EL(1)*J IS REEVALUATED AND
-C PREPROCESSED BEFORE STARTING THE CORRECTOR ITERATION.  IPUP IS SET
-C TO 0 AS AN INDICATOR THAT THIS HAS BEEN DONE.
-C-----------------------------------------------------------------------
-      IERR = 0
-      CALL PJAC (NEQ, Y, YH, NYH, EWT, ACOR, SAVF, WM, IWM, F, JAC,
-     1   IERR)
-      IF (IERR .LT. 0) RETURN
-      IPUP = 0
-      RC = 1.0D0
-      NSLP = NST
-      CRATE = 0.7D0
-      IF (IERPJ .NE. 0) GO TO 430
- 250  DO 260 I = 1,N
- 260    ACOR(I) = 0.0D0
- 270  IF (MITER .NE. 0) GO TO 350
-C-----------------------------------------------------------------------
-C IN THE CASE OF FUNCTIONAL ITERATION, UPDATE Y DIRECTLY FROM
-C THE RESULT OF THE LAST FUNCTION EVALUATION.
-C-----------------------------------------------------------------------
-      DO 290 I = 1,N
-        SAVF(I) = H*SAVF(I) - YH(I,2)
- 290    Y(I) = SAVF(I) - ACOR(I)
-      DEL = VNORM (N, Y, EWT)
-      DO 300 I = 1,N
-        Y(I) = YH(I,1) + EL(1)*SAVF(I)
- 300    ACOR(I) = SAVF(I)
-      GO TO 400
-C-----------------------------------------------------------------------
-C IN THE CASE OF THE CHORD METHOD, COMPUTE THE CORRECTOR ERROR,
-C AND SOLVE THE LINEAR SYSTEM WITH THAT AS RIGHT-HAND SIDE AND
-C P AS COEFFICIENT MATRIX.
-C-----------------------------------------------------------------------
- 350  DO 360 I = 1,N
- 360    Y(I) = H*SAVF(I) - (YH(I,2) + ACOR(I))
-      CALL SLVS (WM, IWM, Y, SAVF)
-      IF (IERSL .LT. 0) GO TO 430
-      IF (IERSL .GT. 0) GO TO 410
-      DEL = VNORM (N, Y, EWT)
-      DO 380 I = 1,N
-        ACOR(I) = ACOR(I) + Y(I)
- 380    Y(I) = YH(I,1) + EL(1)*ACOR(I)
-C-----------------------------------------------------------------------
-C TEST FOR CONVERGENCE.  IF M.GT.0, AN ESTIMATE OF THE CONVERGENCE
-C RATE CONSTANT IS STORED IN CRATE, AND THIS IS USED IN THE TEST.
-C-----------------------------------------------------------------------
- 400  IF (M .NE. 0) CRATE = DMAX1(0.2D0*CRATE,DEL/DELP)
-      DCON = DEL*DMIN1(1.0D0,1.5D0*CRATE)/(TESCO(2,NQ)*CONIT)
-      IF (DCON .LE. 1.0D0) GO TO 450
-      M = M + 1
-      IF (M .EQ. MAXCOR) GO TO 410
-      IF (M .GE. 2 .AND. DEL .GT. 2.0D0*DELP) GO TO 410
-      DELP = DEL
-      IERR = 0
-      CALL F (NEQ, TN, Y, SAVF, IERR)
-      IF (IERR .LT. 0) RETURN
-      NFE = NFE + 1
-      GO TO 270
-C-----------------------------------------------------------------------
-C THE CORRECTOR ITERATION FAILED TO CONVERGE.
-C IF MITER .NE. 0 AND THE JACOBIAN IS OUT OF DATE, PJAC IS CALLED FOR
-C THE NEXT TRY.  OTHERWISE THE YH ARRAY IS RETRACTED TO ITS VALUES
-C BEFORE PREDICTION, AND H IS REDUCED, IF POSSIBLE.  IF H CANNOT BE
-C REDUCED OR MXNCF FAILURES HAVE OCCURRED, EXIT WITH KFLAG = -2.
-C-----------------------------------------------------------------------
- 410  IF (MITER .EQ. 0 .OR. JCUR .EQ. 1) GO TO 430
-      ICF = 1
-      IPUP = MITER
-      GO TO 220
- 430  ICF = 2
-      NCF = NCF + 1
-      RMAX = 2.0D0
-      TN = TOLD
-      I1 = NQNYH + 1
-      DO 445 JB = 1,NQ
-        I1 = I1 - NYH
-CDIR$ IVDEP
-        DO 440 I = I1,NQNYH
- 440      YH1(I) = YH1(I) - YH1(I+NYH)
- 445    CONTINUE
-      IF (IERPJ .LT. 0 .OR. IERSL .LT. 0) GO TO 680
-      IF (DABS(H) .LE. HMIN*1.00001D0) GO TO 670
-      IF (NCF .EQ. MXNCF) GO TO 670
-      RH = 0.25D0
-      IPUP = MITER
-      IREDO = 1
-      GO TO 170
-C-----------------------------------------------------------------------
-C THE CORRECTOR HAS CONVERGED.  JCUR IS SET TO 0
-C TO SIGNAL THAT THE JACOBIAN INVOLVED MAY NEED UPDATING LATER.
-C THE LOCAL ERROR TEST IS MADE AND CONTROL PASSES TO STATEMENT 500
-C IF IT FAILS.
-C-----------------------------------------------------------------------
- 450  JCUR = 0
-      IF (M .EQ. 0) DSM = DEL/TESCO(2,NQ)
-      IF (M .GT. 0) DSM = VNORM (N, ACOR, EWT)/TESCO(2,NQ)
-      IF (DSM .GT. 1.0D0) GO TO 500
-C-----------------------------------------------------------------------
-C AFTER A SUCCESSFUL STEP, UPDATE THE YH ARRAY.
-C CONSIDER CHANGING H IF IALTH = 1.  OTHERWISE DECREASE IALTH BY 1.
-C IF IALTH IS THEN 1 AND NQ .LT. MAXORD, THEN ACOR IS SAVED FOR
-C USE IN A POSSIBLE ORDER INCREASE ON THE NEXT STEP.
-C IF A CHANGE IN H IS CONSIDERED, AN INCREASE OR DECREASE IN ORDER
-C BY ONE IS CONSIDERED ALSO.  A CHANGE IN H IS MADE ONLY IF IT IS BY A
-C FACTOR OF AT LEAST 1.1.  IF NOT, IALTH IS SET TO 3 TO PREVENT
-C TESTING FOR THAT MANY STEPS.
-C-----------------------------------------------------------------------
-      KFLAG = 0
-      IREDO = 0
-      NST = NST + 1
-      HU = H
-      NQU = NQ
-      DO 470 J = 1,L
-        DO 470 I = 1,N
- 470      YH(I,J) = YH(I,J) + EL(J)*ACOR(I)
-      IALTH = IALTH - 1
-      IF (IALTH .EQ. 0) GO TO 520
-      IF (IALTH .GT. 1) GO TO 700
-      IF (L .EQ. LMAX) GO TO 700
-      DO 490 I = 1,N
- 490    YH(I,LMAX) = ACOR(I)
-      GO TO 700
-C-----------------------------------------------------------------------
-C THE ERROR TEST FAILED.  KFLAG KEEPS TRACK OF MULTIPLE FAILURES.
-C RESTORE TN AND THE YH ARRAY TO THEIR PREVIOUS VALUES, AND PREPARE
-C TO TRY THE STEP AGAIN.  COMPUTE THE OPTIMUM STEP SIZE FOR THIS OR
-C ONE LOWER ORDER.  AFTER 2 OR MORE FAILURES, H IS FORCED TO DECREASE
-C BY A FACTOR OF 0.2 OR LESS.
-C-----------------------------------------------------------------------
- 500  KFLAG = KFLAG - 1
-      TN = TOLD
-      I1 = NQNYH + 1
-      DO 515 JB = 1,NQ
-        I1 = I1 - NYH
-CDIR$ IVDEP
-        DO 510 I = I1,NQNYH
- 510      YH1(I) = YH1(I) - YH1(I+NYH)
- 515    CONTINUE
-      RMAX = 2.0D0
-      IF (DABS(H) .LE. HMIN*1.00001D0) GO TO 660
-      IF (KFLAG .LE. -3) GO TO 640
-      IREDO = 2
-      RHUP = 0.0D0
-      GO TO 540
-C-----------------------------------------------------------------------
-C REGARDLESS OF THE SUCCESS OR FAILURE OF THE STEP, FACTORS
-C RHDN, RHSM, AND RHUP ARE COMPUTED, BY WHICH H COULD BE MULTIPLIED
-C AT ORDER NQ - 1, ORDER NQ, OR ORDER NQ + 1, RESPECTIVELY.
-C IN THE CASE OF FAILURE, RHUP = 0.0 TO AVOID AN ORDER INCREASE.
-C THE LARGEST OF THESE IS DETERMINED AND THE NEW ORDER CHOSEN
-C ACCORDINGLY.  IF THE ORDER IS TO BE INCREASED, WE COMPUTE ONE
-C ADDITIONAL SCALED DERIVATIVE.
-C-----------------------------------------------------------------------
- 520  RHUP = 0.0D0
-      IF (L .EQ. LMAX) GO TO 540
-      DO 530 I = 1,N
- 530    SAVF(I) = ACOR(I) - YH(I,LMAX)
-      DUP = VNORM (N, SAVF, EWT)/TESCO(3,NQ)
-      EXUP = 1.0D0/DBLE(L+1)
-      RHUP = 1.0D0/(1.4D0*DUP**EXUP + 0.0000014D0)
- 540  EXSM = 1.0D0/DBLE(L)
-      RHSM = 1.0D0/(1.2D0*DSM**EXSM + 0.0000012D0)
-      RHDN = 0.0D0
-      IF (NQ .EQ. 1) GO TO 560
-      DDN = VNORM (N, YH(1,L), EWT)/TESCO(1,NQ)
-      EXDN = 1.0D0/DBLE(NQ)
-      RHDN = 1.0D0/(1.3D0*DDN**EXDN + 0.0000013D0)
- 560  IF (RHSM .GE. RHUP) GO TO 570
-      IF (RHUP .GT. RHDN) GO TO 590
-      GO TO 580
- 570  IF (RHSM .LT. RHDN) GO TO 580
-      NEWQ = NQ
-      RH = RHSM
-      GO TO 620
- 580  NEWQ = NQ - 1
-      RH = RHDN
-      IF (KFLAG .LT. 0 .AND. RH .GT. 1.0D0) RH = 1.0D0
-      GO TO 620
- 590  NEWQ = L
-      RH = RHUP
-      IF (RH .LT. 1.1D0) GO TO 610
-      R = EL(L)/DBLE(L)
-      DO 600 I = 1,N
- 600    YH(I,NEWQ+1) = ACOR(I)*R
-      GO TO 630
- 610  IALTH = 3
-      GO TO 700
- 620  IF ((KFLAG .EQ. 0) .AND. (RH .LT. 1.1D0)) GO TO 610
-      IF (KFLAG .LE. -2) RH = DMIN1(RH,0.2D0)
-C-----------------------------------------------------------------------
-C IF THERE IS A CHANGE OF ORDER, RESET NQ, L, AND THE COEFFICIENTS.
-C IN ANY CASE H IS RESET ACCORDING TO RH AND THE YH ARRAY IS RESCALED.
-C THEN EXIT FROM 690 IF THE STEP WAS OK, OR REDO THE STEP OTHERWISE.
-C-----------------------------------------------------------------------
-      IF (NEWQ .EQ. NQ) GO TO 170
- 630  NQ = NEWQ
-      L = NQ + 1
-      IRET = 2
-      GO TO 150
-C-----------------------------------------------------------------------
-C CONTROL REACHES THIS SECTION IF 3 OR MORE FAILURES HAVE OCCURRED.
-C IF 10 FAILURES HAVE OCCURRED, EXIT WITH KFLAG = -1.
-C IT IS ASSUMED THAT THE DERIVATIVES THAT HAVE ACCUMULATED IN THE
-C YH ARRAY HAVE ERRORS OF THE WRONG ORDER.  HENCE THE FIRST
-C DERIVATIVE IS RECOMPUTED, AND THE ORDER IS SET TO 1.  THEN
-C H IS REDUCED BY A FACTOR OF 10, AND THE STEP IS RETRIED,
-C UNTIL IT SUCCEEDS OR H REACHES HMIN.
-C-----------------------------------------------------------------------
- 640  IF (KFLAG .EQ. -10) GO TO 660
-      RH = 0.1D0
-      RH = DMAX1(HMIN/DABS(H),RH)
-      H = H*RH
-      DO 645 I = 1,N
- 645    Y(I) = YH(I,1)
-      IERR = 0
-      CALL F (NEQ, TN, Y, SAVF, IERR)
-      IF (IERR .LT. 0) RETURN
-      NFE = NFE + 1
-      DO 650 I = 1,N
- 650    YH(I,2) = H*SAVF(I)
-      IPUP = MITER
-      IALTH = 5
-      IF (NQ .EQ. 1) GO TO 200
-      NQ = 1
-      L = 2
-      IRET = 3
-      GO TO 150
-C-----------------------------------------------------------------------
-C ALL RETURNS ARE MADE THROUGH THIS SECTION.  H IS SAVED IN HOLD
-C TO ALLOW THE CALLER TO CHANGE H ON THE NEXT STEP.
-C-----------------------------------------------------------------------
- 660  KFLAG = -1
-      GO TO 720
- 670  KFLAG = -2
-      GO TO 720
- 680  KFLAG = -3
-      GO TO 720
- 690  RMAX = 10.0D0
- 700  R = 1.0D0/TESCO(2,NQU)
-      DO 710 I = 1,N
- 710    ACOR(I) = ACOR(I)*R
- 720  HOLD = H
-      JSTART = 1
-      RETURN
-C----------------------- END OF SUBROUTINE STODE -----------------------
-      END
--- a/liboctave/external/odepack/vnorm.f	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-      DOUBLE PRECISION FUNCTION VNORM (N, V, W)
-CLLL. OPTIMIZE
-C-----------------------------------------------------------------------
-C THIS FUNCTION ROUTINE COMPUTES THE WEIGHTED ROOT-MEAN-SQUARE NORM
-C OF THE VECTOR OF LENGTH N CONTAINED IN THE ARRAY V, WITH WEIGHTS
-C CONTAINED IN THE ARRAY W OF LENGTH N..
-C   VNORM = SQRT( (1/N) * SUM( V(I)*W(I) )**2 )
-C-----------------------------------------------------------------------
-      INTEGER N,   I
-      DOUBLE PRECISION V, W,   SUM
-      DIMENSION V(N), W(N)
-      SUM = 0.0D0
-      DO 10 I = 1,N
- 10     SUM = SUM + (V(I)*W(I))**2
-      VNORM = DSQRT(SUM/DBLE(N))
-      RETURN
-C----------------------- END OF FUNCTION VNORM -------------------------
-      END
--- a/liboctave/external/slatec-err/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/external/slatec-err/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -8,6 +8,7 @@
   %reldir%/xermsg.f \
   %reldir%/xerprn.f \
   %reldir%/xerrwd.f \
+  %reldir%/xerrwv.f \
   %reldir%/xersve.f \
   %reldir%/xgetf.f \
   %reldir%/xgetua.f \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/external/slatec-err/xerrwv.f	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,96 @@
+*DECK XERRWV
+      SUBROUTINE XERRWV (MSG, NMES, NERR, LEVEL, NI, I1, I2, NR, R1, R2)
+C***BEGIN PROLOGUE  XERRWV
+C***SUBSIDIARY
+C***PURPOSE  Write error message with values.
+C***CATEGORY  R3C
+C***TYPE      SINGLE PRECISION (XERRWV-S, XERRWD-D)
+C***AUTHOR  Hindmarsh, Alan C., (LLNL)
+C***DESCRIPTION
+C
+C  Subroutines XERRWV, XSETF, XSETUN, and the function routine IXSAV,
+C  as given here, constitute a simplified version of the SLATEC error
+C  handling package.
+C
+C  All arguments are input arguments.
+C
+C  MSG    = The message (character array).
+C  NMES   = The length of MSG (number of characters).
+C  NERR   = The error number (not used).
+C  LEVEL  = The error level..
+C           0 or 1 means recoverable (control returns to caller).
+C           2 means fatal (run is aborted--see note below).
+C  NI     = Number of integers (0, 1, or 2) to be printed with message.
+C  I1,I2  = Integers to be printed, depending on NI.
+C  NR     = Number of reals (0, 1, or 2) to be printed with message.
+C  R1,R2  = Reals to be printed, depending on NR.
+C
+C  Note..  this routine is machine-dependent and specialized for use
+C  in limited context, in the following ways..
+C  1. The argument MSG is assumed to be of type CHARACTER, and
+C     the message is printed with a format of (1X,A).
+C  2. The message is assumed to take only one line.
+C     Multi-line messages are generated by repeated calls.
+C  3. If LEVEL = 2, control passes to the statement   STOP
+C     to abort the run.  This statement may be machine-dependent.
+C  4. R1 and R2 are assumed to be in single precision and are printed
+C     in E21.13 format.
+C
+C***ROUTINES CALLED  IXSAV
+C***REVISION HISTORY  (YYMMDD)
+C   791129  DATE WRITTEN
+C   890413  Heavily revised, with Common eliminated. (ACH, PNB)
+C   921118  Replaced MFLGSV/LUNSAV by IXSAV. (ACH)
+C   930329  Modified prologue to SLATEC format. (FNF)
+C   930407  Changed MSG from CHARACTER*1 array to variable. (FNF)
+C   930922  Minor cosmetic change. (FNF)
+C***END PROLOGUE  XERRWV
+C
+C*Internal Notes:
+C
+C For a different default logical unit number, IXSAV (or a subsidiary
+C routine that it calls) will need to be modified.
+C For a different run-abort command, change the statement following
+C statement 100 at the end.
+C-----------------------------------------------------------------------
+C Subroutines called by XERRWV.. None
+C Function routine called by XERRWV.. IXSAV
+C-----------------------------------------------------------------------
+C**End
+C
+C  Declare arguments.
+C
+      REAL R1, R2
+      INTEGER NMES, NERR, LEVEL, NI, I1, I2, NR
+      CHARACTER*(*) MSG
+C
+C  Declare local variables.
+C
+      INTEGER LUNIT, IXSAV, MESFLG
+C
+C  Get logical unit number and message print flag.
+C
+C***FIRST EXECUTABLE STATEMENT  XERRWV
+      LUNIT = IXSAV (1, 0, .FALSE.)
+      MESFLG = IXSAV (2, 0, .FALSE.)
+      IF (MESFLG .EQ. 0) GO TO 100
+C
+C  Write the message.
+C
+      WRITE (LUNIT,10)  MSG(1:NMES)
+ 10   FORMAT(1X,A)
+      IF (NI .EQ. 1) WRITE (LUNIT, 20) I1
+ 20   FORMAT(6X,'In above message,  I1 =',I10)
+      IF (NI .EQ. 2) WRITE (LUNIT, 30) I1,I2
+ 30   FORMAT(6X,'In above message,  I1 =',I10,3X,'I2 =',I10)
+      IF (NR .EQ. 1) WRITE (LUNIT, 40) R1
+ 40   FORMAT(6X,'In above message,  R1 =',E21.13)
+      IF (NR .EQ. 2) WRITE (LUNIT, 50) R1,R2
+ 50   FORMAT(6X,'In above,  R1 =',E21.13,3X,'R2 =',E21.13)
+C
+C  Abort the run if LEVEL = 2.
+C
+ 100  IF (LEVEL .NE. 2) RETURN
+      CALL XSTOPX (' ')
+C----------------------- End of Subroutine XERRWV ----------------------
+      END
--- a/liboctave/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -86,7 +86,7 @@
 ## to the rules in the etc/HACKING.md file:
 
 %canon_reldir%_%canon_reldir%_current = 8
-%canon_reldir%_%canon_reldir%_revision = 1
+%canon_reldir%_%canon_reldir%_revision = 0
 %canon_reldir%_%canon_reldir%_age = 0
 
 %canon_reldir%_%canon_reldir%_version_info = $(%canon_reldir%_%canon_reldir%_current):$(%canon_reldir%_%canon_reldir%_revision):$(%canon_reldir%_%canon_reldir%_age)
--- a/liboctave/numeric/CollocWt.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/CollocWt.cc	Sun May 16 09:44:35 2021 +0200
@@ -415,7 +415,6 @@
   if (wid <= 0.0)
     {
       error ("CollocWt: width less than or equal to zero");
-      return;
     }
 
   octave_idx_type nt = n + inc_left + inc_right;
--- a/liboctave/numeric/DASSL.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/DASSL.cc	Sun May 16 09:44:35 2021 +0200
@@ -232,7 +232,8 @@
           else
             {
               (*current_liboctave_error_handler)
-                ("dassl: invalid value for maximum order: %d", maxord);
+                ("dassl: invalid value for maximum order: %"
+                 OCTAVE_F77_INT_TYPE_FORMAT, maxord);
               integration_error = true;
               return retval;
             }
--- a/liboctave/numeric/ODES.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/ODES.h	Sun May 16 09:44:35 2021 +0200
@@ -67,10 +67,10 @@
 
   ColumnVector parameter_vector (void) { return theta; }
 
-  void initialize (const ColumnVector& x, double t);
+  OCTAVE_API void initialize (const ColumnVector& x, double t);
 
-  void initialize (const ColumnVector& x, double t,
-                   const ColumnVector& theta);
+  OCTAVE_API void
+  initialize (const ColumnVector& x, double t, const ColumnVector& theta);
 
 protected:
 
--- a/liboctave/numeric/aepbalance.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/aepbalance.cc	Sun May 16 09:44:35 2021 +0200
@@ -48,6 +48,7 @@
   namespace math
   {
     template <>
+    OCTAVE_API
     aepbalance<Matrix>::aepbalance (const Matrix& a, bool noperm, bool noscal)
       : balanced_mat (a), scale (), ilo (), ihi (),
         job (get_job (noperm, noscal))
@@ -72,7 +73,7 @@
     }
 
     template <>
-    Matrix
+    OCTAVE_API Matrix
     aepbalance<Matrix>::balancing_matrix (void) const
     {
       F77_INT n = to_f77_int (balanced_mat.rows ());
@@ -98,6 +99,7 @@
     }
 
     template <>
+    OCTAVE_API
     aepbalance<FloatMatrix>::aepbalance (const FloatMatrix& a, bool noperm,
                                          bool noscal)
       : balanced_mat (a), scale (), ilo (), ihi (),
@@ -123,7 +125,7 @@
     }
 
     template <>
-    FloatMatrix
+    OCTAVE_API FloatMatrix
     aepbalance<FloatMatrix>::balancing_matrix (void) const
     {
       F77_INT n = to_f77_int (balanced_mat.rows ());
@@ -149,6 +151,7 @@
     }
 
     template <>
+    OCTAVE_API
     aepbalance<ComplexMatrix>::aepbalance (const ComplexMatrix& a, bool noperm,
                                            bool noscal)
       : balanced_mat (a), scale (), ilo (), ihi (),
@@ -174,7 +177,7 @@
     }
 
     template <>
-    ComplexMatrix
+    OCTAVE_API ComplexMatrix
     aepbalance<ComplexMatrix>::balancing_matrix (void) const
     {
       F77_INT n = to_f77_int (balanced_mat.rows ());
@@ -201,6 +204,7 @@
     }
 
     template <>
+    OCTAVE_API
     aepbalance<FloatComplexMatrix>::aepbalance (const FloatComplexMatrix& a,
                                                 bool noperm, bool noscal)
       : balanced_mat (a), scale (), ilo (), ihi (),
@@ -226,7 +230,7 @@
     }
 
     template <>
-    FloatComplexMatrix
+    OCTAVE_API FloatComplexMatrix
     aepbalance<FloatComplexMatrix>::balancing_matrix (void) const
     {
       F77_INT n = to_f77_int (balanced_mat.rows ());
--- a/liboctave/numeric/aepbalance.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/aepbalance.h	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,8 @@
   namespace math
   {
     template <typename MT>
-    class aepbalance
+    class
+    aepbalance
     {
     public:
 
@@ -43,7 +44,7 @@
 
       aepbalance (void) : balanced_mat (), scale (), ilo (), ihi (), job () { }
 
-      aepbalance (const MT& a, bool noperm = false, bool noscal = false);
+      OCTAVE_API aepbalance (const MT& a, bool noperm = false, bool noscal = false);
 
       aepbalance (const aepbalance& a)
         : balanced_mat (a.balanced_mat), scale (a.scale),
@@ -66,7 +67,7 @@
 
       virtual ~aepbalance (void) = default;
 
-      MT balancing_matrix (void) const;
+      OCTAVE_API MT balancing_matrix (void) const;
 
       MT balanced_matrix (void) const
       {
--- a/liboctave/numeric/chol.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/chol.cc	Sun May 16 09:44:35 2021 +0200
@@ -406,7 +406,7 @@
     // Specializations.
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<Matrix>::init (const Matrix& a, bool upper, bool calc_cond)
     {
       octave_idx_type a_nr = a.rows ();
@@ -481,7 +481,7 @@
 #if defined (HAVE_QRUPDATE)
 
     template <>
-    void
+    OCTAVE_API void
     chol<Matrix>::update (const ColumnVector& u)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -498,7 +498,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<Matrix>::downdate (const ColumnVector& u)
     {
       F77_INT info = -1;
@@ -519,7 +519,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<Matrix>::insert_sym (const ColumnVector& u, octave_idx_type j_arg)
     {
       F77_INT info = -1;
@@ -546,7 +546,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     chol<Matrix>::delete_sym (octave_idx_type j_arg)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -563,7 +563,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     chol<Matrix>::shift_sym (octave_idx_type i_arg, octave_idx_type j_arg)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -582,7 +582,7 @@
 #endif
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<FloatMatrix>::init (const FloatMatrix& a, bool upper, bool calc_cond)
     {
       octave_idx_type a_nr = a.rows ();
@@ -657,7 +657,7 @@
 #if defined (HAVE_QRUPDATE)
 
     template <>
-    void
+    OCTAVE_API void
     chol<FloatMatrix>::update (const FloatColumnVector& u)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -674,7 +674,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<FloatMatrix>::downdate (const FloatColumnVector& u)
     {
       F77_INT info = -1;
@@ -695,7 +695,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<FloatMatrix>::insert_sym (const FloatColumnVector& u,
                                    octave_idx_type j_arg)
     {
@@ -723,7 +723,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     chol<FloatMatrix>::delete_sym (octave_idx_type j_arg)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -741,7 +741,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     chol<FloatMatrix>::shift_sym (octave_idx_type i_arg, octave_idx_type j_arg)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -760,7 +760,7 @@
 #endif
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<ComplexMatrix>::init (const ComplexMatrix& a, bool upper, bool calc_cond)
     {
       octave_idx_type a_nr = a.rows ();
@@ -834,7 +834,7 @@
 #if defined (HAVE_QRUPDATE)
 
     template <>
-    void
+    OCTAVE_API void
     chol<ComplexMatrix>::update (const ComplexColumnVector& u)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -854,7 +854,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<ComplexMatrix>::downdate (const ComplexColumnVector& u)
     {
       F77_INT info = -1;
@@ -878,7 +878,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<ComplexMatrix>::insert_sym (const ComplexColumnVector& u,
                                      octave_idx_type j_arg)
     {
@@ -909,7 +909,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     chol<ComplexMatrix>::delete_sym (octave_idx_type j_arg)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -928,7 +928,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     chol<ComplexMatrix>::shift_sym (octave_idx_type i_arg,
                                     octave_idx_type j_arg)
     {
@@ -951,7 +951,7 @@
 #endif
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<FloatComplexMatrix>::init (const FloatComplexMatrix& a, bool upper,
                                     bool calc_cond)
     {
@@ -1026,7 +1026,7 @@
 #if defined (HAVE_QRUPDATE)
 
     template <>
-    void
+    OCTAVE_API void
     chol<FloatComplexMatrix>::update (const FloatComplexColumnVector& u)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -1043,7 +1043,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<FloatComplexMatrix>::downdate (const FloatComplexColumnVector& u)
     {
       F77_INT info = -1;
@@ -1065,7 +1065,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     chol<FloatComplexMatrix>::insert_sym (const FloatComplexColumnVector& u,
                                           octave_idx_type j_arg)
     {
@@ -1095,7 +1095,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     chol<FloatComplexMatrix>::delete_sym (octave_idx_type j_arg)
     {
       F77_INT n = to_f77_int (chol_mat.rows ());
@@ -1113,7 +1113,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     chol<FloatComplexMatrix>::shift_sym (octave_idx_type i_arg,
                                          octave_idx_type j_arg)
     {
@@ -1143,16 +1143,16 @@
 
     template class chol<FloatComplexMatrix>;
 
-    template Matrix
+    template OCTAVE_API Matrix
     chol2inv<Matrix> (const Matrix& r);
 
-    template ComplexMatrix
+    template OCTAVE_API ComplexMatrix
     chol2inv<ComplexMatrix> (const ComplexMatrix& r);
 
-    template FloatMatrix
+    template OCTAVE_API FloatMatrix
     chol2inv<FloatMatrix> (const FloatMatrix& r);
 
-    template FloatComplexMatrix
+    template OCTAVE_API FloatComplexMatrix
     chol2inv<FloatComplexMatrix> (const FloatComplexMatrix& r);
   }
 }
--- a/liboctave/numeric/chol.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/chol.h	Sun May 16 09:44:35 2021 +0200
@@ -76,19 +76,19 @@
       COND_T rcond (void) const { return xrcond; }
 
       // Compute the inverse of a matrix using the Cholesky factorization.
-      T inverse (void) const;
+      OCTAVE_API T inverse (void) const;
 
-      void set (const T& R);
+      OCTAVE_API void set (const T& R);
 
-      void update (const VT& u);
+      OCTAVE_API void update (const VT& u);
 
-      octave_idx_type downdate (const VT& u);
+      OCTAVE_API octave_idx_type downdate (const VT& u);
 
-      octave_idx_type insert_sym (const VT& u, octave_idx_type j);
+      OCTAVE_API octave_idx_type insert_sym (const VT& u, octave_idx_type j);
 
-      void delete_sym (octave_idx_type j);
+      OCTAVE_API void delete_sym (octave_idx_type j);
 
-      void shift_sym (octave_idx_type i, octave_idx_type j);
+      OCTAVE_API void shift_sym (octave_idx_type i, octave_idx_type j);
 
     private:
 
@@ -98,11 +98,11 @@
 
       bool is_upper;
 
-      octave_idx_type init (const T& a, bool upper, bool calc_cond);
+      OCTAVE_API octave_idx_type init (const T& a, bool upper, bool calc_cond);
     };
 
     template <typename T>
-    T
+    OCTAVE_API T
     chol2inv (const T& r);
   }
 }
--- a/liboctave/numeric/eigs-base.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/eigs-base.cc	Sun May 16 09:44:35 2021 +0200
@@ -3944,7 +3944,7 @@
 // Matrix
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricMatrix<Matrix>
   (const Matrix& m, const std::string typ, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, Matrix& eig_vec,
@@ -3953,7 +3953,7 @@
    bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricMatrixShift<Matrix>
   (const Matrix& m, double sigma, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, Matrix& eig_vec,
@@ -3962,7 +3962,7 @@
    bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricFunc<Matrix>
 (EigsFunc fun, octave_idx_type n, const std::string& _typ, double sigma,
    octave_idx_type k, octave_idx_type p, octave_idx_type& info,
@@ -3971,7 +3971,7 @@
    bool rvec, bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricMatrix<Matrix>
   (const Matrix& m, const std::string typ, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -3980,7 +3980,7 @@
    bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricMatrixShift<Matrix>
   (const Matrix& m, double sigmar, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -3989,7 +3989,7 @@
    bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricFunc<Matrix>
 (EigsFunc fun, octave_idx_type n, const std::string& _typ, double sigmar,
    octave_idx_type k, octave_idx_type p, octave_idx_type& info,
@@ -4000,7 +4000,7 @@
 // SparseMatrix
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricMatrix<SparseMatrix>
   (const SparseMatrix& m, const std::string typ, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, Matrix& eig_vec,
@@ -4009,7 +4009,7 @@
    bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricMatrixShift<SparseMatrix>
   (const SparseMatrix& m, double sigma, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, Matrix& eig_vec,
@@ -4018,7 +4018,7 @@
    bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricFunc<SparseMatrix>
 (EigsFunc fun, octave_idx_type n, const std::string& _typ, double sigma,
    octave_idx_type k, octave_idx_type p, octave_idx_type& info,
@@ -4027,7 +4027,7 @@
    bool rvec, bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricMatrix<SparseMatrix>
   (const SparseMatrix& m, const std::string typ, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -4036,7 +4036,7 @@
    bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricMatrixShift<SparseMatrix>
   (const SparseMatrix& m, double sigmar, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -4045,7 +4045,7 @@
    bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricFunc<SparseMatrix>
 (EigsFunc fun, octave_idx_type n, const std::string& _typ, double sigmar,
    octave_idx_type k, octave_idx_type p, octave_idx_type& info,
@@ -4056,7 +4056,7 @@
 // ComplexMatrix
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricMatrix<ComplexMatrix>
   (const ComplexMatrix& m, const std::string typ, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -4065,7 +4065,7 @@
    bool rvec, bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricMatrixShift<ComplexMatrix>
   (const ComplexMatrix& m, Complex sigma, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -4074,7 +4074,7 @@
    bool rvec, bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricFunc<ComplexMatrix>
 (EigsComplexFunc fun, octave_idx_type n, const std::string& _typ, Complex sigma,
    octave_idx_type k, octave_idx_type p, octave_idx_type& info,
@@ -4085,7 +4085,7 @@
 // SparseComplexMatrix
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricMatrix<SparseComplexMatrix>
   (const SparseComplexMatrix& m, const std::string typ, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -4094,7 +4094,7 @@
    double tol, bool rvec, bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricMatrixShift<SparseComplexMatrix>
   (const SparseComplexMatrix& m, Complex sigma, octave_idx_type k,
    octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -4103,7 +4103,7 @@
    double tol, bool rvec, bool cholB, int disp, int maxit);
 
 template
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricFunc<SparseComplexMatrix>
 (EigsComplexFunc fun, octave_idx_type n, const std::string& _typ, Complex sigma,
    octave_idx_type k, octave_idx_type p, octave_idx_type& info,
--- a/liboctave/numeric/eigs-base.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/eigs-base.h	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,7 @@
 
 #include "octave-config.h"
 
+#include <functional>
 #include <iosfwd>
 #include <string>
 
@@ -38,13 +39,15 @@
 class Matrix;
 class ComplexMatrix;
 
-typedef ColumnVector (*EigsFunc) (const ColumnVector& x, int& eigs_error);
+typedef
+std::function<ColumnVector (const ColumnVector& x, int& eigs_error)> EigsFunc;
 
-typedef ComplexColumnVector (*EigsComplexFunc) (const ComplexColumnVector& x,
-                                                int& eigs_error);
+typedef
+std::function<ComplexColumnVector
+              (const ComplexColumnVector& x, int& eigs_error)> EigsComplexFunc;
 
 template <typename M>
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricMatrix (const M& m, const std::string typ,
                          octave_idx_type k, octave_idx_type p,
                          octave_idx_type& info, Matrix& eig_vec,
@@ -54,7 +57,7 @@
                          bool cholB, int disp, int maxit);
 
 template <typename M>
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricMatrixShift (const M& m, double sigma,
                               octave_idx_type k, octave_idx_type p,
                               octave_idx_type& info, Matrix& eig_vec,
@@ -64,7 +67,7 @@
                               bool cholB, int disp, int maxit);
 
 template <typename M>
-extern OCTAVE_API octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealSymmetricFunc (EigsFunc fun, octave_idx_type n,
                        const std::string& _typ, double sigma,
                        octave_idx_type k, octave_idx_type p,
@@ -75,7 +78,7 @@
                        bool cholB, int disp, int maxit);
 
 template <typename M>
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricMatrix (const M& m, const std::string typ,
                             octave_idx_type k, octave_idx_type p,
                             octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -85,7 +88,7 @@
                             bool cholB, int disp, int maxit);
 
 template <typename M>
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricMatrixShift (const M& m, double sigmar,
                                  octave_idx_type k, octave_idx_type p,
                                  octave_idx_type& info,
@@ -96,7 +99,7 @@
                                  bool cholB, int disp, int maxit);
 
 template <typename M>
-extern OCTAVE_API octave_idx_type
+OCTAVE_API octave_idx_type
 EigsRealNonSymmetricFunc (EigsFunc fun, octave_idx_type n,
                           const std::string& _typ, double sigmar,
                           octave_idx_type k, octave_idx_type p,
@@ -107,7 +110,7 @@
                           bool cholB, int disp, int maxit);
 
 template <typename M>
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricMatrix (const M& m, const std::string typ,
                                octave_idx_type k, octave_idx_type p,
                                octave_idx_type& info, ComplexMatrix& eig_vec,
@@ -118,7 +121,7 @@
                                bool cholB, int disp, int maxit);
 
 template <typename M>
-octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricMatrixShift (const M& m, Complex sigma,
                                     octave_idx_type k, octave_idx_type p,
                                     octave_idx_type& info,
@@ -130,7 +133,7 @@
                                     bool cholB, int disp, int maxit);
 
 template <typename M>
-extern OCTAVE_API octave_idx_type
+OCTAVE_API octave_idx_type
 EigsComplexNonSymmetricFunc (EigsComplexFunc fun, octave_idx_type n,
                              const std::string& _typ, Complex sigma,
                              octave_idx_type k, octave_idx_type p,
--- a/liboctave/numeric/gepbalance.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/gepbalance.cc	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,7 @@
   namespace math
   {
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     gepbalance<Matrix>::init (const Matrix& a, const Matrix& b,
                               const std::string& balance_job)
     {
@@ -108,7 +108,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     gepbalance<FloatMatrix>::init (const FloatMatrix& a, const FloatMatrix& b,
                                    const std::string& balance_job)
     {
@@ -174,7 +174,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     gepbalance<ComplexMatrix>::init (const ComplexMatrix& a,
                                      const ComplexMatrix& b,
                                      const std::string& balance_job)
@@ -242,7 +242,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     gepbalance<FloatComplexMatrix>::init (const FloatComplexMatrix& a,
                                           const FloatComplexMatrix& b,
                                           const std::string& balance_job)
--- a/liboctave/numeric/gepbalance.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/gepbalance.h	Sun May 16 09:44:35 2021 +0200
@@ -87,7 +87,8 @@
       RT balancing_mat;
       RT balancing_mat2;
 
-      octave_idx_type init (const T& a, const T& b, const std::string& job);
+      OCTAVE_API octave_idx_type
+      init (const T& a, const T& b, const std::string& job);
     };
   }
 }
--- a/liboctave/numeric/gsvd.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/gsvd.cc	Sun May 16 09:44:35 2021 +0200
@@ -585,8 +585,9 @@
                       info);
 
       if (info < 0)
-        (*current_liboctave_error_handler) ("*ggsvd.f: argument %d illegal",
-                                            -info);
+        (*current_liboctave_error_handler)
+          ("*ggsvd.f: argument %" OCTAVE_F77_INT_TYPE_FORMAT " illegal",
+           -info);
       else
         {
           if (info > 0)
--- a/liboctave/numeric/gsvd.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/gsvd.h	Sun May 16 09:44:35 2021 +0200
@@ -34,6 +34,7 @@
   {
     template <typename T>
     class
+    OCTAVE_API
     gsvd
     {
     public:
--- a/liboctave/numeric/hess.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/hess.cc	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
   namespace math
   {
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     hess<Matrix>::init (const Matrix& a)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
@@ -104,7 +104,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     hess<FloatMatrix>::init (const FloatMatrix& a)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
@@ -167,7 +167,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     hess<ComplexMatrix>::init (const ComplexMatrix& a)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
@@ -230,7 +230,7 @@
     }
 
     template <>
-    octave_idx_type
+    OCTAVE_API octave_idx_type
     hess<FloatComplexMatrix>::init (const FloatComplexMatrix& a)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
--- a/liboctave/numeric/hess.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/hess.h	Sun May 16 09:44:35 2021 +0200
@@ -82,11 +82,11 @@
       T hess_mat;
       T unitary_hess_mat;
 
-      octave_idx_type init (const T& a);
+      OCTAVE_API octave_idx_type init (const T& a);
     };
 
     template <typename T>
-    extern std::ostream&
+    extern OCTAVE_API std::ostream&
     operator << (std::ostream& os, const hess<T>& a);
   }
 }
--- a/liboctave/numeric/lo-blas-proto.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/lo-blas-proto.h	Sun May 16 09:44:35 2021 +0200
@@ -205,6 +205,7 @@
 
   // XERBLA
 
+  OCTAVE_API
   F77_RET_T
   F77_FUNC (xerbla, XERBLA) (F77_CONST_CHAR_ARG_DECL, const F77_INT&
                              F77_CHAR_ARG_LEN_DECL);
--- a/liboctave/numeric/lo-lapack-proto.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/lo-lapack-proto.h	Sun May 16 09:44:35 2021 +0200
@@ -266,6 +266,124 @@
                              F77_DBLE_CMPLX*, F77_DBLE_CMPLX*,
                              const F77_INT&, F77_INT&);
 
+  // GELQF
+
+  F77_RET_T
+  F77_FUNC (cgelqf, CGELQF) (const F77_INT&, const F77_INT&,
+                             F77_CMPLX*, const F77_INT&,
+                             F77_CMPLX*, F77_CMPLX*,
+                             const F77_INT&, F77_INT&);
+
+  F77_RET_T
+  F77_FUNC (dgelqf, DGELQF) (const F77_INT&, const F77_INT&,
+                             F77_DBLE*, const F77_INT&,
+                             F77_DBLE*, F77_DBLE*,
+                             const F77_INT&, F77_INT&);
+
+  F77_RET_T
+  F77_FUNC (sgelqf, SGELQF) (const F77_INT&, const F77_INT&,
+                             F77_REAL*, const F77_INT&,
+                             F77_REAL*, F77_REAL*,
+                             const F77_INT&, F77_INT&);
+
+  F77_RET_T
+  F77_FUNC (zgelqf, ZGELQF) (const F77_INT&, const F77_INT&,
+                             F77_DBLE_CMPLX*, const F77_INT&,
+                             F77_DBLE_CMPLX*, F77_DBLE_CMPLX*,
+                             const F77_INT&, F77_INT&);
+
+  // ORMLQ
+
+  F77_RET_T
+  F77_FUNC (cormlq, CORMLQ) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&, const F77_INT&,
+                             F77_CMPLX*, const F77_INT&,
+                             F77_CMPLX*, F77_CMPLX*,
+                             const F77_INT&, F77_CMPLX*,
+                             const F77_INT&, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (dormlq, DORMLQ) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&, const F77_INT&,
+                             F77_DBLE*, const F77_INT&,
+                             F77_DBLE*, F77_DBLE*,
+                             const F77_INT&, F77_DBLE*,
+                             const F77_INT&, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (sormlq, SORMLQ) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&, const F77_INT&,
+                             F77_REAL*, const F77_INT&,
+                             F77_REAL*, F77_REAL*,
+                             const F77_INT&, F77_REAL*,
+                             const F77_INT&, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (zormlq, ZORMLQ) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&, const F77_INT&,
+                             F77_DBLE_CMPLX*, const F77_INT&,
+                             F77_DBLE_CMPLX*, F77_DBLE_CMPLX*,
+                             const F77_INT&, F77_DBLE_CMPLX*,
+                             const F77_INT&, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  // ORMQR
+
+  F77_RET_T
+  F77_FUNC (cormqr, CORMQR) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&, const F77_INT&,
+                             F77_CMPLX*, const F77_INT&,
+                             F77_CMPLX*, F77_CMPLX*,
+                             const F77_INT&, F77_CMPLX*,
+                             const F77_INT&, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (dormqr, DORMQR) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&, const F77_INT&,
+                             F77_DBLE*, const F77_INT&,
+                             F77_DBLE*, F77_DBLE*,
+                             const F77_INT&, F77_DBLE*,
+                             const F77_INT&, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (sormqr, SORMQR) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&, const F77_INT&,
+                             F77_REAL*, const F77_INT&,
+                             F77_REAL*, F77_REAL*,
+                             const F77_INT&, F77_REAL*,
+                             const F77_INT&, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (zormqr, ZORMQR) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&, const F77_INT&,
+                             F77_DBLE_CMPLX*, const F77_INT&,
+                             F77_DBLE_CMPLX*, F77_DBLE_CMPLX*,
+                             const F77_INT&, F77_DBLE_CMPLX*,
+                             const F77_INT&, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
   // GESDD
 
   F77_RET_T
@@ -354,6 +472,90 @@
                              F77_CHAR_ARG_LEN_DECL
                              F77_CHAR_ARG_LEN_DECL);
 
+  // GEJSV
+
+  F77_RET_T
+  F77_FUNC (cgejsv, CGEJSV) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&,
+                             F77_CMPLX*, const F77_INT&, F77_REAL*,
+                             F77_CMPLX*, const F77_INT&,
+                             F77_CMPLX*, const F77_INT&,
+                             F77_CMPLX*, const F77_INT&,
+                             F77_REAL*,  const F77_INT&,
+                             F77_INT *, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (dgejsv, DGEJSV) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&,
+                             F77_DBLE*, const F77_INT&, F77_DBLE*,
+                             F77_DBLE*, const F77_INT&,
+                             F77_DBLE*, const F77_INT&,
+                             F77_DBLE*, const F77_INT&,
+                             F77_INT *, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (sgejsv, SGEJSV) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&,
+                             F77_REAL*, const F77_INT&, F77_REAL*,
+                             F77_REAL*, const F77_INT&,
+                             F77_REAL*, const F77_INT&,
+                             F77_REAL*, const F77_INT&,
+                             F77_INT *, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
+  F77_RET_T
+  F77_FUNC (zgejsv, ZGEJSV) (F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             F77_CONST_CHAR_ARG_DECL,
+                             const F77_INT&, const F77_INT&,
+                             F77_DBLE_CMPLX*, const F77_INT&, F77_DBLE*,
+                             F77_DBLE_CMPLX*, const F77_INT&,
+                             F77_DBLE_CMPLX*, const F77_INT&,
+                             F77_DBLE_CMPLX*, const F77_INT&,
+                             F77_DBLE*,       const F77_INT&,
+                             F77_INT *, F77_INT&
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL
+                             F77_CHAR_ARG_LEN_DECL);
+
   // GEESX
 
   typedef F77_INT (*double_selector) (const F77_DBLE&, const F77_DBLE&);
@@ -1640,6 +1842,32 @@
                              const F77_INT& LIWORK,
                              F77_INT& INFO);
 
+  F77_RET_T
+  F77_FUNC (ztgsen, ZTGSEN) (const F77_INT& IJOB,
+                             const F77_LOGICAL& WANTQ,
+                             const F77_LOGICAL& WANTZ,
+                             const F77_LOGICAL *SELECT,
+                             const F77_INT& N,
+                             F77_DBLE_CMPLX *A,
+                             const F77_INT& LDA,
+                             F77_DBLE_CMPLX *B,
+                             const F77_INT& LDB,
+                             F77_DBLE_CMPLX *ALPHA,
+                             F77_DBLE_CMPLX *BETA,
+                             F77_DBLE_CMPLX *Q,
+                             const F77_INT& LDQ,
+                             F77_DBLE_CMPLX *Z,
+                             const F77_INT& LDZ,
+                             F77_INT& M,
+                             F77_DBLE& PL,
+                             F77_DBLE& PR,
+                             F77_DBLE *DIF,
+                             F77_DBLE_CMPLX *WORK,
+                             const F77_INT& LWORK,
+                             F77_INT *IWORK,
+                             const F77_INT& LIWORK,
+                             F77_INT& INFO);
+
   // TRCON
 
   F77_RET_T
--- a/liboctave/numeric/lo-mappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/lo-mappers.h	Sun May 16 09:44:35 2021 +0200
@@ -203,6 +203,13 @@
     inline bool isinf (double x) { return std::isinf (x); }
     inline bool isinf (float x) { return std::isinf (x); }
 
+    template <typename T>
+    bool
+    isinf (const octave_int<T>&)
+    {
+      return false;
+    }
+
     // FIXME: Do we need isinf overload for complex?
     template <typename T>
     bool
--- a/liboctave/numeric/lu.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/lu.cc	Sun May 16 09:44:35 2021 +0200
@@ -270,6 +270,7 @@
     // Specializations.
 
     template <>
+    OCTAVE_API
     lu<Matrix>::lu (const Matrix& a)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
@@ -293,7 +294,7 @@
 #if defined (HAVE_QRUPDATE_LUU)
 
     template <>
-    void
+    OCTAVE_API void
     lu<Matrix>::update (const ColumnVector& u, const ColumnVector& v)
     {
       if (packed ())
@@ -319,7 +320,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<Matrix>::update (const Matrix& u, const Matrix& v)
     {
       if (packed ())
@@ -352,7 +353,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<Matrix>::update_piv (const ColumnVector& u, const ColumnVector& v)
     {
       if (packed ())
@@ -383,7 +384,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<Matrix>::update_piv (const Matrix& u, const Matrix& v)
     {
       if (packed ())
@@ -422,6 +423,7 @@
 #endif
 
     template <>
+    OCTAVE_API
     lu<FloatMatrix>::lu (const FloatMatrix& a)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
@@ -445,7 +447,7 @@
 #if defined (HAVE_QRUPDATE_LUU)
 
     template <>
-    void
+    OCTAVE_API void
     lu<FloatMatrix>::update (const FloatColumnVector& u,
                              const FloatColumnVector& v)
     {
@@ -473,7 +475,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<FloatMatrix>::update (const FloatMatrix& u, const FloatMatrix& v)
     {
       if (packed ())
@@ -506,7 +508,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<FloatMatrix>::update_piv (const FloatColumnVector& u,
                                  const FloatColumnVector& v)
     {
@@ -538,7 +540,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<FloatMatrix>::update_piv (const FloatMatrix& u, const FloatMatrix& v)
     {
       if (packed ())
@@ -577,6 +579,7 @@
 #endif
 
     template <>
+    OCTAVE_API
     lu<ComplexMatrix>::lu (const ComplexMatrix& a)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
@@ -601,7 +604,7 @@
 #if defined (HAVE_QRUPDATE_LUU)
 
     template <>
-    void
+    OCTAVE_API void
     lu<ComplexMatrix>::update (const ComplexColumnVector& u,
                                const ComplexColumnVector& v)
     {
@@ -630,7 +633,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<ComplexMatrix>::update (const ComplexMatrix& u, const ComplexMatrix& v)
     {
       if (packed ())
@@ -666,7 +669,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<ComplexMatrix>::update_piv (const ComplexColumnVector& u,
                                    const ComplexColumnVector& v)
     {
@@ -700,7 +703,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<ComplexMatrix>::update_piv (const ComplexMatrix& u,
                                    const ComplexMatrix& v)
     {
@@ -744,6 +747,7 @@
 #endif
 
     template <>
+    OCTAVE_API
     lu<FloatComplexMatrix>::lu (const FloatComplexMatrix& a)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
@@ -768,7 +772,7 @@
 #if defined (HAVE_QRUPDATE_LUU)
 
     template <>
-    void
+    OCTAVE_API void
     lu<FloatComplexMatrix>::update (const FloatComplexColumnVector& u,
                                     const FloatComplexColumnVector& v)
     {
@@ -797,7 +801,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<FloatComplexMatrix>::update (const FloatComplexMatrix& u,
                                     const FloatComplexMatrix& v)
     {
@@ -832,7 +836,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<FloatComplexMatrix>::update_piv (const FloatComplexColumnVector& u,
                                         const FloatComplexColumnVector& v)
     {
@@ -866,7 +870,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     lu<FloatComplexMatrix>::update_piv (const FloatComplexMatrix& u,
                                         const FloatComplexMatrix& v)
     {
--- a/liboctave/numeric/lu.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/lu.h	Sun May 16 09:44:35 2021 +0200
@@ -49,12 +49,12 @@
       lu (void)
         : a_fact (), l_fact (), ipvt () { }
 
-      lu (const T& a);
+      OCTAVE_API lu (const T& a);
 
       lu (const lu& a)
         : a_fact (a.a_fact), l_fact (a.l_fact), ipvt (a.ipvt) { }
 
-      lu (const T& l, const T& u, const PermMatrix& p);
+      OCTAVE_API lu (const T& l, const T& u, const PermMatrix& p);
 
       lu& operator = (const lu& a)
       {
@@ -70,35 +70,35 @@
 
       virtual ~lu (void) = default;
 
-      bool packed (void) const;
+      OCTAVE_API bool packed (void) const;
 
-      void unpack (void);
+      OCTAVE_API void unpack (void);
 
-      T L (void) const;
+      OCTAVE_API T L (void) const;
 
-      T U (void) const;
+      OCTAVE_API T U (void) const;
 
-      T Y (void) const;
+      OCTAVE_API T Y (void) const;
 
-      PermMatrix P (void) const;
+      OCTAVE_API PermMatrix P (void) const;
 
-      ColumnVector P_vec (void) const;
+      OCTAVE_API ColumnVector P_vec (void) const;
 
-      bool regular (void) const;
+      OCTAVE_API bool regular (void) const;
 
-      void update (const VT& u, const VT& v);
+      OCTAVE_API void update (const VT& u, const VT& v);
 
-      void update (const T& u, const T& v);
+      OCTAVE_API void update (const T& u, const T& v);
 
-      void update_piv (const VT& u, const VT& v);
+      OCTAVE_API void update_piv (const VT& u, const VT& v);
 
-      void update_piv (const T& u, const T& v);
+      OCTAVE_API void update_piv (const T& u, const T& v);
 
     protected:
 
       // The result of getp is passed to other Octave Matrix functions,
       // so we use octave_idx_type.
-      Array<octave_idx_type> getp (void) const;
+      OCTAVE_API Array<octave_idx_type> getp (void) const;
 
       T a_fact;
       T l_fact;
--- a/liboctave/numeric/oct-convn.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/oct-convn.cc	Sun May 16 09:44:35 2021 +0200
@@ -168,10 +168,10 @@
   if (ct == convn_same)
     {
       // Pick the relevant part.
-      Array<idx_vector> sidx (dim_vector (nd, 1));
+      Array<octave::idx_vector> sidx (dim_vector (nd, 1));
 
       for (int i = 0; i < nd; i++)
-        sidx(i) = idx_vector::make_range (bdims(i)/2, 1, adims(i));
+        sidx(i) = octave::idx_vector::make_range (bdims(i)/2, 1, adims(i));
       c = c.index (sidx);
     }
 
--- a/liboctave/numeric/oct-rand.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/oct-rand.cc	Sun May 16 09:44:35 2021 +0200
@@ -291,7 +291,7 @@
   }
 
   template <>
-  double rand::uniform<double> (void)
+  OCTAVE_API double rand::uniform<double> (void)
   {
     double retval;
 
@@ -304,7 +304,7 @@
   }
 
   template <>
-  double rand::normal<double> (void)
+  OCTAVE_API double rand::normal<double> (void)
   {
     double retval;
 
@@ -317,7 +317,7 @@
   }
 
   template <>
-  double rand::exponential<double> (void)
+  OCTAVE_API double rand::exponential<double> (void)
   {
     double retval;
 
@@ -330,7 +330,7 @@
   }
 
   template <>
-  double rand::poisson<double> (double a)
+  OCTAVE_API double rand::poisson<double> (double a)
   {
     double retval;
 
@@ -352,7 +352,7 @@
   }
 
   template <>
-  double rand::gamma<double> (double a)
+  OCTAVE_API double rand::gamma<double> (double a)
   {
     double retval;
 
@@ -370,7 +370,7 @@
   }
 
   template <>
-  float rand::uniform<float> (void)
+  OCTAVE_API float rand::uniform<float> (void)
   {
     float retval;
 
@@ -383,7 +383,7 @@
   }
 
   template <>
-  float rand::normal<float> (void)
+  OCTAVE_API float rand::normal<float> (void)
   {
     float retval;
 
@@ -396,7 +396,7 @@
   }
 
   template <>
-  float rand::exponential<float> (void)
+  OCTAVE_API float rand::exponential<float> (void)
   {
     float retval;
 
@@ -409,7 +409,7 @@
   }
 
   template <>
-  float rand::poisson<float> (float a)
+  OCTAVE_API float rand::poisson<float> (float a)
   {
     float retval;
 
@@ -434,7 +434,7 @@
   }
 
   template <>
-  float rand::gamma<float> (float a)
+  OCTAVE_API float rand::gamma<float> (float a)
   {
     float retval;
 
@@ -490,8 +490,8 @@
     return retval;
   }
 
-  template double rand::do_scalar<double> (double);
-  template float rand::do_scalar<float> (float);
+  template OCTAVE_API double rand::do_scalar<double> (double);
+  template OCTAVE_API float rand::do_scalar<float> (float);
 
   template <typename T>
   Array<T>
@@ -511,8 +511,10 @@
     return retval;
   }
 
-  template Array<double> rand::do_vector<double> (octave_idx_type, double);
-  template Array<float> rand::do_vector<float> (octave_idx_type, float);
+  template OCTAVE_API Array<double>
+  rand::do_vector<double> (octave_idx_type, double);
+  template OCTAVE_API Array<float>
+  rand::do_vector<float> (octave_idx_type, float);
 
   NDArray rand::do_nd_array (const dim_vector& dims, double a)
   {
--- a/liboctave/numeric/oct-rand.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/oct-rand.h	Sun May 16 09:44:35 2021 +0200
@@ -45,7 +45,7 @@
   {
   protected:
 
-    rand (void);
+    OCTAVE_API rand (void);
 
   public:
 
@@ -207,86 +207,88 @@
     std::map<int, uint32NDArray> rand_states;
 
     // Return the current seed.
-    double do_seed (void);
+    OCTAVE_API double do_seed (void);
 
     // Set the seed.
-    void do_seed (double s);
+    OCTAVE_API void do_seed (double s);
 
     // Reset the seed.
-    void do_reset ();
+    OCTAVE_API void do_reset ();
 
     // Return the current state.
-    uint32NDArray do_state (const std::string& d);
+    OCTAVE_API uint32NDArray do_state (const std::string& d);
 
     // Set the current state/
-    void do_state (const uint32NDArray& s, const std::string& d);
+    OCTAVE_API void do_state (const uint32NDArray& s, const std::string& d);
 
     // Reset the current state/
-    void do_reset (const std::string& d);
+    OCTAVE_API void do_reset (const std::string& d);
 
     // Return the current distribution.
-    std::string do_distribution (void);
+    OCTAVE_API std::string do_distribution (void);
 
     // Set the current distribution.  May be either "uniform" (the
     // default), "normal", "exponential", "poisson", or "gamma".
-    void do_distribution (const std::string& d);
+    OCTAVE_API void do_distribution (const std::string& d);
 
-    void do_uniform_distribution (void);
+    OCTAVE_API void do_uniform_distribution (void);
 
-    void do_normal_distribution (void);
+    OCTAVE_API void do_normal_distribution (void);
 
-    void do_exponential_distribution (void);
+    OCTAVE_API void do_exponential_distribution (void);
 
-    void do_poisson_distribution (void);
+    OCTAVE_API void do_poisson_distribution (void);
 
-    void do_gamma_distribution (void);
+    OCTAVE_API void do_gamma_distribution (void);
 
     // The following templates only make sense for double and float
     // types.
 
-    template <typename T> T uniform (void);
+    template <typename T> OCTAVE_API T uniform (void);
 
-    template <typename T> T normal (void);
+    template <typename T> OCTAVE_API T normal (void);
 
-    template <typename T> T exponential (void);
+    template <typename T> OCTAVE_API T exponential (void);
 
-    template <typename T> T poisson (T a);
+    template <typename T> OCTAVE_API T poisson (T a);
 
-    template <typename T> T gamma (T a);
+    template <typename T> OCTAVE_API T gamma (T a);
 
     // Return the next number from the sequence.
-    template <typename T> T do_scalar (T a = 1);
+    template <typename T> OCTAVE_API T do_scalar (T a = 1);
 
     // Return an array of numbers from the sequence.
-    template <typename T> Array<T> do_vector (octave_idx_type n, T a = 1);
+    template <typename T> OCTAVE_API Array<T>
+    do_vector (octave_idx_type n, T a = 1);
 
     // Return an N-dimensional array of numbers from the sequence,
     // filled in column major order.
-    NDArray do_nd_array (const dim_vector& dims, double a = 1.);
+    OCTAVE_API NDArray do_nd_array (const dim_vector& dims, double a = 1.);
 
     // Return an N-dimensional array of numbers from the sequence,
     // filled in column major order.
-    FloatNDArray do_float_nd_array (const dim_vector& dims, float a = 1.);
+    OCTAVE_API FloatNDArray
+    do_float_nd_array (const dim_vector& dims, float a = 1.);
 
     // Some helper functions.
 
-    void initialize_ranlib_generators (void);
+    OCTAVE_API void initialize_ranlib_generators (void);
 
-    void initialize_mersenne_twister (void);
+    OCTAVE_API void initialize_mersenne_twister (void);
 
-    uint32NDArray get_internal_state (void);
+    OCTAVE_API uint32NDArray get_internal_state (void);
 
-    void save_state (void);
+    OCTAVE_API void save_state (void);
 
-    int get_dist_id (const std::string& d);
+    OCTAVE_API int get_dist_id (const std::string& d);
 
-    void set_internal_state (const uint32NDArray& s);
+    OCTAVE_API void set_internal_state (const uint32NDArray& s);
 
-    void switch_to_generator (int dist);
+    OCTAVE_API void switch_to_generator (int dist);
 
-    void fill (octave_idx_type len, double *v, double a);
+    OCTAVE_API void fill (octave_idx_type len, double *v, double a);
 
-    void fill (octave_idx_type len, float *v, float a);
+    OCTAVE_API void fill (octave_idx_type len, float *v, float a);
   };
 }
 
--- a/liboctave/numeric/qr.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/qr.cc	Sun May 16 09:44:35 2021 +0200
@@ -378,7 +378,7 @@
     // Specializations.
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::form (octave_idx_type n_arg, Matrix& afact, double *tau,
                       type qr_type)
     {
@@ -449,7 +449,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::init (const Matrix& a, type qr_type)
     {
       F77_INT m = to_f77_int (a.rows ());
@@ -485,7 +485,7 @@
 #if defined (HAVE_QRUPDATE)
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::update (const ColumnVector& u, const ColumnVector& v)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -507,7 +507,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::update (const Matrix& u, const Matrix& v)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -535,7 +535,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::insert_col (const ColumnVector& u, octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -571,7 +571,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::insert_col (const Matrix& u, const Array<octave_idx_type>& j)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -629,7 +629,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::delete_col (octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -658,7 +658,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::delete_col (const Array<octave_idx_type>& j)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -708,7 +708,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::insert_row (const RowVector& u, octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -740,7 +740,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::delete_row (octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -766,7 +766,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<Matrix>::shift_cols (octave_idx_type i_arg, octave_idx_type j_arg)
     {
       F77_INT i = to_f77_int (i_arg);
@@ -792,7 +792,7 @@
 #endif
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::form (octave_idx_type n_arg, FloatMatrix& afact,
                            float *tau, type qr_type)
     {
@@ -863,7 +863,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::init (const FloatMatrix& a, type qr_type)
     {
       F77_INT m = to_f77_int (a.rows ());
@@ -899,7 +899,7 @@
 #if defined (HAVE_QRUPDATE)
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::update (const FloatColumnVector& u, const FloatColumnVector& v)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -921,7 +921,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::update (const FloatMatrix& u, const FloatMatrix& v)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -949,7 +949,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::insert_col (const FloatColumnVector& u,
                                  octave_idx_type j_arg)
     {
@@ -986,7 +986,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::insert_col (const FloatMatrix& u,
                                  const Array<octave_idx_type>& j)
     {
@@ -1045,7 +1045,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::delete_col (octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -1074,7 +1074,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::delete_col (const Array<octave_idx_type>& j)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -1124,7 +1124,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::insert_row (const FloatRowVector& u,
                                  octave_idx_type j_arg)
     {
@@ -1157,7 +1157,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::delete_row (octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -1184,7 +1184,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatMatrix>::shift_cols (octave_idx_type i_arg, octave_idx_type j_arg)
     {
       F77_INT i = to_f77_int (i_arg);
@@ -1210,7 +1210,7 @@
 #endif
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::form (octave_idx_type n_arg, ComplexMatrix& afact,
                              Complex *tau, type qr_type)
     {
@@ -1287,7 +1287,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::init (const ComplexMatrix& a, type qr_type)
     {
       F77_INT m = to_f77_int (a.rows ());
@@ -1327,7 +1327,7 @@
 #if defined (HAVE_QRUPDATE)
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::update (const ComplexColumnVector& u,
                                const ComplexColumnVector& v)
     {
@@ -1353,7 +1353,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::update (const ComplexMatrix& u, const ComplexMatrix& v)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -1385,7 +1385,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::insert_col (const ComplexColumnVector& u,
                                    octave_idx_type j_arg)
     {
@@ -1423,7 +1423,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::insert_col (const ComplexMatrix& u,
                                    const Array<octave_idx_type>& j)
     {
@@ -1485,7 +1485,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::delete_col (octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -1515,7 +1515,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::delete_col (const Array<octave_idx_type>& j)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -1566,7 +1566,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::insert_row (const ComplexRowVector& u,
                                    octave_idx_type j_arg)
     {
@@ -1600,7 +1600,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::delete_row (octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -1628,7 +1628,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<ComplexMatrix>::shift_cols (octave_idx_type i_arg,
                                    octave_idx_type j_arg)
     {
@@ -1656,7 +1656,7 @@
 #endif
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::form (octave_idx_type n_arg, FloatComplexMatrix& afact,
                                   FloatComplex *tau, type qr_type)
     {
@@ -1731,7 +1731,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::init (const FloatComplexMatrix& a, type qr_type)
     {
       F77_INT m = to_f77_int (a.rows ());
@@ -1769,7 +1769,7 @@
 #if defined (HAVE_QRUPDATE)
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::update (const FloatComplexColumnVector& u,
                                     const FloatComplexColumnVector& v)
     {
@@ -1795,7 +1795,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::update (const FloatComplexMatrix& u,
                                     const FloatComplexMatrix& v)
     {
@@ -1827,7 +1827,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::insert_col (const FloatComplexColumnVector& u,
                                         octave_idx_type j_arg)
     {
@@ -1864,7 +1864,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::insert_col (const FloatComplexMatrix& u,
                                         const Array<octave_idx_type>& j)
     {
@@ -1924,7 +1924,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::delete_col (octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -1954,7 +1954,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::delete_col (const Array<octave_idx_type>& j)
     {
       F77_INT m = to_f77_int (q.rows ());
@@ -2004,7 +2004,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::insert_row (const FloatComplexRowVector& u,
                                         octave_idx_type j_arg)
     {
@@ -2038,7 +2038,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::delete_row (octave_idx_type j_arg)
     {
       F77_INT j = to_f77_int (j_arg);
@@ -2066,7 +2066,7 @@
     }
 
     template <>
-    void
+    OCTAVE_API void
     qr<FloatComplexMatrix>::shift_cols (octave_idx_type i_arg,
                                         octave_idx_type j_arg)
     {
--- a/liboctave/numeric/qr.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/qr.h	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
         init (a, qr_type);
       }
 
-      qr (const T& q, const T& r);
+      OCTAVE_API qr (const T& q, const T& r);
 
       qr (const qr& a) : q (a.q), r (a.r) { }
 
@@ -80,39 +80,40 @@
 
       T R (void) const { return r; }
 
-      type get_type (void) const;
+      OCTAVE_API type get_type (void) const;
 
-      bool regular (void) const;
+      OCTAVE_API bool regular (void) const;
 
-      void init (const T& a, type qr_type);
+      OCTAVE_API void init (const T& a, type qr_type);
 
-      void update (const CV_T& u, const CV_T& v);
+      OCTAVE_API void update (const CV_T& u, const CV_T& v);
 
-      void update (const T& u, const T& v);
+      OCTAVE_API void update (const T& u, const T& v);
 
-      void insert_col (const CV_T& u, octave_idx_type j);
+      OCTAVE_API void insert_col (const CV_T& u, octave_idx_type j);
 
-      void insert_col (const T& u, const Array<octave_idx_type>& j);
+      OCTAVE_API void insert_col (const T& u, const Array<octave_idx_type>& j);
 
-      void delete_col (octave_idx_type j);
+      OCTAVE_API void delete_col (octave_idx_type j);
 
-      void delete_col (const Array<octave_idx_type>& j);
+      OCTAVE_API void delete_col (const Array<octave_idx_type>& j);
 
-      void insert_row (const RV_T& u, octave_idx_type j);
+      OCTAVE_API void insert_row (const RV_T& u, octave_idx_type j);
 
-      void delete_row (octave_idx_type j);
+      OCTAVE_API void delete_row (octave_idx_type j);
 
-      void shift_cols (octave_idx_type i, octave_idx_type j);
+      OCTAVE_API void shift_cols (octave_idx_type i, octave_idx_type j);
 
     protected:
 
       T q;
       T r;
 
-      void form (octave_idx_type n, T& afact, ELT_T *tau, type qr_type);
+      OCTAVE_API void
+      form (octave_idx_type n, T& afact, ELT_T *tau, type qr_type);
     };
 
-    extern void warn_qrupdate_once (void);
+    extern OCTAVE_API void warn_qrupdate_once (void);
   }
 }
 
--- a/liboctave/numeric/qrp.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/qrp.cc	Sun May 16 09:44:35 2021 +0200
@@ -50,6 +50,7 @@
     // Specialization.
 
     template <>
+    OCTAVE_API
     void
     qrp<Matrix>::init (const Matrix& a, type qr_type)
     {
@@ -102,6 +103,7 @@
     }
 
     template <>
+    OCTAVE_API
     qrp<Matrix>::qrp (const Matrix& a, type qr_type)
       : qr<Matrix> (), p ()
     {
@@ -109,6 +111,7 @@
     }
 
     template <>
+    OCTAVE_API
     RowVector
     qrp<Matrix>::Pvec (void) const
     {
@@ -118,6 +121,7 @@
     }
 
     template <>
+    OCTAVE_API
     void
     qrp<FloatMatrix>::init (const FloatMatrix& a, type qr_type)
     {
@@ -170,6 +174,7 @@
     }
 
     template <>
+    OCTAVE_API
     qrp<FloatMatrix>::qrp (const FloatMatrix& a, type qr_type)
       : qr<FloatMatrix> (), p ()
     {
@@ -177,6 +182,7 @@
     }
 
     template <>
+    OCTAVE_API
     FloatRowVector
     qrp<FloatMatrix>::Pvec (void) const
     {
@@ -186,6 +192,7 @@
     }
 
     template <>
+    OCTAVE_API
     void
     qrp<ComplexMatrix>::init (const ComplexMatrix& a, type qr_type)
     {
@@ -246,6 +253,7 @@
     }
 
     template <>
+    OCTAVE_API
     qrp<ComplexMatrix>::qrp (const ComplexMatrix& a, type qr_type)
       : qr<ComplexMatrix> (), p ()
     {
@@ -253,6 +261,7 @@
     }
 
     template <>
+    OCTAVE_API
     RowVector
     qrp<ComplexMatrix>::Pvec (void) const
     {
@@ -262,6 +271,7 @@
     }
 
     template <>
+    OCTAVE_API
     void
     qrp<FloatComplexMatrix>::init (const FloatComplexMatrix& a, type qr_type)
     {
@@ -322,6 +332,7 @@
     }
 
     template <>
+    OCTAVE_API
     qrp<FloatComplexMatrix>::qrp (const FloatComplexMatrix& a, type qr_type)
       : qr<FloatComplexMatrix> (), p ()
     {
@@ -329,6 +340,7 @@
     }
 
     template <>
+    OCTAVE_API
     FloatRowVector
     qrp<FloatComplexMatrix>::Pvec (void) const
     {
--- a/liboctave/numeric/qrp.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/qrp.h	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 
       qrp (void) : qr<T> (), p () { }
 
-      qrp (const T&, type = qr<T>::std);
+      OCTAVE_API qrp (const T&, type = qr<T>::std);
 
       qrp (const qrp& a) : qr<T> (a), p (a.p) { }
 
@@ -64,11 +64,11 @@
 
       ~qrp (void) = default;
 
-      void init (const T&, type = qr<T>::std);
+      OCTAVE_API void init (const T&, type = qr<T>::std);
 
       PermMatrix P (void) const { return p; }
 
-      RV_T Pvec (void) const;
+      OCTAVE_API RV_T Pvec (void) const;
 
     private:
 
--- a/liboctave/numeric/randgamma.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/randgamma.cc	Sun May 16 09:44:35 2021 +0200
@@ -131,6 +131,6 @@
       }
   }
 
-  template void rand_gamma (double, octave_idx_type, double *);
-  template void rand_gamma (float, octave_idx_type, float *);
+  template OCTAVE_API void rand_gamma (double, octave_idx_type, double *);
+  template OCTAVE_API void rand_gamma (float, octave_idx_type, float *);
 }
--- a/liboctave/numeric/randgamma.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/randgamma.h	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 namespace octave
 {
   template <typename T>
-  void
+  OCTAVE_API void
   rand_gamma (T a, octave_idx_type n, T *p);
 
   template <typename T>
--- a/liboctave/numeric/randmtzig.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/randmtzig.cc	Sun May 16 09:44:35 2021 +0200
@@ -162,7 +162,9 @@
 #include <cstdio>
 
 #include <algorithm>
+#include <random>
 
+#include "oct-syscalls.h"
 #include "oct-time.h"
 #include "randmtzig.h"
 
@@ -259,36 +261,50 @@
     uint32_t entropy[MT_N];
     int n = 0;
 
-    /* Look for entropy in /dev/urandom */
-    FILE *urandom = std::fopen ("/dev/urandom", "rb");
-    if (urandom)
-      {
-        while (n < MT_N)
-          {
-            unsigned char word[4];
-            if (std::fread (word, 4, 1, urandom) != 1)
-              break;
-            entropy[n++] = word[0] + (word[1]<<8) + (word[2]<<16)
-                           + (static_cast<uint32_t> (word[3])<<24);
-          }
-        std::fclose (urandom);
-      }
-
-    /* If there isn't enough entropy, gather some from various sources */
+    // Gather some entropy from various sources
 
     sys::time now;
 
+    // Current time in seconds
     if (n < MT_N)
-      entropy[n++] = now.unix_time (); /* Current time in seconds */
+      entropy[n++] = now.unix_time ();
+
+    // CPU time used (usec)
+    if (n < MT_N)
+      entropy[n++] = clock ();
+
+    // Fractional part of current time
+    if (n < MT_N)
+      entropy[n++] = now.usec ();
+
+    // Include the PID to make sure that several processes reaching here at the
+    // same time use different random numbers.
+    if (n < MT_N)
+      entropy[n++] = sys::getpid ();
 
     if (n < MT_N)
-      entropy[n++] = clock ();    /* CPU time used (usec) */
+      {
+        try
+          {
+            // The standard doesn't *guarantee* that random_device provides
+            // non-deterministic random numbers. So add entropy from this
+            // source last to make sure we gathered at least some entropy from
+            // the earlier sources.
+            std::random_device rd;
+            std::uniform_int_distribution<uint32_t> dist;
+            // Add 1024 bit of "true" entropy
+            int n_max = std::min (n + 32, MT_N);
+            while (n < n_max)
+              entropy[n++] = dist (rd);
+          }
+        catch (const std::exception&)
+          {
+            // Just ignore any exception and skip that source of entropy.
+          }
+      }
 
-    if (n < MT_N)
-      entropy[n++] = now.usec ();   /* Fractional part of current time */
-
-    /* Send all the entropy into the initial state vector */
-    init_mersenne_twister (entropy,n);
+    // Send all the entropy into the initial state vector
+    init_mersenne_twister (entropy, n);
   }
 
   void set_mersenne_twister_state (const uint32_t *save)
@@ -410,7 +426,7 @@
 
   /* Determine mantissa for uniform doubles */
   template <>
-  double
+  OCTAVE_API double
   rand_uniform<double> (void)
   {
     return randu53 ();
@@ -418,7 +434,7 @@
 
   /* Determine mantissa for uniform floats */
   template <>
-  float
+  OCTAVE_API float
   rand_uniform<float> (void)
   {
     return randu24 ();
@@ -565,7 +581,7 @@
    */
 
 
-  template <> double rand_normal<double> (void)
+  template <> OCTAVE_API double rand_normal<double> (void)
   {
     if (initt)
       create_ziggurat_tables ();
@@ -629,7 +645,7 @@
       }
   }
 
-  template <> double rand_exponential<double> (void)
+  template <> OCTAVE_API double rand_exponential<double> (void)
   {
     if (initt)
       create_ziggurat_tables ();
@@ -655,17 +671,17 @@
       }
   }
 
-  template <> void rand_uniform<double> (octave_idx_type n, double *p)
+  template <> OCTAVE_API void rand_uniform<double> (octave_idx_type n, double *p)
   {
     std::generate_n (p, n, [](void) { return rand_uniform<double> (); });
   }
 
-  template <> void rand_normal (octave_idx_type n, double *p)
+  template <> OCTAVE_API void rand_normal (octave_idx_type n, double *p)
   {
     std::generate_n (p, n, [](void) { return rand_normal<double> (); });
   }
 
-  template <> void rand_exponential (octave_idx_type n, double *p)
+  template <> OCTAVE_API void rand_exponential (octave_idx_type n, double *p)
   {
     std::generate_n (p, n, [](void) { return rand_exponential<double> (); });
   }
@@ -767,7 +783,7 @@
    * distribution is exp(-0.5*x*x)
    */
 
-  template <> float rand_normal<float> (void)
+  template <> OCTAVE_API float rand_normal<float> (void)
   {
     if (inittf)
       create_ziggurat_float_tables ();
@@ -807,7 +823,7 @@
       }
   }
 
-  template <> float rand_exponential<float> (void)
+  template <> OCTAVE_API float rand_exponential<float> (void)
   {
     if (inittf)
       create_ziggurat_float_tables ();
@@ -833,17 +849,17 @@
       }
   }
 
-  template <> void rand_uniform (octave_idx_type n, float *p)
+  template <> OCTAVE_API void rand_uniform (octave_idx_type n, float *p)
   {
     std::generate_n (p, n, [](void) { return rand_uniform<float> (); });
   }
 
-  template <> void rand_normal (octave_idx_type n, float *p)
+  template <> OCTAVE_API void rand_normal (octave_idx_type n, float *p)
   {
     std::generate_n (p, n, [](void) { return rand_normal<float> (); });
   }
 
-  template <> void rand_exponential (octave_idx_type n, float *p)
+  template <> OCTAVE_API void rand_exponential (octave_idx_type n, float *p)
   {
     std::generate_n (p, n, [](void) { return rand_exponential<float> (); });
   }
--- a/liboctave/numeric/randmtzig.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/randmtzig.h	Sun May 16 09:44:35 2021 +0200
@@ -75,46 +75,47 @@
 {
   // Mersenne Twister.
 
-  extern void init_mersenne_twister (void);
-  extern void init_mersenne_twister (const uint32_t seed);
-  extern void init_mersenne_twister (const uint32_t *init_key,
-                                     const int key_length);
+  extern OCTAVE_API void init_mersenne_twister (void);
+  extern OCTAVE_API void init_mersenne_twister (const uint32_t seed);
+  extern OCTAVE_API void init_mersenne_twister (const uint32_t *init_key,
+                                                const int key_length);
 
-  extern void set_mersenne_twister_state (const uint32_t *save);
-  extern void get_mersenne_twister_state (uint32_t *save);
+  extern OCTAVE_API void set_mersenne_twister_state (const uint32_t *save);
+  extern OCTAVE_API void get_mersenne_twister_state (uint32_t *save);
 
-  template <typename T> T rand_uniform (void);
-  template <typename T> T rand_normal (void);
-  template <typename T> T rand_exponential (void);
+  template <typename T> OCTAVE_API T rand_uniform (void);
+  template <typename T> OCTAVE_API T rand_normal (void);
+  template <typename T> OCTAVE_API T rand_exponential (void);
 
-  template <typename T> void rand_uniform (octave_idx_type n, T *p);
-  template <typename T> void rand_normal (octave_idx_type n, T *p);
-  template <typename T> void rand_exponential (octave_idx_type n, T *p);
+  template <typename T> OCTAVE_API void rand_uniform (octave_idx_type n, T *p);
+  template <typename T> OCTAVE_API void rand_normal (octave_idx_type n, T *p);
+  template <typename T> OCTAVE_API void
+  rand_exponential (octave_idx_type n, T *p);
 
-  template <> double rand_uniform<double> (void);
-  template <> double rand_normal<double> (void);
-  template <> double rand_exponential<double> (void);
+  template <> OCTAVE_API double rand_uniform<double> (void);
+  template <> OCTAVE_API double rand_normal<double> (void);
+  template <> OCTAVE_API double rand_exponential<double> (void);
 
-  template <> float rand_uniform<float> (void);
-  template <> float rand_normal<float> (void);
-  template <> float rand_exponential<float> (void);
+  template <> OCTAVE_API float rand_uniform<float> (void);
+  template <> OCTAVE_API float rand_normal<float> (void);
+  template <> OCTAVE_API float rand_exponential<float> (void);
 
-  template <> void
+  template <> OCTAVE_API void
   rand_uniform<double> (octave_idx_type n, double *p);
 
-  template <> void
+  template <> OCTAVE_API void
   rand_normal<double> (octave_idx_type n, double *p);
 
-  template <> void
+  template <> OCTAVE_API void
   rand_exponential<double> (octave_idx_type n, double *p);
 
-  template <> void
+  template <> OCTAVE_API void
   rand_uniform<float> (octave_idx_type n, float *p);
 
-  template <> void
+  template <> OCTAVE_API void
   rand_normal<float> (octave_idx_type n, float *p);
 
-  template <> void
+  template <> OCTAVE_API void
   rand_exponential<float> (octave_idx_type n, float *p);
 }
 
--- a/liboctave/numeric/randpoisson.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/randpoisson.cc	Sun May 16 09:44:35 2021 +0200
@@ -455,6 +455,6 @@
     return ret;
   }
 
-  template double rand_poisson<double> (double);
-  template float rand_poisson<float> (float);
+  template OCTAVE_API double rand_poisson<double> (double);
+  template OCTAVE_API float rand_poisson<float> (float);
 }
--- a/liboctave/numeric/randpoisson.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/randpoisson.h	Sun May 16 09:44:35 2021 +0200
@@ -33,9 +33,9 @@
 
 namespace octave
 {
-  template <typename T> void rand_poisson (T L, octave_idx_type n, T *p);
+  template <typename T> OCTAVE_API void rand_poisson (T L, octave_idx_type n, T *p);
 
-  template <typename T> T rand_poisson (T L);
+  template <typename T> OCTAVE_API T rand_poisson (T L);
 }
 
 #endif
--- a/liboctave/numeric/schur.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/schur.cc	Sun May 16 09:44:35 2021 +0200
@@ -98,7 +98,7 @@
     }
 
     template <>
-    F77_INT
+    OCTAVE_API F77_INT
     schur<Matrix>::init (const Matrix& a, const std::string& ord, bool calc_unitary)
     {
       F77_INT a_nr = to_f77_int (a.rows ());
@@ -184,7 +184,7 @@
     }
 
     template <>
-    F77_INT
+    OCTAVE_API F77_INT
     schur<FloatMatrix>::init (const FloatMatrix& a, const std::string& ord,
                               bool calc_unitary)
     {
@@ -271,7 +271,7 @@
     }
 
     template <>
-    F77_INT
+    OCTAVE_API F77_INT
     schur<ComplexMatrix>::init (const ComplexMatrix& a, const std::string& ord,
                                 bool calc_unitary)
     {
@@ -354,7 +354,7 @@
     }
 
     template <>
-    schur<ComplexMatrix>
+    OCTAVE_API schur<ComplexMatrix>
     rsf2csf<ComplexMatrix, Matrix> (const Matrix& s_arg, const Matrix& u_arg)
     {
       ComplexMatrix s (s_arg);
@@ -379,7 +379,7 @@
     }
 
     template <>
-    F77_INT
+    OCTAVE_API F77_INT
     schur<FloatComplexMatrix>::init (const FloatComplexMatrix& a,
                                      const std::string& ord, bool calc_unitary)
     {
@@ -462,7 +462,7 @@
     }
 
     template <>
-    schur<FloatComplexMatrix>
+    OCTAVE_API schur<FloatComplexMatrix>
     rsf2csf<FloatComplexMatrix, FloatMatrix> (const FloatMatrix& s_arg,
                                               const FloatMatrix& u_arg)
     {
--- a/liboctave/numeric/schur.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/schur.h	Sun May 16 09:44:35 2021 +0200
@@ -95,12 +95,12 @@
       T schur_mat;
       T unitary_mat;
 
-      octave_f77_int_type
+      OCTAVE_API octave_f77_int_type
       init (const T& a, const std::string& ord, bool calc_unitary);
     };
 
     template <typename RT, typename AT>
-    extern schur<RT>
+    extern OCTAVE_API schur<RT>
     rsf2csf (const AT& s, const AT& u);
   }
 }
--- a/liboctave/numeric/sparse-chol.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/sparse-chol.cc	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,6 @@
 #include "dSparse.h"
 #include "lo-error.h"
 #include "oct-cmplx.h"
-#include "oct-refcount.h"
 #include "oct-sparse.h"
 #include "oct-spparms.h"
 #include "quit.h"
@@ -52,14 +51,14 @@
     public:
 
       sparse_chol_rep (void)
-        : count (1), is_pd (false), minor_p (0), perms (), cond (0)
+        : is_pd (false), minor_p (0), perms (), cond (0)
 #if defined (HAVE_CHOLMOD)
         , Lsparse (nullptr), Common ()
 #endif
       { }
 
       sparse_chol_rep (const chol_type& a, bool natural, bool force)
-        : count (1), is_pd (false), minor_p (0), perms (), cond (0)
+        : is_pd (false), minor_p (0), perms (), cond (0)
 #if defined (HAVE_CHOLMOD)
         , Lsparse (nullptr), Common ()
 #endif
@@ -69,7 +68,7 @@
 
       sparse_chol_rep (const chol_type& a, octave_idx_type& info,
                        bool natural, bool force)
-        : count (1), is_pd (false), minor_p (0), perms (), cond (0)
+        : is_pd (false), minor_p (0), perms (), cond (0)
 #if defined (HAVE_CHOLMOD)
         , Lsparse (nullptr), Common ()
 #endif
@@ -118,8 +117,6 @@
 
       double rcond (void) const { return cond; }
 
-      refcount<octave_idx_type> count;
-
     private:
 
       bool is_pd;
@@ -293,26 +290,19 @@
           cm->postorder = false;
         }
 
-      cholmod_factor *Lfactor;
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-      Lfactor = CHOLMOD_NAME(analyze) (ac, cm);
+      cholmod_factor *Lfactor = CHOLMOD_NAME(analyze) (ac, cm);
       CHOLMOD_NAME(factorize) (ac, Lfactor, cm);
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
       is_pd = cm->status == CHOLMOD_OK;
       info = (is_pd ? 0 : cm->status);
 
       if (is_pd || force)
         {
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           cond = CHOLMOD_NAME(rcond) (Lfactor, cm);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           minor_p = Lfactor->minor;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           Lsparse = CHOLMOD_NAME(factor_to_sparse) (Lfactor, cm);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           if (minor_p > 0 && minor_p < a_nr)
             {
@@ -320,11 +310,10 @@
               Lsparse->p = CHOLMOD_NAME(realloc) (minor_p+1,
                                                   sizeof(octave_idx_type),
                                                   Lsparse->p, &n1, cm);
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
+
               CHOLMOD_NAME(reallocate_sparse)
                 (static_cast<octave_idx_type *>(Lsparse->p)[minor_p],
                  Lsparse, cm);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
               Lsparse->ncol = minor_p;
             }
@@ -342,10 +331,8 @@
       // NAME used to prefix statistics report from print_common
       static char blank_name[] = " ";
 
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
       CHOLMOD_NAME(print_common) (blank_name, cm);
       CHOLMOD_NAME(free_factor) (&Lfactor, cm);
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
       return info;
 
@@ -426,36 +413,6 @@
     { }
 
     template <typename chol_type>
-    sparse_chol<chol_type>::sparse_chol (const sparse_chol<chol_type>& a)
-      : rep (a.rep)
-    {
-      rep->count++;
-    }
-
-    template <typename chol_type>
-    sparse_chol<chol_type>::~sparse_chol (void)
-    {
-      if (--rep->count == 0)
-        delete rep;
-    }
-
-    template <typename chol_type>
-    sparse_chol<chol_type>&
-    sparse_chol<chol_type>::operator = (const sparse_chol& a)
-    {
-      if (this != &a)
-        {
-          if (--rep->count == 0)
-            delete rep;
-
-          rep = a.rep;
-          rep->count++;
-        }
-
-      return *this;
-    }
-
-    template <typename chol_type>
     chol_type
     sparse_chol<chol_type>::L (void) const
     {
@@ -591,6 +548,7 @@
     // different from the default).
 
     template <>
+    OCTAVE_API
     sparse_chol<SparseComplexMatrix>::sparse_chol (const SparseComplexMatrix& a,
                                                    octave_idx_type& info)
       : rep (new sparse_chol<SparseComplexMatrix>::sparse_chol_rep (a, info,
@@ -600,14 +558,15 @@
 
     // Instantiations we need.
 
-    template class sparse_chol<SparseMatrix>;
+    template class OCTAVE_API sparse_chol<SparseMatrix>;
 
     template class sparse_chol<SparseComplexMatrix>;
 
-    template SparseMatrix
+    template OCTAVE_API SparseMatrix
     chol2inv<SparseMatrix> (const SparseMatrix& r);
 
-    template SparseComplexMatrix
+    template OCTAVE_API SparseComplexMatrix
     chol2inv<SparseComplexMatrix> (const SparseComplexMatrix& r);
+
   }
 }
--- a/liboctave/numeric/sparse-chol.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/sparse-chol.h	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,8 @@
 
 #include "octave-config.h"
 
+#include <memory>
+
 #include "CSparse.h"
 
 class RowVector;
@@ -45,6 +47,7 @@
 
     template <typename chol_type>
     class
+    OCTAVE_API
     sparse_chol
     {
     public:
@@ -60,11 +63,12 @@
 
       sparse_chol (const chol_type& a, octave_idx_type& info);
 
-      sparse_chol (const sparse_chol<chol_type>& a);
+      sparse_chol (const sparse_chol<chol_type>& a) = default;
 
-      virtual ~sparse_chol (void);
+      virtual ~sparse_chol (void) = default;
 
-      sparse_chol& operator = (const sparse_chol& a);
+      sparse_chol<chol_type>&
+      operator = (const sparse_chol<chol_type>& a) = default;
 
       chol_type L (void) const;
 
@@ -90,18 +94,13 @@
 
     private:
 
-      sparse_chol_rep *rep;
+      std::shared_ptr<sparse_chol_rep> rep;
     };
 
     template <typename chol_type>
+    OCTAVE_API
     chol_type
     chol2inv (const chol_type& r);
-
-    // SparseComplexMatrix specialization.
-
-    template <>
-    sparse_chol<SparseComplexMatrix>::sparse_chol
-      (const SparseComplexMatrix& a, octave_idx_type& info);
   }
 }
 
--- a/liboctave/numeric/sparse-dmsolve.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/sparse-dmsolve.cc	Sun May 16 09:44:35 2021 +0200
@@ -505,34 +505,34 @@
 
 // Instantiations we need.
 
-template ComplexMatrix
+template OCTAVE_API ComplexMatrix
 dmsolve<ComplexMatrix, SparseComplexMatrix, Matrix>
   (const SparseComplexMatrix&, const Matrix&, octave_idx_type&);
 
-template SparseComplexMatrix
+template OCTAVE_API SparseComplexMatrix
 dmsolve<SparseComplexMatrix, SparseComplexMatrix, SparseMatrix>
   (const SparseComplexMatrix&, const SparseMatrix&, octave_idx_type&);
 
-template ComplexMatrix
+template OCTAVE_API ComplexMatrix
 dmsolve<ComplexMatrix, SparseComplexMatrix, ComplexMatrix>
   (const SparseComplexMatrix&, const ComplexMatrix&, octave_idx_type&);
 
-template SparseComplexMatrix
+template OCTAVE_API SparseComplexMatrix
 dmsolve<SparseComplexMatrix, SparseComplexMatrix, SparseComplexMatrix>
   (const SparseComplexMatrix&, const SparseComplexMatrix&, octave_idx_type&);
 
-template Matrix
+template OCTAVE_API Matrix
 dmsolve<Matrix, SparseMatrix, Matrix>
   (const SparseMatrix&, const Matrix&, octave_idx_type&);
 
-template SparseMatrix
+template OCTAVE_API SparseMatrix
 dmsolve<SparseMatrix, SparseMatrix, SparseMatrix>
   (const SparseMatrix&, const SparseMatrix&, octave_idx_type&);
 
-template ComplexMatrix
+template OCTAVE_API ComplexMatrix
 dmsolve<ComplexMatrix, SparseMatrix, ComplexMatrix>
   (const SparseMatrix&, const ComplexMatrix&, octave_idx_type&);
 
-template SparseComplexMatrix
+template OCTAVE_API SparseComplexMatrix
 dmsolve<SparseComplexMatrix, SparseMatrix, SparseComplexMatrix>
   (const SparseMatrix&, const SparseComplexMatrix&, octave_idx_type&);
--- a/liboctave/numeric/sparse-dmsolve.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/sparse-dmsolve.h	Sun May 16 09:44:35 2021 +0200
@@ -29,7 +29,7 @@
 #include "octave-config.h"
 
 template <typename RT, typename ST, typename T>
-RT
+OCTAVE_API RT
 dmsolve (const ST& a, const T& b, octave_idx_type& info);
 
 #endif
--- a/liboctave/numeric/sparse-lu.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/sparse-lu.cc	Sun May 16 09:44:35 2021 +0200
@@ -127,28 +127,28 @@
     // SparseMatrix Specialization.
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_defaults<double> (double *Control)
     {
       UMFPACK_DNAME (defaults) (Control);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_free_numeric<double> (void **Numeric)
     {
       UMFPACK_DNAME (free_numeric) (Numeric);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_free_symbolic<double> (void **Symbolic)
     {
       UMFPACK_DNAME (free_symbolic) (Symbolic);
     }
 
     template <>
-    inline octave_idx_type
+    inline OCTAVE_API octave_idx_type
     umfpack_get_lunz<double>
     (octave_idx_type *lnz, octave_idx_type *unz, void *Numeric)
     {
@@ -160,7 +160,7 @@
     }
 
     template <>
-    inline octave_idx_type
+    inline OCTAVE_API octave_idx_type
     umfpack_get_numeric<double>
     (octave_idx_type *Lp, octave_idx_type *Lj, double *Lx,
      octave_idx_type *Up, octave_idx_type *Ui, double *Ux,
@@ -178,7 +178,7 @@
     }
 
     template <>
-    inline octave_idx_type
+    inline OCTAVE_API octave_idx_type
     umfpack_numeric<double>
     (const octave_idx_type *Ap, const octave_idx_type *Ai,
      const double *Ax, void *Symbolic, void **Numeric,
@@ -190,7 +190,7 @@
     }
 
     template <>
-    inline octave_idx_type
+    inline OCTAVE_API octave_idx_type
     umfpack_qsymbolic<double>
     (octave_idx_type n_row, octave_idx_type n_col, const octave_idx_type *Ap,
      const octave_idx_type *Ai, const double *Ax,
@@ -205,21 +205,21 @@
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_control<double> (const double *Control)
     {
       UMFPACK_DNAME (report_control) (Control);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_info<double> (const double *Control, const double *Info)
     {
       UMFPACK_DNAME (report_info) (Control, Info);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_matrix<double>
     (octave_idx_type n_row, octave_idx_type n_col, const octave_idx_type *Ap,
      const octave_idx_type *Ai, const double *Ax, octave_idx_type col_form,
@@ -232,14 +232,14 @@
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_numeric<double> (void *Numeric, const double *Control)
     {
       UMFPACK_DNAME (report_numeric) (Numeric, Control);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_perm<double>
     (octave_idx_type np, const octave_idx_type *Perm, const double *Control)
     {
@@ -247,14 +247,14 @@
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_status<double> (double *Control, octave_idx_type status)
     {
       UMFPACK_DNAME (report_status) (Control, status);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_symbolic<double> (void *Symbolic, const double *Control)
     {
       UMFPACK_DNAME (report_symbolic) (Symbolic, Control);
@@ -263,28 +263,28 @@
     // SparseComplexMatrix specialization.
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_defaults<Complex> (double *Control)
     {
       UMFPACK_ZNAME (defaults) (Control);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_free_numeric<Complex> (void **Numeric)
     {
       UMFPACK_ZNAME (free_numeric) (Numeric);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_free_symbolic<Complex> (void **Symbolic)
     {
       UMFPACK_ZNAME (free_symbolic) (Symbolic);
     }
 
     template <>
-    inline octave_idx_type
+    inline OCTAVE_API octave_idx_type
     umfpack_get_lunz<Complex>
     (octave_idx_type *lnz, octave_idx_type *unz, void *Numeric)
     {
@@ -296,7 +296,7 @@
     }
 
     template <>
-    inline octave_idx_type
+    inline OCTAVE_API octave_idx_type
     umfpack_get_numeric<Complex>
     (octave_idx_type *Lp, octave_idx_type *Lj, Complex *Lz,
      octave_idx_type *Up, octave_idx_type *Ui, Complex *Uz,
@@ -317,7 +317,7 @@
     }
 
     template <>
-    inline octave_idx_type
+    inline OCTAVE_API octave_idx_type
     umfpack_numeric<Complex>
     (const octave_idx_type *Ap, const octave_idx_type *Ai,
      const Complex *Az, void *Symbolic, void **Numeric,
@@ -330,7 +330,7 @@
     }
 
     template <>
-    inline octave_idx_type
+    inline OCTAVE_API octave_idx_type
     umfpack_qsymbolic<Complex>
     (octave_idx_type n_row, octave_idx_type n_col,
      const octave_idx_type *Ap, const octave_idx_type *Ai,
@@ -346,21 +346,21 @@
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_control<Complex> (const double *Control)
     {
       UMFPACK_ZNAME (report_control) (Control);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_info<Complex> (const double *Control, const double *Info)
     {
       UMFPACK_ZNAME (report_info) (Control, Info);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_matrix<Complex>
     (octave_idx_type n_row, octave_idx_type n_col,
      const octave_idx_type *Ap, const octave_idx_type *Ai,
@@ -374,14 +374,14 @@
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_numeric<Complex> (void *Numeric, const double *Control)
     {
       UMFPACK_ZNAME (report_numeric) (Numeric, Control);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_perm<Complex>
     (octave_idx_type np, const octave_idx_type *Perm, const double *Control)
     {
@@ -389,14 +389,14 @@
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_status<Complex> (double *Control, octave_idx_type status)
     {
       UMFPACK_ZNAME (report_status) (Control, status);
     }
 
     template <>
-    inline void
+    inline OCTAVE_API void
     umfpack_report_symbolic <Complex> (void *Symbolic, const double *Control)
     {
       UMFPACK_ZNAME (report_symbolic) (Symbolic, Control);
@@ -981,9 +981,8 @@
     }
 
     // Instantiations we need.
+    template class OCTAVE_API sparse_lu<SparseMatrix>;
 
-    template class sparse_lu<SparseMatrix>;
-
-    template class sparse_lu<SparseComplexMatrix>;
+    template class OCTAVE_API sparse_lu<SparseComplexMatrix>;
   }
 }
--- a/liboctave/numeric/sparse-lu.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/sparse-lu.h	Sun May 16 09:44:35 2021 +0200
@@ -55,9 +55,11 @@
       sparse_lu (void)
         : Lfact (), Ufact (), Rfact (), cond (0), P (), Q () { }
 
+      OCTAVE_API
       sparse_lu (const lu_type& a, const Matrix& piv_thres = Matrix (),
                  bool scale = false);
 
+      OCTAVE_API
       sparse_lu (const lu_type& a, const ColumnVector& Qinit,
                  const Matrix& piv_thres, bool scale = false,
                  bool FixedQ = false, double droptol = -1.0,
@@ -90,19 +92,19 @@
 
       SparseMatrix R (void) const { return Rfact; }
 
-      lu_type Y (void) const;
+      OCTAVE_API lu_type Y (void) const;
 
-      SparseMatrix Pc (void) const;
+      OCTAVE_API SparseMatrix Pc (void) const;
 
-      SparseMatrix Pr (void) const;
+      OCTAVE_API SparseMatrix Pr (void) const;
 
-      ColumnVector Pc_vec (void) const;
+      OCTAVE_API ColumnVector Pc_vec (void) const;
 
-      ColumnVector Pr_vec (void) const;
+      OCTAVE_API ColumnVector Pr_vec (void) const;
 
-      PermMatrix Pc_mat (void) const;
+      OCTAVE_API PermMatrix Pc_mat (void) const;
 
-      PermMatrix Pr_mat (void) const;
+      OCTAVE_API PermMatrix Pr_mat (void) const;
 
       const octave_idx_type * row_perm (void) const { return P.fortran_vec (); }
 
--- a/liboctave/numeric/sparse-qr.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/sparse-qr.cc	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,6 @@
 #include "dSparse.h"
 #include "lo-error.h"
 #include "oct-locbuf.h"
-#include "oct-refcount.h"
 #include "oct-sparse.h"
 #include "quit.h"
 #include "sparse-qr.h"
@@ -44,24 +43,19 @@
 {
   namespace math
   {
+#if defined (HAVE_CXSPARSE)
     template <typename SPARSE_T>
     class
     cxsparse_types
-    {
-    };
+      { };
 
     template <>
     class
     cxsparse_types<SparseMatrix>
     {
     public:
-#if defined (HAVE_CXSPARSE)
       typedef CXSPARSE_DNAME (s) symbolic_type;
       typedef CXSPARSE_DNAME (n) numeric_type;
-#else
-      typedef void symbolic_type;
-      typedef void numeric_type;
-#endif
     };
 
     template <>
@@ -69,14 +63,10 @@
     cxsparse_types<SparseComplexMatrix>
     {
     public:
-#if defined (HAVE_CXSPARSE)
       typedef CXSPARSE_ZNAME (s) symbolic_type;
       typedef CXSPARSE_ZNAME (n) numeric_type;
-#else
-      typedef void symbolic_type;
-      typedef void numeric_type;
+    };
 #endif
-    };
 
     template <typename SPARSE_T>
     class sparse_qr<SPARSE_T>::sparse_qr_rep
@@ -95,7 +85,9 @@
 
       bool ok (void) const
       {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+        return (m_H && m_Htau && m_HPinv && m_R && m_E);
+#elif defined (HAVE_CXSPARSE)
         return (N && S);
 #else
         return false;
@@ -108,29 +100,51 @@
 
       ColumnVector P (void) const;
 
+      ColumnVector E (void) const;
+
       SPARSE_T R (bool econ) const;
 
       typename SPARSE_T::dense_matrix_type
-      C (const typename SPARSE_T::dense_matrix_type& b) const;
-
-      typename SPARSE_T::dense_matrix_type
-      Q (void) const;
-
-      refcount<octave_idx_type> count;
+      C (const typename SPARSE_T::dense_matrix_type& b, bool econ = false);
+
+      typename SPARSE_T::dense_matrix_type Q (bool econ = false);
 
       octave_idx_type nrows;
       octave_idx_type ncols;
 
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      template <typename RHS_T, typename RET_T>
+      RET_T solve (const RHS_T& b, octave_idx_type& info) const;
+
+#endif
+
+#if defined (HAVE_CXSPARSE)
+
       typename cxsparse_types<SPARSE_T>::symbolic_type *S;
       typename cxsparse_types<SPARSE_T>::numeric_type *N;
 
+#endif
+
       template <typename RHS_T, typename RET_T>
-      RET_T
-      tall_solve (const RHS_T& b, octave_idx_type& info) const;
+      RET_T tall_solve (const RHS_T& b, octave_idx_type& info);
 
       template <typename RHS_T, typename RET_T>
-      RET_T
-      wide_solve (const RHS_T& b, octave_idx_type& info) const;
+      RET_T wide_solve (const RHS_T& b, octave_idx_type& info) const;
+
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+    private:
+
+      cholmod_common m_cc;
+      cholmod_sparse *m_R;  // R factor
+      // Column permutation for A. Fill-reducing ordering.
+      SuiteSparse_long *m_E;
+      cholmod_sparse *m_H;  // Householder vectors
+      cholmod_dense *m_Htau;  // beta scalars
+      SuiteSparse_long *m_HPinv;
+
+#endif
     };
 
     template <typename SPARSE_T>
@@ -157,7 +171,17 @@
     ColumnVector
     sparse_qr<SPARSE_T>::sparse_qr_rep::P (void) const
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      ColumnVector ret (nrows);
+
+      // FIXME: Is ret.xelem (m_HPinv[i]) = i + 1 correct?
+      for (octave_idx_type i = 0; i < nrows; i++)
+        ret.xelem (from_suitesparse_long (m_HPinv[i])) = i + 1;
+
+      return ret;
+
+#elif defined (HAVE_CXSPARSE)
 
       ColumnVector ret (N->L->m);
 
@@ -173,20 +197,340 @@
 #endif
     }
 
+    template <typename SPARSE_T>
+    ColumnVector
+    sparse_qr<SPARSE_T>::sparse_qr_rep::E (void) const
+    {
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      ColumnVector ret (ncols);
+
+      for (octave_idx_type i = 0; i < ncols; i++)
+        ret(i) = from_suitesparse_long (m_E[i]) + 1;
+
+      return ret;
+
+#else
+
+      return ColumnVector ();
+
+#endif
+    }
+
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+    // Convert real sparse octave matrix to real sparse cholmod matrix.
+    // Returns a "shallow" copy of a.
+    static cholmod_sparse
+    ros2rcs (const SparseMatrix& a)
+    {
+      cholmod_sparse A;
+
+      octave_idx_type ncols = a.cols ();
+      octave_idx_type nnz = a.nnz ();
+
+      A.ncol = ncols;
+      A.nrow = a.rows ();
+      A.itype = CHOLMOD_LONG;
+      A.nzmax = nnz;
+      A.sorted = 0;
+      A.packed = 1;
+      A.stype = 0;
+      A.xtype = CHOLMOD_REAL;
+      A.dtype = CHOLMOD_DOUBLE;
+      A.nz = nullptr;
+      A.z = nullptr;
+      if (sizeof (octave_idx_type) == sizeof (SuiteSparse_long))
+        {
+          A.p = reinterpret_cast<SuiteSparse_long *> (a.cidx ());
+          A.i = reinterpret_cast<SuiteSparse_long *> (a.ridx ());
+        }
+      else
+        {
+          SuiteSparse_long *A_p;
+          A_p = new SuiteSparse_long[ncols+1];
+          for (octave_idx_type i = 0; i < ncols+1; i++)
+            A_p[i] = a.cidx (i);
+          A.p = A_p;
+          SuiteSparse_long *A_i;
+          A_i = new SuiteSparse_long[nnz];
+          for (octave_idx_type i = 0; i < nnz; i++)
+            A_i[i] = a.ridx (i);
+          A.i = A_i;
+        }
+      A.x = const_cast<double *> (a.data ());
+
+      return A;
+    }
+
+    // Convert complex sparse octave matrix to complex sparse cholmod matrix.
+    // Returns a "shallow" copy of a.
+    static cholmod_sparse
+    cos2ccs (const SparseComplexMatrix& a)
+    {
+      cholmod_sparse A;
+
+      octave_idx_type ncols = a.cols ();
+      octave_idx_type nnz = a.nnz ();
+
+      A.ncol = ncols;
+      A.nrow = a.rows ();
+      A.itype = CHOLMOD_LONG;
+      A.nzmax = nnz;
+      A.sorted = 0;
+      A.packed = 1;
+      A.stype = 0;
+      A.xtype = CHOLMOD_COMPLEX;
+      A.dtype = CHOLMOD_DOUBLE;
+      A.nz = nullptr;
+      A.z = nullptr;
+      if (sizeof (octave_idx_type) == sizeof (SuiteSparse_long))
+        {
+          A.p = reinterpret_cast<SuiteSparse_long *> (a.cidx ());
+          A.i = reinterpret_cast<SuiteSparse_long *> (a.ridx ());
+        }
+      else
+        {
+          SuiteSparse_long *A_p;
+          A_p = new SuiteSparse_long[ncols+1];
+          for (octave_idx_type i = 0; i < ncols+1; i++)
+            A_p[i] = a.cidx (i);
+          A.p = A_p;
+          SuiteSparse_long *A_i;
+          A_i = new SuiteSparse_long[nnz];
+          for (octave_idx_type i = 0; i < nnz; i++)
+            A_i[i] = a.ridx (i);
+          A.i = A_i;
+        }
+      A.x = const_cast<Complex *>
+                   (reinterpret_cast<const Complex *> (a.data ()));
+
+      return A;
+    }
+
+    // Convert real dense octave matrix to complex dense cholmod matrix.
+    // Returns a "deep" copy of a.
+    static cholmod_dense*
+    rod2ccd (const MArray<double>& a, cholmod_common *cc1)
+    {
+      cholmod_dense *A
+        = cholmod_l_allocate_dense (a.rows (), a.cols (), a.rows(),
+                                    CHOLMOD_COMPLEX, cc1);
+
+      const double *a_x = a.data ();
+
+      Complex *A_x = reinterpret_cast<Complex *> (A->x);
+      for (octave_idx_type j = 0; j < a.cols() * a.rows() ; j++)
+        A_x[j] = Complex (a_x[j], 0.0);
+
+      return A;
+    }
+
+    // Convert real dense octave matrix to real dense cholmod matrix.
+    // Returns a "shallow" copy of a.
+    static cholmod_dense
+    rod2rcd (const MArray<double> &a)
+    {
+      cholmod_dense A;
+
+      A.ncol = a.cols ();
+      A.nrow = a.rows ();
+      A.nzmax = a.cols () * a.rows ();
+      A.xtype = CHOLMOD_REAL;
+      A.dtype = CHOLMOD_DOUBLE;
+      A.z = nullptr;
+      A.d = a.rows ();
+      A.x = const_cast<double *> (a.data ());
+
+      return A;
+    }
+
+    // Convert complex dense octave matrix to complex dense cholmod matrix.
+    // Returns a "shallow" copy of a.
+    static cholmod_dense
+    cod2ccd (const ComplexMatrix &a)
+    {
+      cholmod_dense A;
+
+      A.ncol = a.cols ();
+      A.nrow = a.rows ();
+      A.nzmax = a.cols () * a.rows ();
+      A.xtype = CHOLMOD_COMPLEX;
+      A.dtype = CHOLMOD_DOUBLE;
+      A.z = nullptr;
+      A.d = a.rows ();
+      A.x = const_cast<Complex*> (reinterpret_cast<const Complex*> (a.data ()));
+
+      return A;
+    }
+
+    // Convert real sparse cholmod matrix to real sparse octave matrix.
+    // Returns a "shallow" copy of y.
+    static SparseMatrix
+    rcs2ros (const cholmod_sparse* y)
+    {
+      octave_idx_type nrow = from_size_t (y->nrow);
+      octave_idx_type ncol = from_size_t (y->ncol);
+      octave_idx_type nz = from_size_t (y->nzmax);
+      SparseMatrix ret (nrow, ncol, nz);
+
+      SuiteSparse_long *y_p = reinterpret_cast<SuiteSparse_long *> (y->p);
+      for (octave_idx_type j = 0; j < ncol + 1; j++)
+        ret.xcidx (j) = from_suitesparse_long (y_p[j]);
+
+      SuiteSparse_long *y_i = reinterpret_cast<SuiteSparse_long *> (y->i);
+      double *y_x = reinterpret_cast<double *> (y->x);
+      for (octave_idx_type j = 0; j < nz; j++)
+        {
+          ret.xridx (j) = from_suitesparse_long (y_i[j]);
+          ret.xdata (j) = y_x[j];
+        }
+
+      return ret;
+    }
+
+    // Convert complex sparse cholmod matrix to complex sparse octave matrix.
+    // Returns a "deep" copy of a.
+    static SparseComplexMatrix
+    ccs2cos (const cholmod_sparse *a)
+    {
+      octave_idx_type nrow = from_size_t (a->nrow);
+      octave_idx_type ncol = from_size_t (a->ncol);
+      octave_idx_type nz = from_size_t (a->nzmax);
+      SparseComplexMatrix ret (nrow, ncol, nz);
+
+      SuiteSparse_long *a_p = reinterpret_cast<SuiteSparse_long *> (a->p);
+      for (octave_idx_type j = 0; j < ncol + 1; j++)
+        ret.xcidx(j) = from_suitesparse_long (a_p[j]);
+
+      SuiteSparse_long *a_i = reinterpret_cast<SuiteSparse_long *> (a->i);
+      Complex *a_x = reinterpret_cast<Complex *> (a->x);
+      for (octave_idx_type j = 0; j < nz; j++)
+        {
+          ret.xridx(j) = from_suitesparse_long (a_i[j]);
+          ret.xdata(j) = a_x[j];
+        }
+
+      return ret;
+    }
+
+    // Convert real sparse octave matrix to complex sparse cholmod matrix.
+    // Returns a "deep" copy of a.
+    static cholmod_sparse*
+    ros2ccs (const SparseMatrix& a, cholmod_common *cc)
+    {
+      cholmod_sparse *A
+        = cholmod_l_allocate_sparse (a.rows (), a.cols (), a.nnz (), 0, 1, 0,
+                                     CHOLMOD_COMPLEX, cc);
+
+      octave_idx_type ncol = a.cols ();
+      SuiteSparse_long *A_p = reinterpret_cast<SuiteSparse_long *> (A->p);
+      for (octave_idx_type j = 0; j < ncol + 1; j++)
+        A_p[j] = a.cidx(j);
+
+      const double *a_x = a.data ();
+      Complex *A_x = reinterpret_cast<Complex *> (A->x);
+      SuiteSparse_long *A_i = reinterpret_cast<SuiteSparse_long *> (A->i);
+      for (octave_idx_type j = 0; j < a.nnz (); j++)
+        {
+          A_x[j] = Complex (a_x[j], 0.0);
+          A_i[j] = a.ridx(j);
+        }
+      return A;
+    }
+
+    static suitesparse_integer
+    suitesparse_long_to_suitesparse_integer (SuiteSparse_long x)
+    {
+      if (x < std::numeric_limits<suitesparse_integer>::min ()
+          || x > std::numeric_limits<suitesparse_integer>::max ())
+        (*current_liboctave_error_handler)
+          ("integer dimension or index out of range for SuiteSparse's indexing type");
+
+      return static_cast<suitesparse_integer> (x);
+    }
+
+    static void
+    spqr_error_handler (const cholmod_common *cc)
+    {
+      if (cc->status >= 0)
+        return;
+
+      switch (cc->status)
+        {
+        case CHOLMOD_OUT_OF_MEMORY:
+          (*current_liboctave_error_handler)
+            ("sparse_qr: sparse matrix QR factorization failed"
+             " - out of memory");
+        case CHOLMOD_TOO_LARGE:
+          (*current_liboctave_error_handler)
+            ("sparse_qr: sparse matrix QR factorization failed"
+             " - integer overflow occurred");
+        default:
+          (*current_liboctave_error_handler)
+            ("sparse_qr: sparse matrix QR factorization failed"
+             " - error %d", cc->status);
+        }
+
+      // FIXME: Free memory?
+      // FIXME: Can cc-status > 0 (CHOLMOD_NOT_POSDEF, CHOLMOD_DSMALL) occur?
+    }
+#endif
+
     // Specializations.
 
     // Real-valued matrices.
 
+    // Arguments for parameter order (taken from SuiteSparseQR documentation).
+    // 0: fixed ordering 0 (no permutation of columns)
+    // 1: natural ordering 1 (only singleton columns are permuted to the left of
+    //    the matrix)
+    // 2: colamd
+    // 3:
+    // 4: CHOLMOD best-effort (COLAMD, METIS,...)
+    // 5: AMD(a'*a)
+    // 6: metis(a'*a)
+    // 7: SuiteSparseQR default ordering
+    // 8: try COLAMD, AMD, and METIS; pick best
+    // 9: try COLAMD and AMD; pick best
+    //FIXME: What is order = 3?
     template <>
     sparse_qr<SparseMatrix>::sparse_qr_rep::sparse_qr_rep
     (const SparseMatrix& a, int order)
-      : count (1), nrows (a.rows ()), ncols (a.columns ())
-#if defined (HAVE_CXSPARSE)
+      : nrows (a.rows ()), ncols (a.columns ())
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+      , m_cc (), m_R (nullptr), m_E (nullptr), m_H (nullptr), m_Htau (nullptr),
+        m_HPinv (nullptr)
+    {
+      octave_idx_type nr = a.rows ();
+      octave_idx_type nc = a.cols ();
+
+      if (nr <= 0 || nc <= 0)
+        (*current_liboctave_error_handler)
+          ("matrix dimension with negative or zero size");
+
+      if (order < 0 || order > 9)
+        (*current_liboctave_error_handler)
+          ("ordering %d is not supported by SPQR", order);
+
+      cholmod_l_start (&m_cc);
+      cholmod_sparse A = ros2rcs (a);
+
+      SuiteSparseQR<double> (order, static_cast<double> (SPQR_DEFAULT_TOL),
+                             static_cast<SuiteSparse_long> (A.nrow),
+                             &A, &m_R, &m_E, &m_H, &m_HPinv, &m_Htau, &m_cc);
+      spqr_error_handler (&m_cc);
+
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.i);
+        }
+    }
+
+#elif defined (HAVE_CXSPARSE)
       , S (nullptr), N (nullptr)
-#endif
     {
-#if defined (HAVE_CXSPARSE)
-
       CXSPARSE_DNAME () A;
 
       A.nzmax = a.nnz ();
@@ -201,31 +545,43 @@
       A.x = const_cast<double *> (a.data ());
       A.nz = -1;
 
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
       S = CXSPARSE_DNAME (_sqr) (order, &A, 1);
       N = CXSPARSE_DNAME (_qr) (&A, S);
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
       if (! N)
         (*current_liboctave_error_handler)
           ("sparse_qr: sparse matrix QR factorization filled");
 
+    }
+
 #else
 
+    {
       octave_unused_parameter (order);
 
       (*current_liboctave_error_handler)
-        ("sparse_qr: support for CXSparse was unavailable or disabled when liboctave was built");
+        ("sparse_qr: support for SPQR or CXSparse was unavailable or disabled when liboctave was built");
+    }
 
 #endif
-    }
 
     template <>
     sparse_qr<SparseMatrix>::sparse_qr_rep::~sparse_qr_rep (void)
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      cholmod_l_free_sparse (&m_R, &m_cc);
+      cholmod_l_free_sparse (&m_H, &m_cc);
+      cholmod_l_free_dense (&m_Htau, &m_cc);
+      free (m_E);  // FIXME: use cholmod_l_free
+      free (m_HPinv);
+      cholmod_l_finish (&m_cc);
+
+#elif defined (HAVE_CXSPARSE)
+
       CXSPARSE_DNAME (_sfree) (S);
       CXSPARSE_DNAME (_nfree) (N);
+
 #endif
     }
 
@@ -233,18 +589,20 @@
     SparseMatrix
     sparse_qr<SparseMatrix>::sparse_qr_rep::V (void) const
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      return rcs2ros (m_H);
+
+#elif defined (HAVE_CXSPARSE)
 
       // Drop zeros from V and sort
       // FIXME: Is the double transpose to sort necessary?
 
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
       CXSPARSE_DNAME (_dropzeros) (N->L);
       CXSPARSE_DNAME () *D = CXSPARSE_DNAME (_transpose) (N->L, 1);
       CXSPARSE_DNAME (_spfree) (N->L);
       N->L = CXSPARSE_DNAME (_transpose) (D, 1);
       CXSPARSE_DNAME (_spfree) (D);
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
       octave_idx_type nc = N->L->n;
       octave_idx_type nz = N->L->nzmax;
@@ -272,18 +630,38 @@
     SparseMatrix
     sparse_qr<SparseMatrix>::sparse_qr_rep::R (bool econ) const
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      octave_idx_type nr = static_cast<octave_idx_type> (m_R->nrow);
+      octave_idx_type nc = static_cast<octave_idx_type> (m_R->ncol);
+      octave_idx_type nz = static_cast<octave_idx_type> (m_R->nzmax);
+
+      // FIXME: Does this work if econ = true?
+      SparseMatrix ret ((econ ? (nc > nr ? nr : nc) : nr), nc, nz);
+      SuiteSparse_long *Rp = reinterpret_cast<SuiteSparse_long *> (m_R->p);
+      SuiteSparse_long *Ri = reinterpret_cast<SuiteSparse_long *> (m_R->i);
+
+      for (octave_idx_type j = 0; j < nc + 1; j++)
+        ret.xcidx (j) = from_suitesparse_long (Rp[j]);
+
+      for (octave_idx_type j = 0; j < nz; j++)
+        {
+          ret.xridx (j) = from_suitesparse_long (Ri[j]);
+          ret.xdata (j) = (reinterpret_cast<double *> (m_R->x))[j];
+        }
+
+      return ret;
+
+#elif defined (HAVE_CXSPARSE)
 
       // Drop zeros from R and sort
       // FIXME: Is the double transpose to sort necessary?
 
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
       CXSPARSE_DNAME (_dropzeros) (N->U);
       CXSPARSE_DNAME () *D = CXSPARSE_DNAME (_transpose) (N->U, 1);
       CXSPARSE_DNAME (_spfree) (N->U);
       N->U = CXSPARSE_DNAME (_transpose) (D, 1);
       CXSPARSE_DNAME (_spfree) (D);
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
       octave_idx_type nc = N->U->n;
       octave_idx_type nz = N->U->nzmax;
@@ -312,9 +690,46 @@
 
     template <>
     Matrix
-    sparse_qr<SparseMatrix>::sparse_qr_rep::C (const Matrix& b) const
+    sparse_qr<SparseMatrix>::sparse_qr_rep::C (const Matrix &b, bool econ)
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+      octave_idx_type nr = (econ
+                            ? (ncols > nrows ? nrows : ncols)
+                            : nrows);
+      octave_idx_type b_nr = b.rows ();
+      octave_idx_type b_nc = b.cols ();
+      Matrix ret (nr, b_nc);
+
+      if (nrows != b_nr)
+        (*current_liboctave_error_handler)
+          ("sparse_qr: matrix dimension mismatch");
+      else if (b_nc <= 0 || b_nr <= 0)
+        (*current_liboctave_error_handler)
+          ("sparse_qr: matrix dimension with negative or zero size");
+
+      cholmod_dense *QTB;  // Q' * B
+      cholmod_dense B = rod2rcd (b);
+
+      QTB = SuiteSparseQR_qmult<double> (SPQR_QTX, m_H, m_Htau, m_HPinv, &B,
+                                         &m_cc);
+      spqr_error_handler (&m_cc);
+
+      // copy QTB into ret
+      double *QTB_x = reinterpret_cast<double *> (QTB->x);
+      double *ret_vec = reinterpret_cast<double *> (ret.fortran_vec ());
+      for (octave_idx_type j = 0; j < b_nc; j++)
+        for (octave_idx_type i = 0; i < nr; i++)
+          ret_vec[j * nr + i] = QTB_x[j * b_nr + i];
+
+      cholmod_l_free_dense (&QTB, &m_cc);
+
+      return ret;
+
+#elif defined (HAVE_CXSPARSE)
+
+      if (econ)
+        (*current_liboctave_error_handler)
+          ("sparse-qr: economy mode with CXSparse not supported");
 
       octave_idx_type b_nr = b.rows ();
       octave_idx_type b_nc = b.cols ();
@@ -347,17 +762,13 @@
 
               volatile octave_idx_type nm = (nr < nc ? nr : nc);
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_ipvec) (S->pinv, bvec + idx, buf, b_nr);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
               for (volatile octave_idx_type i = 0; i < nm; i++)
                 {
                   octave_quit ();
 
-                  BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
                   CXSPARSE_DNAME (_happly) (N->L, i, N->B[i], buf);
-                  END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
                 }
 
               for (octave_idx_type i = 0; i < b_nr; i++)
@@ -370,6 +781,7 @@
 #else
 
       octave_unused_parameter (b);
+      octave_unused_parameter (econ);
 
       return Matrix ();
 
@@ -378,13 +790,50 @@
 
     template <>
     Matrix
-    sparse_qr<SparseMatrix>::sparse_qr_rep::Q (void) const
+    sparse_qr<SparseMatrix>::sparse_qr_rep::Q (bool econ)
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      octave_idx_type nc = (econ
+                            ? (ncols > nrows ? nrows : ncols)
+                            : nrows);
+      Matrix ret (nrows, nc);
+      cholmod_dense *q;
+
+      // I is nrows x nrows identity matrix
+      cholmod_dense *I
+        = cholmod_l_allocate_dense (nrows, nrows, nrows, CHOLMOD_REAL, &m_cc);
+
+      for (octave_idx_type i = 0; i < nrows * nrows; i++)
+        (reinterpret_cast<double *> (I->x))[i] = 0.0;
+
+      for (octave_idx_type i = 0; i < nrows; i++)
+       (reinterpret_cast<double *> (I->x))[i * nrows + i] = 1.0;
+
+      q = SuiteSparseQR_qmult<double> (SPQR_QX, m_H, m_Htau, m_HPinv, I, &m_cc);
+      spqr_error_handler (&m_cc);
+
+      double *q_x = reinterpret_cast<double *> (q->x);
+      double *ret_vec = const_cast<double *> (ret.fortran_vec ());
+      for (octave_idx_type j = 0; j < nc; j++)
+        for (octave_idx_type i = 0; i < nrows; i++)
+          ret_vec[j * nrows + i] = q_x[j * nrows + i];
+
+      cholmod_l_free_dense (&q, &m_cc);
+      cholmod_l_free_dense (&I, &m_cc);
+
+      return ret;
+
+#elif defined (HAVE_CXSPARSE)
+
+      if (econ)
+        (*current_liboctave_error_handler)
+          ("sparse-qr: economy mode with CXSparse not supported");
+
       octave_idx_type nc = N->L->n;
       octave_idx_type nr = nrows;
       Matrix ret (nr, nr);
-      double *vec = ret.fortran_vec ();
+      double *ret_vec = ret.fortran_vec ();
 
       if (nr < 0 || nc < 0)
         (*current_liboctave_error_handler) ("matrix dimension mismatch");
@@ -400,7 +849,7 @@
 
           OCTAVE_LOCAL_BUFFER (double, buf, S->m2);
 
-          for (volatile octave_idx_type j = 0, idx = 0; j < nr; j++, idx+=nr)
+          for (volatile octave_idx_type j = 0, idx = 0; j < nr; j++, idx += nr)
             {
               octave_quit ();
 
@@ -410,21 +859,17 @@
 
               volatile octave_idx_type nm = (nr < nc ? nr : nc);
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_ipvec) (S->pinv, bvec, buf, nr);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
               for (volatile octave_idx_type i = 0; i < nm; i++)
                 {
                   octave_quit ();
 
-                  BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
                   CXSPARSE_DNAME (_happly) (N->L, i, N->B[i], buf);
-                  END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
                 }
 
               for (octave_idx_type i = 0; i < nr; i++)
-                vec[i+idx] = buf[i];
+                ret_vec[i+idx] = buf[i];
 
               bvec[j] = 0.0;
             }
@@ -434,6 +879,8 @@
 
 #else
 
+      octave_unused_parameter (econ);
+
       return Matrix ();
 
 #endif
@@ -443,11 +890,96 @@
     template <>
     Matrix
     sparse_qr<SparseMatrix>::sparse_qr_rep::tall_solve<MArray<double>, Matrix>
-    (const MArray<double>& b, octave_idx_type& info) const
+    (const MArray<double>& b, octave_idx_type& info)
     {
       info = -1;
 
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD) && defined (HAVE_CXSPARSE))
+
+      octave_idx_type b_nr = b.rows ();
+      octave_idx_type b_nc = b.cols ();
+      Matrix x (ncols, b_nc);  // X = m_E'*(m_R\(Q'*B))
+
+      if (nrows <= 0 || ncols <= 0 || b_nc <= 0 || b_nr <= 0)
+        (*current_liboctave_error_handler)
+          ("matrix dimension with negative or zero size");
+
+      if (nrows < 0 || ncols < 0 || nrows != b_nr)
+        (*current_liboctave_error_handler) ("matrix dimension mismatch");
+
+      cholmod_dense *QTB;  // Q' * B
+      cholmod_dense B = rod2rcd (b);
+
+      // FIXME: Process b column by column as in the CXSPARSE version below.
+      // This avoids a large dense matrix Q' * B in memory.
+      QTB = SuiteSparseQR_qmult<double> (SPQR_QTX, m_H, m_Htau, m_HPinv, &B,
+                                         &m_cc);
+
+      spqr_error_handler (&m_cc);
+
+      // convert m_R into CXSPARSE matrix R2
+      CXSPARSE_DNAME (_sparse) R2;
+      R2.n = ncols;
+      R2.m = ncols;
+      R2.nzmax = m_R->nzmax;
+      R2.x = reinterpret_cast<double *> (m_R->x);
+      suitesparse_integer *R2_p;
+      suitesparse_integer *R2_i;
+      if (sizeof (suitesparse_integer) == sizeof (SuiteSparse_long))
+        {
+          R2.p = reinterpret_cast<suitesparse_integer *> (m_R->p);
+          R2.i = reinterpret_cast<suitesparse_integer *> (m_R->i);
+        }
+      else
+        {
+          R2_p = new suitesparse_integer[ncols+1];
+          SuiteSparse_long * R_p = reinterpret_cast<SuiteSparse_long *> (m_R->p);
+          for (octave_idx_type i = 0; i < ncols+1; i++)
+            R2_p[i] = suitesparse_long_to_suitesparse_integer (R_p[i]);
+          R2.p = R2_p;
+          octave_idx_type nnz = m_R->nzmax;
+          R2_i = new suitesparse_integer[nnz];
+          SuiteSparse_long * R_i = reinterpret_cast<SuiteSparse_long *> (m_R->i);
+          for (octave_idx_type i = 0; i < nnz; i++)
+            R2_i[i] =  suitesparse_long_to_suitesparse_integer (R_i[i]);
+          R2.i = R2_i;
+        }
+      R2.nz = -1;
+      double *x_vec = const_cast<double *> (x.fortran_vec ());
+      suitesparse_integer *E;
+      if (sizeof (suitesparse_integer) != sizeof (SuiteSparse_long))
+        {
+          E = new suitesparse_integer [ncols];
+          for (octave_idx_type i = 0; i < ncols; i++)
+            E[i] = suitesparse_long_to_suitesparse_integer (m_E[i]);
+        }
+      else
+        E = reinterpret_cast<suitesparse_integer *> (m_E);
+      for (volatile octave_idx_type j = 0; j < b_nc; j++)
+        {
+          // fill x(:,j)
+          // solve (m_R\(Q'*B(:,j)) and store result in QTB(:,j)
+          CXSPARSE_DNAME (_usolve)
+            (&R2, &(reinterpret_cast<double *> (QTB->x)[j * b_nr]));
+          // x(:,j) = m_E' * (m_R\(Q'*B(:,j))
+          CXSPARSE_DNAME (_ipvec)
+            (E, &(reinterpret_cast<double *> (QTB->x)[j * b_nr]),
+             &x_vec[j * ncols], ncols);
+        }
+
+      if (sizeof (suitesparse_integer) != sizeof (SuiteSparse_long))
+        {
+          delete [] R2_p;
+          delete [] R2_i;
+          delete [] E;
+        }
+      cholmod_l_free_dense (&QTB, &m_cc);
+
+      info = 0;
+
+      return x;
+
+#elif defined (HAVE_CXSPARSE)
 
       octave_idx_type nr = nrows;
       octave_idx_type nc = ncols;
@@ -470,23 +1002,17 @@
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_ipvec) (S->pinv, bvec + bidx, buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_usolve) (N->U, buf);
           CXSPARSE_DNAME (_ipvec) (S->q, buf, vec + idx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
         }
 
       info = 0;
@@ -509,7 +1035,6 @@
     (const MArray<double>& b, octave_idx_type& info) const
     {
       info = -1;
-
 #if defined (HAVE_CXSPARSE)
 
       // These are swapped because the original matrix was transposed in
@@ -538,23 +1063,17 @@
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->q, bvec + bidx, buf, nr);
           CXSPARSE_DNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->pinv, buf, vec + idx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
         }
 
       info = 0;
@@ -562,7 +1081,6 @@
       return x;
 
 #else
-
       octave_unused_parameter (b);
 
       return Matrix ();
@@ -574,7 +1092,7 @@
     template <>
     SparseMatrix
     sparse_qr<SparseMatrix>::sparse_qr_rep::tall_solve<SparseMatrix, SparseMatrix>
-    (const SparseMatrix& b, octave_idx_type& info) const
+    (const SparseMatrix& b, octave_idx_type& info)
     {
       info = -1;
 
@@ -605,23 +1123,17 @@
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_ipvec) (S->pinv, Xx, buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_usolve) (N->U, buf);
           CXSPARSE_DNAME (_ipvec) (S->q, buf, Xx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
@@ -698,23 +1210,17 @@
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->q, Xx, buf, nr);
           CXSPARSE_DNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->pinv, buf, Xx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
@@ -758,7 +1264,7 @@
     template <>
     ComplexMatrix
     sparse_qr<SparseMatrix>::sparse_qr_rep::tall_solve<MArray<Complex>, ComplexMatrix>
-    (const MArray<Complex>& b, octave_idx_type& info) const
+    (const MArray<Complex>& b, octave_idx_type& info)
     {
       info = -1;
 
@@ -791,20 +1297,15 @@
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_ipvec) (S->pinv, Xx, buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_usolve) (N->U, buf);
           CXSPARSE_DNAME (_ipvec) (S->q, buf, Xx, nc);
 
@@ -812,21 +1313,16 @@
             buf[j] = 0.;
 
           CXSPARSE_DNAME (_ipvec) (S->pinv, Xz, buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_usolve) (N->U, buf);
           CXSPARSE_DNAME (_ipvec) (S->q, buf, Xz, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             vec[j+idx] = Complex (Xx[j], Xz[j]);
@@ -887,44 +1383,32 @@
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->q, Xx, buf, nr);
           CXSPARSE_DNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->pinv, buf, Xx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->q, Xz, buf, nr);
           CXSPARSE_DNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->pinv, buf, Xz, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             vec[j+idx] = Complex (Xx[j], Xz[j]);
@@ -948,13 +1432,41 @@
     template <>
     sparse_qr<SparseComplexMatrix>::sparse_qr_rep::sparse_qr_rep
     (const SparseComplexMatrix& a, int order)
-      : count (1), nrows (a.rows ()), ncols (a.columns ())
-#if defined (HAVE_CXSPARSE)
-      , S (nullptr), N (nullptr)
-#endif
+      : nrows (a.rows ()), ncols (a.columns ())
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+        , m_cc (), m_R (nullptr), m_E (nullptr), m_H (nullptr),
+          m_Htau (nullptr), m_HPinv (nullptr)
     {
-#if defined (HAVE_CXSPARSE)
-
+      octave_idx_type nr = a.rows ();
+      octave_idx_type nc = a.cols ();
+
+      if (nr <= 0 || nc <= 0)
+        (*current_liboctave_error_handler)
+          ("matrix dimension with negative or zero size");
+
+      if (order < 0 || order > 9)
+        (*current_liboctave_error_handler)
+          ("ordering %d is not supported by SPQR", order);
+
+      cholmod_l_start (&m_cc);
+      cholmod_sparse A = cos2ccs (a);
+
+      SuiteSparseQR<Complex> (order, static_cast<double> (SPQR_DEFAULT_TOL),
+                              static_cast<SuiteSparse_long> (A.nrow),
+                              &A, &m_R, &m_E, &m_H,
+                              &m_HPinv, &m_Htau, &m_cc);
+      spqr_error_handler (&m_cc);
+
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.i);
+        }
+    }
+
+#elif defined (HAVE_CXSPARSE)
+        , S (nullptr), N (nullptr)
+    {
       CXSPARSE_ZNAME () A;
 
       A.nzmax = a.nnz ();
@@ -970,31 +1482,43 @@
               (reinterpret_cast<const cs_complex_t *> (a.data ()));
       A.nz = -1;
 
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
       S = CXSPARSE_ZNAME (_sqr) (order, &A, 1);
       N = CXSPARSE_ZNAME (_qr) (&A, S);
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
       if (! N)
         (*current_liboctave_error_handler)
           ("sparse_qr: sparse matrix QR factorization filled");
 
+    }
+
 #else
 
+    {
       octave_unused_parameter (order);
 
       (*current_liboctave_error_handler)
         ("sparse_qr: support for CXSparse was unavailable or disabled when liboctave was built");
+    }
 
 #endif
-    }
 
     template <>
     sparse_qr<SparseComplexMatrix>::sparse_qr_rep::~sparse_qr_rep (void)
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      cholmod_l_free_sparse (&m_R, &m_cc);
+      cholmod_l_free_sparse (&m_H, &m_cc);
+      cholmod_l_free_dense (&m_Htau, &m_cc);
+      free (m_E);  // FIXME: use cholmod_l_free
+      free (m_HPinv);
+      cholmod_l_finish (&m_cc);
+
+#elif defined (HAVE_CXSPARSE)
+
       CXSPARSE_ZNAME (_sfree) (S);
       CXSPARSE_ZNAME (_nfree) (N);
+
 #endif
     }
 
@@ -1006,13 +1530,11 @@
       // Drop zeros from V and sort
       // FIXME: Is the double transpose to sort necessary?
 
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
       CXSPARSE_ZNAME (_dropzeros) (N->L);
       CXSPARSE_ZNAME () *D = CXSPARSE_ZNAME (_transpose) (N->L, 1);
       CXSPARSE_ZNAME (_spfree) (N->L);
       N->L = CXSPARSE_ZNAME (_transpose) (D, 1);
       CXSPARSE_ZNAME (_spfree) (D);
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
       octave_idx_type nc = N->L->n;
       octave_idx_type nz = N->L->nzmax;
@@ -1024,7 +1546,7 @@
       for (octave_idx_type j = 0; j < nz; j++)
         {
           ret.xridx (j) = N->L->i[j];
-          ret.xdata (j) = reinterpret_cast<Complex *>(N->L->x)[j];
+          ret.xdata (j) = reinterpret_cast<Complex *> (N->L->x)[j];
         }
 
       return ret;
@@ -1040,17 +1562,38 @@
     SparseComplexMatrix
     sparse_qr<SparseComplexMatrix>::sparse_qr_rep::R (bool econ) const
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      octave_idx_type nr = from_size_t (m_R->nrow);
+      octave_idx_type nc = from_size_t (m_R->ncol);
+      octave_idx_type nz = from_size_t (m_R->nzmax);
+
+      // FIXME: Does this work if econ = true?
+      SparseComplexMatrix ret ((econ ? (nc > nr ? nr : nc) : nr), nc, nz);
+      SuiteSparse_long *Rp = reinterpret_cast<SuiteSparse_long *> (m_R->p);
+      SuiteSparse_long *Ri = reinterpret_cast<SuiteSparse_long *> (m_R->i);
+
+      for (octave_idx_type j = 0; j < nc + 1; j++)
+        ret.xcidx (j) = from_suitesparse_long (Rp[j]);
+
+      for (octave_idx_type j = 0; j < nz; j++)
+        {
+          ret.xridx (j) = from_suitesparse_long (Ri[j]);
+          ret.xdata (j) = (reinterpret_cast<Complex *> (m_R->x))[j];
+        }
+
+      return ret;
+
+#elif defined (HAVE_CXSPARSE)
+
       // Drop zeros from R and sort
       // FIXME: Is the double transpose to sort necessary?
 
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
       CXSPARSE_ZNAME (_dropzeros) (N->U);
       CXSPARSE_ZNAME () *D = CXSPARSE_ZNAME (_transpose) (N->U, 1);
       CXSPARSE_ZNAME (_spfree) (N->U);
       N->U = CXSPARSE_ZNAME (_transpose) (D, 1);
       CXSPARSE_ZNAME (_spfree) (D);
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
       octave_idx_type nc = N->U->n;
       octave_idx_type nz = N->U->nzmax;
@@ -1080,9 +1623,50 @@
 
     template <>
     ComplexMatrix
-    sparse_qr<SparseComplexMatrix>::sparse_qr_rep::C (const ComplexMatrix& b) const
+    sparse_qr<SparseComplexMatrix>::sparse_qr_rep::C
+    (const ComplexMatrix& b, bool econ)
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      // FIXME: not tested
+      octave_idx_type nr = (econ
+                            ? (ncols > nrows ? nrows : ncols)
+                            : nrows);
+      octave_idx_type b_nr = b.rows ();
+      octave_idx_type b_nc = b.cols ();
+      ComplexMatrix ret (nr, b_nc);
+
+      if (nrows != b_nr)
+        (*current_liboctave_error_handler) ("matrix dimension mismatch");
+
+      if (b_nc <= 0 || b_nr <= 0)
+        (*current_liboctave_error_handler)
+          ("matrix dimension with negative or zero size");
+
+      cholmod_dense *QTB;  // Q' * B
+      cholmod_dense B = cod2ccd (b);
+
+      QTB = SuiteSparseQR_qmult<Complex> (SPQR_QTX, m_H, m_Htau, m_HPinv, &B,
+                                          &m_cc);
+      spqr_error_handler (&m_cc);
+
+      // copy QTB into ret
+      Complex *QTB_x = reinterpret_cast<Complex *> (QTB->x);
+      Complex *ret_vec = reinterpret_cast<Complex *> (ret.fortran_vec ());
+      for (octave_idx_type j = 0; j < b_nc; j++)
+        for (octave_idx_type i = 0; i < nr; i++)
+          ret_vec[j * nr + i] = QTB_x[j * b_nr + i];
+
+      cholmod_l_free_dense (&QTB, &m_cc);
+
+      return ret;
+
+#elif defined (HAVE_CXSPARSE)
+
+      if (econ)
+        (*current_liboctave_error_handler)
+          ("sparse-qr: economy mode with CXSparse not supported");
+
       octave_idx_type b_nr = b.rows ();
       octave_idx_type b_nc = b.cols ();
       octave_idx_type nc = N->L->n;
@@ -1109,20 +1693,16 @@
 
               volatile octave_idx_type nm = (nr < nc ? nr : nc);
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_ipvec) (S->pinv, bvec + idx,
                                        reinterpret_cast<cs_complex_t *> (buf),
                                        b_nr);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
               for (volatile octave_idx_type i = 0; i < nm; i++)
                 {
                   octave_quit ();
 
-                  BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
                   CXSPARSE_ZNAME (_happly) (N->L, i, N->B[i],
                                             reinterpret_cast<cs_complex_t *> (buf));
-                  END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
                 }
 
               for (octave_idx_type i = 0; i < b_nr; i++)
@@ -1135,6 +1715,7 @@
 #else
 
       octave_unused_parameter (b);
+      octave_unused_parameter (econ);
 
       return ComplexMatrix ();
 
@@ -1143,9 +1724,49 @@
 
     template <>
     ComplexMatrix
-    sparse_qr<SparseComplexMatrix>::sparse_qr_rep::Q (void) const
+    sparse_qr<SparseComplexMatrix>::sparse_qr_rep::Q (bool econ)
     {
-#if defined (HAVE_CXSPARSE)
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      octave_idx_type nc = (econ
+                            ? (ncols > nrows ? nrows : ncols)
+                            : nrows);
+      ComplexMatrix ret (nrows, nc);
+      cholmod_dense *q;
+
+      // I is nrows x nrows identity matrix
+      cholmod_dense *I
+        = reinterpret_cast<cholmod_dense *>
+            (cholmod_l_allocate_dense (nrows, nrows, nrows, CHOLMOD_COMPLEX, &m_cc));
+
+      for (octave_idx_type i = 0; i < nrows * nrows; i++)
+        (reinterpret_cast<Complex *> (I->x))[i] = 0.0;
+
+      for (octave_idx_type i = 0; i < nrows; i++)
+        (reinterpret_cast<Complex *> (I->x))[i * nrows + i] = 1.0;
+
+      q = SuiteSparseQR_qmult<Complex> (SPQR_QX, m_H, m_Htau, m_HPinv, I,
+                                        &m_cc);
+      spqr_error_handler (&m_cc);
+
+      Complex *q_x = reinterpret_cast<Complex *> (q->x);
+      Complex *ret_vec = const_cast<Complex*> (ret.fortran_vec ());
+
+      for (octave_idx_type j = 0; j < nc; j++)
+        for (octave_idx_type i = 0; i < nrows; i++)
+          ret_vec[j * nrows + i] = q_x[j * nrows + i];
+
+      cholmod_l_free_dense (&q, &m_cc);
+      cholmod_l_free_dense (&I, &m_cc);
+
+      return ret;
+
+#elif defined (HAVE_CXSPARSE)
+
+      if (econ)
+        (*current_liboctave_error_handler)
+          ("sparse-qr: economy mode with CXSparse not supported");
+
       octave_idx_type nc = N->L->n;
       octave_idx_type nr = nrows;
       ComplexMatrix ret (nr, nr);
@@ -1173,20 +1794,16 @@
 
               volatile octave_idx_type nm = (nr < nc ? nr : nc);
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_ipvec) (S->pinv, bvec,
                                        reinterpret_cast<cs_complex_t *> (buf),
                                        nr);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
               for (volatile octave_idx_type i = 0; i < nm; i++)
                 {
                   octave_quit ();
 
-                  BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
                   CXSPARSE_ZNAME (_happly) (N->L, i, N->B[i],
                                             reinterpret_cast<cs_complex_t *> (buf));
-                  END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
                 }
 
               for (octave_idx_type i = 0; i < nr; i++)
@@ -1200,6 +1817,8 @@
 
 #else
 
+      octave_unused_parameter (econ);
+
       return ComplexMatrix ();
 
 #endif
@@ -1210,7 +1829,7 @@
     SparseComplexMatrix
     sparse_qr<SparseMatrix>::sparse_qr_rep::tall_solve<SparseComplexMatrix,
                                                        SparseComplexMatrix>
-      (const SparseComplexMatrix& b, octave_idx_type& info) const
+      (const SparseComplexMatrix& b, octave_idx_type& info)
     {
       info = -1;
 
@@ -1246,44 +1865,32 @@
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_ipvec) (S->pinv, Xx, buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_usolve) (N->U, buf);
           CXSPARSE_DNAME (_ipvec) (S->q, buf, Xx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_ipvec) (S->pinv, Xz, buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_usolve) (N->U, buf);
           CXSPARSE_DNAME (_ipvec) (S->q, buf, Xz, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
@@ -1366,44 +1973,32 @@
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->q, Xx, buf, nr);
           CXSPARSE_DNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->pinv, buf, Xx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = 0.;
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->q, Xz, buf, nr);
           CXSPARSE_DNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_DNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_DNAME (_pvec) (S->pinv, buf, Xz, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
@@ -1448,7 +2043,7 @@
     ComplexMatrix
     sparse_qr<SparseComplexMatrix>::sparse_qr_rep::tall_solve<MArray<double>,
                                                               ComplexMatrix>
-      (const MArray<double>& b, octave_idx_type& info) const
+      (const MArray<double>& b, octave_idx_type& info)
     {
       info = -1;
 
@@ -1476,25 +2071,19 @@
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = cs_complex_t (0.0, 0.0);
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_ipvec) (S->pinv,
                                    reinterpret_cast<cs_complex_t *>(Xx),
                                    buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_usolve) (N->U, buf);
           CXSPARSE_ZNAME (_ipvec) (S->q, buf, vec + idx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
         }
 
       info = 0;
@@ -1552,24 +2141,18 @@
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = cs_complex_t (0.0, 0.0);
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-          CXSPARSE_ZNAME (_pvec) (S->q, reinterpret_cast<cs_complex_t *>(Xx),
+          CXSPARSE_ZNAME (_pvec) (S->q, reinterpret_cast<cs_complex_t *> (Xx),
                                   buf, nr);
           CXSPARSE_ZNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_happly) (N->L, j, B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_pvec) (S->pinv, buf, vec + idx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
         }
 
       info = 0;
@@ -1590,7 +2173,7 @@
     SparseComplexMatrix
     sparse_qr<SparseComplexMatrix>::sparse_qr_rep::tall_solve<SparseMatrix,
                                                               SparseComplexMatrix>
-      (const SparseMatrix& b, octave_idx_type& info) const
+      (const SparseMatrix& b, octave_idx_type& info)
     {
       info = -1;
 
@@ -1621,27 +2204,21 @@
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = cs_complex_t (0.0, 0.0);
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_ipvec) (S->pinv,
-                                   reinterpret_cast<cs_complex_t *>(Xx),
+                                   reinterpret_cast<cs_complex_t *> (Xx),
                                    buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_usolve) (N->U, buf);
           CXSPARSE_ZNAME (_ipvec) (S->q, buf,
                                    reinterpret_cast<cs_complex_t *> (Xx),
                                    nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
@@ -1725,27 +2302,21 @@
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = cs_complex_t (0.0, 0.0);
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_pvec) (S->q,
-                                  reinterpret_cast<cs_complex_t *>(Xx),
+                                  reinterpret_cast<cs_complex_t *> (Xx),
                                   buf, nr);
           CXSPARSE_ZNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_happly) (N->L, j, B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_pvec) (S->pinv, buf,
                                   reinterpret_cast<cs_complex_t *> (Xx),
                                   nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
@@ -1790,7 +2361,7 @@
     ComplexMatrix
     sparse_qr<SparseComplexMatrix>::sparse_qr_rep::tall_solve<MArray<Complex>,
                                                               ComplexMatrix>
-      (const MArray<Complex>& b, octave_idx_type& info) const
+      (const MArray<Complex>& b, octave_idx_type& info)
     {
       info = -1;
 
@@ -1819,23 +2390,17 @@
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = cs_complex_t (0.0, 0.0);
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_ipvec) (S->pinv, bvec + bidx, buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_usolve) (N->U, buf);
           CXSPARSE_ZNAME (_ipvec) (S->q, buf, vec + idx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
         }
 
       info = 0;
@@ -1893,23 +2458,17 @@
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = cs_complex_t (0.0, 0.0);
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_pvec) (S->q, bvec + bidx, buf, nr);
           CXSPARSE_ZNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_happly) (N->L, j, B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_pvec) (S->pinv, buf, vec + idx, nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
         }
 
       info = 0;
@@ -1928,8 +2487,9 @@
     template <>
     template <>
     SparseComplexMatrix
-    sparse_qr<SparseComplexMatrix>::sparse_qr_rep::tall_solve<SparseComplexMatrix, SparseComplexMatrix>
-      (const SparseComplexMatrix& b, octave_idx_type& info) const
+    sparse_qr<SparseComplexMatrix>::sparse_qr_rep::tall_solve<SparseComplexMatrix,
+                                                              SparseComplexMatrix>
+      (const SparseComplexMatrix& b, octave_idx_type& info)
     {
       info = -1;
 
@@ -1960,27 +2520,21 @@
           for (octave_idx_type j = nr; j < S->m2; j++)
             buf[j] = cs_complex_t (0.0, 0.0);
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_ipvec) (S->pinv,
-                                   reinterpret_cast<cs_complex_t *>(Xx),
+                                   reinterpret_cast<cs_complex_t *> (Xx),
                                    buf, nr);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = 0; j < nc; j++)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_happly) (N->L, j, N->B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_usolve) (N->U, buf);
           CXSPARSE_ZNAME (_ipvec) (S->q, buf,
                                    reinterpret_cast<cs_complex_t *> (Xx),
                                    nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
@@ -2023,7 +2577,8 @@
     template <>
     template <>
     SparseComplexMatrix
-    sparse_qr<SparseComplexMatrix>::sparse_qr_rep::wide_solve<SparseComplexMatrix, SparseComplexMatrix>
+    sparse_qr<SparseComplexMatrix>::sparse_qr_rep::wide_solve<SparseComplexMatrix,
+                                                              SparseComplexMatrix>
       (const SparseComplexMatrix& b, octave_idx_type& info) const
     {
       info = -1;
@@ -2063,25 +2618,19 @@
           for (octave_idx_type j = nr; j < nbuf; j++)
             buf[j] = cs_complex_t (0.0, 0.0);
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_pvec) (S->q, reinterpret_cast<cs_complex_t *>(Xx),
                                   buf, nr);
           CXSPARSE_ZNAME (_utsolve) (N->U, buf);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (volatile octave_idx_type j = nr-1; j >= 0; j--)
             {
               octave_quit ();
 
-              BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
               CXSPARSE_ZNAME (_happly) (N->L, j, B[j], buf);
-              END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
             }
 
-          BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
           CXSPARSE_ZNAME (_pvec) (S->pinv, buf,
                                   reinterpret_cast<cs_complex_t *>(Xx), nc);
-          END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
@@ -2132,36 +2681,6 @@
     { }
 
     template <typename SPARSE_T>
-    sparse_qr<SPARSE_T>::sparse_qr (const sparse_qr<SPARSE_T>& a)
-      : rep (a.rep)
-    {
-      rep->count++;
-    }
-
-    template <typename SPARSE_T>
-    sparse_qr<SPARSE_T>::~sparse_qr (void)
-    {
-      if (--rep->count == 0)
-        delete rep;
-    }
-
-    template <typename SPARSE_T>
-    sparse_qr<SPARSE_T>&
-    sparse_qr<SPARSE_T>::operator = (const sparse_qr<SPARSE_T>& a)
-    {
-      if (this != &a)
-        {
-          if (--rep->count == 0)
-            delete rep;
-
-          rep = a.rep;
-          rep->count++;
-        }
-
-      return *this;
-    }
-
-    template <typename SPARSE_T>
     bool
     sparse_qr<SPARSE_T>::ok (void) const
     {
@@ -2190,6 +2709,27 @@
     }
 
     template <typename SPARSE_T>
+    ColumnVector
+    sparse_qr<SPARSE_T>::E (void) const
+    {
+      return rep->E();
+    }
+
+
+    template <typename SPARSE_T>
+    SparseMatrix
+    sparse_qr<SPARSE_T>::E_MAT (void) const
+    {
+      ColumnVector perm = rep->E ();
+      octave_idx_type nrows = perm.rows ();
+      SparseMatrix ret (nrows,nrows,nrows);
+      for (octave_idx_type i = 0; i < nrows; i++)
+        ret(perm(i) - 1,i) = 1.0;
+      return ret;
+    }
+
+
+    template <typename SPARSE_T>
     SPARSE_T
     sparse_qr<SPARSE_T>::R (bool econ) const
     {
@@ -2198,18 +2738,327 @@
 
     template <typename SPARSE_T>
     typename SPARSE_T::dense_matrix_type
-    sparse_qr<SPARSE_T>::C (const typename SPARSE_T::dense_matrix_type& b) const
+    sparse_qr<SPARSE_T>::C (const typename SPARSE_T::dense_matrix_type& b,
+                            bool econ) const
     {
-      return rep->C (b);
+      return rep->C (b, econ);
     }
 
     template <typename SPARSE_T>
     typename SPARSE_T::dense_matrix_type
-    sparse_qr<SPARSE_T>::Q (void) const
+    sparse_qr<SPARSE_T>::Q (bool econ) const
+    {
+      return rep->Q (econ);
+    }
+
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+    //specializations of function min2norm_solve
+    template <>
+    template <>
+    OCTAVE_API Matrix
+    sparse_qr<SparseMatrix>::min2norm_solve<MArray<double>, Matrix>
+    (const SparseMatrix& a, const MArray<double>& b,
+     octave_idx_type& info, int order)
+    {
+      info = -1;
+      octave_idx_type b_nc = b.cols ();
+      octave_idx_type nc = a.cols ();
+      Matrix x (nc, b_nc);
+      cholmod_common cc;
+
+      cholmod_l_start (&cc);
+      cholmod_sparse A = ros2rcs (a);
+      cholmod_dense B = rod2rcd (b);
+      cholmod_dense *X;
+
+      X = SuiteSparseQR_min2norm<double> (order, SPQR_DEFAULT_TOL, &A, &B, &cc);
+      spqr_error_handler (&cc);
+
+      double *vec = x.fortran_vec ();
+      for (volatile octave_idx_type i = 0; i < nc * b_nc; i++)
+        vec[i] = reinterpret_cast<double *> (X->x)[i];
+
+      info = 0;
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.i);
+        }
+      cholmod_l_finish (&cc);
+
+      return x;
+
+    }
+
+    template <>
+    template <>
+    OCTAVE_API SparseMatrix
+    sparse_qr<SparseMatrix>::min2norm_solve<SparseMatrix, SparseMatrix>
+    (const SparseMatrix& a, const SparseMatrix& b, octave_idx_type& info,
+     int order)
+    {
+      info = -1;
+      SparseMatrix x;
+      cholmod_common cc;
+
+      cholmod_l_start (&cc);
+      cholmod_sparse A = ros2rcs (a);
+      cholmod_sparse B = ros2rcs (b);
+      cholmod_sparse *X;
+
+      X = SuiteSparseQR_min2norm<double> (order, SPQR_DEFAULT_TOL, &A, &B, &cc);
+      spqr_error_handler (&cc);
+
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.i);
+          delete [] reinterpret_cast<SuiteSparse_long *> (B.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (B.i);
+        }
+
+      x = rcs2ros (X);
+      cholmod_l_finish (&cc);
+      info = 0;
+
+      return x;
+
+    }
+
+    template <>
+    template <>
+    OCTAVE_API ComplexMatrix
+    sparse_qr<SparseMatrix>::min2norm_solve<MArray<Complex>, ComplexMatrix>
+    (const SparseMatrix& a, const MArray<Complex>& b,
+     octave_idx_type& info, int order)
+    {
+      info = -1;
+
+      octave_idx_type b_nc = b.cols ();
+      octave_idx_type nc = a.cols ();
+
+      ComplexMatrix x (nc, b_nc);
+
+      cholmod_common cc;
+
+      cholmod_l_start (&cc);
+
+      cholmod_sparse *A = ros2ccs (a, &cc);
+      cholmod_dense B = cod2ccd (b);
+      cholmod_dense *X;
+
+      X = SuiteSparseQR_min2norm<Complex> (order, SPQR_DEFAULT_TOL, A, &B, &cc);
+      spqr_error_handler (&cc);
+
+      Complex *vec = x.fortran_vec ();
+      for (volatile octave_idx_type i = 0; i < nc * b_nc; i++)
+        vec[i] = reinterpret_cast<Complex *> (X->x)[i];
+
+      cholmod_l_free_sparse (&A, &cc);
+      cholmod_l_finish (&cc);
+
+      info = 0;
+
+      return x;
+
+    }
+
+    template <>
+    template <>
+    OCTAVE_API SparseComplexMatrix
+    sparse_qr<SparseMatrix>::min2norm_solve<SparseComplexMatrix,
+                                            SparseComplexMatrix>
+    (const SparseMatrix& a, const SparseComplexMatrix& b,
+     octave_idx_type& info, int order)
     {
-      return rep->Q ();
+      info = -1;
+
+      cholmod_common cc;
+
+      cholmod_l_start (&cc);
+
+      cholmod_sparse *A = ros2ccs (a, &cc);
+      cholmod_sparse B = cos2ccs (b);
+      cholmod_sparse *X;
+
+      X = SuiteSparseQR_min2norm<Complex> (order, SPQR_DEFAULT_TOL, A, &B, &cc);
+      spqr_error_handler (&cc);
+
+      cholmod_l_free_sparse (&A, &cc);
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (B.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (B.i);
+        }
+      cholmod_l_finish (&cc);
+
+      SparseComplexMatrix ret = ccs2cos(X);
+
+      info = 0;
+
+      return ret;
+
+    }
+
+    template <>
+    template <>
+    OCTAVE_API ComplexMatrix
+    sparse_qr<SparseComplexMatrix>::min2norm_solve<MArray<Complex>,
+                                                   ComplexMatrix>
+    (const SparseComplexMatrix& a, const MArray<Complex>& b,
+     octave_idx_type& info,int order)
+    {
+      info = -1;
+      octave_idx_type b_nc = b.cols ();
+      octave_idx_type nc = a.cols ();
+      ComplexMatrix x (nc, b_nc);
+
+      cholmod_common cc;
+
+      cholmod_l_start (&cc);
+
+      cholmod_sparse A = cos2ccs (a);
+      cholmod_dense B = cod2ccd (b);
+      cholmod_dense *X;
+
+      X = SuiteSparseQR_min2norm<Complex> (order, SPQR_DEFAULT_TOL, &A, &B, &cc);
+      spqr_error_handler (&cc);
+
+      Complex *vec = x.fortran_vec ();
+      for (volatile octave_idx_type i = 0; i < nc * b_nc; i++)
+        vec[i] = reinterpret_cast<Complex *> (X->x)[i];
+
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.i);
+        }
+      cholmod_l_finish (&cc);
+
+      info = 0;
+
+      return x;
+
     }
 
+    template <>
+    template <>
+    OCTAVE_API ComplexMatrix
+    sparse_qr<SparseComplexMatrix>::min2norm_solve<MArray<double>,
+                                                   ComplexMatrix>
+    (const SparseComplexMatrix& a, const MArray<double>& b,
+     octave_idx_type& info, int order)
+    {
+      info = -1;
+
+      octave_idx_type b_nc = b.cols ();
+      octave_idx_type nc = a.cols ();
+      ComplexMatrix x (nc, b_nc);
+
+      cholmod_common cc;
+
+      cholmod_l_start (&cc);
+
+      cholmod_sparse A = cos2ccs (a);
+      cholmod_dense *B = rod2ccd (b, &cc);
+      cholmod_dense *X;
+
+      X = SuiteSparseQR_min2norm<Complex> (order, SPQR_DEFAULT_TOL, &A, B, &cc);
+      spqr_error_handler (&cc);
+
+      Complex *vec = x.fortran_vec ();
+
+      for (volatile octave_idx_type i = 0; i < nc * b_nc; i++)
+       vec[i] = reinterpret_cast<Complex *> (X->x)[i];
+
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.i);
+        }
+      cholmod_l_free_dense (&B, &cc);
+      cholmod_l_finish (&cc);
+
+      info = 0;
+
+      return x;
+
+    }
+
+    template <>
+    template <>
+    OCTAVE_API SparseComplexMatrix
+    sparse_qr<SparseComplexMatrix>::min2norm_solve<SparseComplexMatrix,
+                                                   SparseComplexMatrix>
+    (const SparseComplexMatrix& a, const SparseComplexMatrix& b,
+     octave_idx_type& info, int order)
+    {
+      info = -1;
+
+      cholmod_common cc;
+
+      cholmod_l_start (&cc);
+
+      cholmod_sparse A = cos2ccs (a);
+      cholmod_sparse B = cos2ccs (b);
+      cholmod_sparse *X;
+
+      X = SuiteSparseQR_min2norm<Complex> (order, SPQR_DEFAULT_TOL, &A, &B, &cc);
+      spqr_error_handler (&cc);
+
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.i);
+          delete [] reinterpret_cast<SuiteSparse_long *> (B.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (B.i);
+        }
+      cholmod_l_finish (&cc);
+
+      info = 0;
+
+      return ccs2cos (X);
+
+    }
+
+    template <>
+    template <>
+    OCTAVE_API SparseComplexMatrix
+    sparse_qr<SparseComplexMatrix>::min2norm_solve<SparseMatrix,
+                                                   SparseComplexMatrix>
+    (const SparseComplexMatrix& a, const SparseMatrix& b,
+     octave_idx_type& info,int order)
+    {
+      info = -1;
+
+      cholmod_common cc;
+
+      cholmod_l_start (&cc);
+
+      cholmod_sparse A = cos2ccs (a);
+      cholmod_sparse *B = ros2ccs (b, &cc);
+      cholmod_sparse *X;
+
+      X = SuiteSparseQR_min2norm<Complex> (order, SPQR_DEFAULT_TOL, &A, B, &cc);
+      spqr_error_handler (&cc);
+
+      SparseComplexMatrix ret = ccs2cos(X);
+
+      if (sizeof (octave_idx_type) != sizeof (SuiteSparse_long))
+        {
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.p);
+          delete [] reinterpret_cast<SuiteSparse_long *> (A.i);
+        }
+      cholmod_l_free_sparse (&B, &cc);
+      cholmod_l_finish (&cc);
+
+      info = 0;
+
+      return ret;
+
+    }
+#endif
+
     // FIXME: Why is the "order" of the QR calculation as used in the
     // CXSparse function sqr 3 for real matrices and 2 for complex?  These
     // values seem to be required but there was no explanation in David
@@ -2228,7 +3077,11 @@
     cxsparse_defaults<SparseMatrix>
     {
     public:
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+      enum { order = SPQR_ORDERING_DEFAULT };
+#elif defined (HAVE_CXSPARSE)
       enum { order = 3 };
+#endif
     };
 
     template <>
@@ -2236,7 +3089,11 @@
     cxsparse_defaults<SparseComplexMatrix>
     {
     public:
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+      enum { order = SPQR_ORDERING_DEFAULT };
+#elif defined (HAVE_CXSPARSE)
       enum { order = 2 };
+#endif
     };
 
     template <typename SPARSE_T>
@@ -2245,6 +3102,32 @@
     sparse_qr<SPARSE_T>::solve (const SPARSE_T& a, const RHS_T& b,
                                 octave_idx_type& info)
     {
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+
+      info = -1;
+
+      octave_idx_type nr = a.rows ();
+      octave_idx_type nc = a.cols ();
+
+      octave_idx_type b_nc = b.cols ();
+      octave_idx_type b_nr = b.rows ();
+
+      int order = cxsparse_defaults<SPARSE_T>::order;
+
+      if (nr <= 0 || nc <= 0 || b_nc <= 0 || b_nr <= 0)
+        (*current_liboctave_error_handler)
+          ("matrix dimension with negative or zero size");
+
+      if ( nr != b_nr)
+        (*current_liboctave_error_handler)
+          ("matrix dimension mismatch in solution of minimum norm problem");
+
+      info = 0;
+
+      return min2norm_solve<RHS_T, RET_T> (a, b, info, order);
+
+#elif defined (HAVE_CXSPARSE)
+
       info = -1;
 
       octave_idx_type nr = a.rows ();
@@ -2277,8 +3160,74 @@
 
           return q.ok () ? q.wide_solve<RHS_T, RET_T> (b, info) : RET_T ();
         }
+
+#else
+
+      octave_unused_parameter (a);
+      octave_unused_parameter (b);
+      octave_unused_parameter (info);
+
+      return RET_T ();
+
+#endif
     }
 
+    //explicit instantiations of static member function solve
+    template
+    OCTAVE_API Matrix
+    sparse_qr<SparseMatrix>::solve<MArray<double>, Matrix>
+    (const SparseMatrix& a, const MArray<double>& b, octave_idx_type& info);
+
+    template
+    OCTAVE_API SparseMatrix
+    sparse_qr<SparseMatrix>::solve<SparseMatrix, SparseMatrix>
+    (const SparseMatrix& a, const SparseMatrix& b, octave_idx_type& info);
+
+    template
+    OCTAVE_API ComplexMatrix
+    sparse_qr<SparseMatrix>::solve<MArray<Complex>, ComplexMatrix>
+    (const SparseMatrix& a, const MArray<Complex>& b, octave_idx_type& info);
+
+    template
+    OCTAVE_API SparseComplexMatrix
+    sparse_qr<SparseMatrix>::solve<SparseComplexMatrix, SparseComplexMatrix>
+    (const SparseMatrix& a, const SparseComplexMatrix& b,
+     octave_idx_type& info);
+
+    template
+    OCTAVE_API ComplexMatrix
+    sparse_qr<SparseComplexMatrix>::solve<MArray<Complex>, ComplexMatrix>
+    (const SparseComplexMatrix& a, const MArray<Complex>& b,
+     octave_idx_type& info);
+
+    template
+    OCTAVE_API SparseComplexMatrix
+    sparse_qr<SparseComplexMatrix>::solve<
+    SparseComplexMatrix, SparseComplexMatrix>
+    (const SparseComplexMatrix& a, const SparseComplexMatrix& b,
+     octave_idx_type& info);
+
+    template
+    OCTAVE_API ComplexMatrix
+    sparse_qr<SparseComplexMatrix>::solve<MArray<double>, ComplexMatrix>
+    (const SparseComplexMatrix& a, const MArray<double>& b,
+     octave_idx_type& info);
+
+    template
+    OCTAVE_API SparseComplexMatrix
+    sparse_qr<SparseComplexMatrix>::solve<SparseMatrix, SparseComplexMatrix>
+    (const SparseComplexMatrix& a, const SparseMatrix& b,
+     octave_idx_type& info);
+
+    //explicit instantiations of member function E_MAT
+    template
+    OCTAVE_API SparseMatrix
+    sparse_qr<SparseMatrix>::E_MAT (void) const;
+
+    template
+    OCTAVE_API SparseMatrix
+    sparse_qr<SparseComplexMatrix>::E_MAT (void) const;
+
     template <typename SPARSE_T>
     template <typename RHS_T, typename RET_T>
     RET_T
@@ -2295,6 +3244,42 @@
       return rep->template wide_solve<RHS_T, RET_T> (b, info);
     }
 
+    // Explicitly instantiate all member functions
+
+    template OCTAVE_API sparse_qr<SparseMatrix>::sparse_qr (void);
+    template OCTAVE_API
+    sparse_qr<SparseMatrix>::sparse_qr (const SparseMatrix& a, int order);
+    template OCTAVE_API bool sparse_qr<SparseMatrix>::ok (void) const;
+    template OCTAVE_API ColumnVector sparse_qr<SparseMatrix>::E (void) const;
+    template OCTAVE_API SparseMatrix sparse_qr<SparseMatrix>::V (void) const;
+    template OCTAVE_API ColumnVector sparse_qr<SparseMatrix>::Pinv (void) const;
+    template OCTAVE_API ColumnVector sparse_qr<SparseMatrix>::P (void) const;
+    template OCTAVE_API SparseMatrix
+    sparse_qr<SparseMatrix>::R (bool econ) const;
+    template OCTAVE_API Matrix
+    sparse_qr<SparseMatrix>::C (const Matrix& b, bool econ) const;
+    template OCTAVE_API Matrix sparse_qr<SparseMatrix>::Q (bool econ) const;
+
+    template OCTAVE_API sparse_qr<SparseComplexMatrix>::sparse_qr (void);
+    template OCTAVE_API
+    sparse_qr<SparseComplexMatrix>::sparse_qr
+    (const SparseComplexMatrix& a, int order);
+    template OCTAVE_API bool sparse_qr<SparseComplexMatrix>::ok (void) const;
+    template OCTAVE_API ColumnVector
+    sparse_qr<SparseComplexMatrix>::E (void) const;
+    template OCTAVE_API SparseComplexMatrix
+    sparse_qr<SparseComplexMatrix>::V (void) const;
+    template OCTAVE_API ColumnVector
+    sparse_qr<SparseComplexMatrix>::Pinv (void) const;
+    template OCTAVE_API ColumnVector
+    sparse_qr<SparseComplexMatrix>::P (void) const;
+    template OCTAVE_API SparseComplexMatrix
+    sparse_qr<SparseComplexMatrix>::R (bool econ) const;
+    template OCTAVE_API ComplexMatrix
+    sparse_qr<SparseComplexMatrix>::C (const ComplexMatrix& b, bool econ) const;
+    template OCTAVE_API ComplexMatrix
+    sparse_qr<SparseComplexMatrix>::Q (bool econ) const;
+
     Matrix
     qrsolve (const SparseMatrix& a, const MArray<double>& b,
              octave_idx_type& info)
@@ -2360,11 +3345,5 @@
                                                    SparseComplexMatrix>
                                              (a, b, info);
     }
-
-    // Instantiations we need.
-
-    template class sparse_qr<SparseMatrix>;
-
-    template class sparse_qr<SparseComplexMatrix>;
   }
 }
--- a/liboctave/numeric/sparse-qr.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/sparse-qr.h	Sun May 16 09:44:35 2021 +0200
@@ -28,12 +28,14 @@
 
 #include "octave-config.h"
 
+#include <memory>
+
 #include "oct-cmplx.h"
 
 class Matrix;
 class ComplexMatrix;
+class SparseMatrix;
 class SparseComplexMatrix;
-class SparseMatrix;
 class ColumnVector;
 template <typename T> class MArray;
 
@@ -52,83 +54,106 @@
     {
     public:
 
-      sparse_qr (void);
-
-      sparse_qr (const SPARSE_T& a, int order = 0);
-
-      sparse_qr (const sparse_qr& a);
+      OCTAVE_API sparse_qr (void);
 
-      ~sparse_qr (void);
+#if (defined (HAVE_SPQR) && defined (HAVE_CHOLMOD))
+      // order = 7 selects SPQR default ordering
+      OCTAVE_API sparse_qr (const SPARSE_T& a, int order = 7);
+#else
+      OCTAVE_API sparse_qr (const SPARSE_T& a, int order = 0);
+#endif
 
-      sparse_qr& operator = (const sparse_qr& a);
+      OCTAVE_API sparse_qr (const sparse_qr& a) = default;
+
+      OCTAVE_API ~sparse_qr (void) = default;
 
-      bool ok (void) const;
+      OCTAVE_API sparse_qr& operator = (const sparse_qr& a) = default;
+
+      OCTAVE_API bool ok (void) const;
 
-      SPARSE_T V (void) const;
+      OCTAVE_API ColumnVector E (void) const;
 
-      ColumnVector Pinv (void) const;
+      // constructs permutation matrix from permutation vector rep -> E()
+      OCTAVE_API SparseMatrix E_MAT () const;
 
-      ColumnVector P (void) const;
+      OCTAVE_API SPARSE_T V (void) const;
+
+      OCTAVE_API ColumnVector Pinv (void) const;
 
-      SPARSE_T R (bool econ = false) const;
+      OCTAVE_API ColumnVector P (void) const;
+
+      OCTAVE_API SPARSE_T R (bool econ = false) const;
 
-      typename SPARSE_T::dense_matrix_type
-      C (const typename SPARSE_T::dense_matrix_type& b) const;
+      OCTAVE_API typename SPARSE_T::dense_matrix_type
+      C (const typename SPARSE_T::dense_matrix_type& b, bool econ = false) const;
 
-      typename SPARSE_T::dense_matrix_type
-      Q (void) const;
+      OCTAVE_API typename SPARSE_T::dense_matrix_type
+      Q (bool econ = false) const;
 
       template <typename RHS_T, typename RET_T>
-      static RET_T
+      static OCTAVE_API RET_T
       solve (const SPARSE_T& a, const RHS_T& b,
              octave_idx_type& info);
 
     private:
 
+      template <typename RHS_T,typename RET_T>
+      static OCTAVE_API RET_T
+      min2norm_solve (const SPARSE_T& a, const RHS_T& b,
+                      octave_idx_type& info, int order);
+
       class sparse_qr_rep;
 
-      sparse_qr_rep *rep;
+      std::shared_ptr<sparse_qr_rep> rep;
 
       template <typename RHS_T, typename RET_T>
-      RET_T
+      OCTAVE_API RET_T
       tall_solve (const RHS_T& b, octave_idx_type& info) const;
 
       template <typename RHS_T, typename RET_T>
-      RET_T
+      OCTAVE_API RET_T
       wide_solve (const RHS_T& b, octave_idx_type& info) const;
     };
 
+#if defined (__clang__) || defined (_WIN32)
+    // extern instantiations with set visibility/export/import attribute
+
+    extern template class OCTAVE_API sparse_qr<SparseMatrix>;
+
+    extern template class OCTAVE_API sparse_qr<SparseComplexMatrix>;
+#endif
+
     // Provide qrsolve for backward compatibility.
 
-    extern Matrix
+    extern OCTAVE_API Matrix
     qrsolve (const SparseMatrix& a, const MArray<double>& b,
              octave_idx_type& info);
 
-    extern SparseMatrix
+    extern OCTAVE_API SparseMatrix
     qrsolve (const SparseMatrix& a, const SparseMatrix& b,
              octave_idx_type& info);
 
-    extern ComplexMatrix
+    extern OCTAVE_API ComplexMatrix
     qrsolve (const SparseMatrix& a, const MArray<Complex>& b,
              octave_idx_type& info);
 
-    extern SparseComplexMatrix
+    extern OCTAVE_API SparseComplexMatrix
     qrsolve (const SparseMatrix& a, const SparseComplexMatrix& b,
              octave_idx_type& info);
 
-    extern ComplexMatrix
+    extern OCTAVE_API ComplexMatrix
     qrsolve (const SparseComplexMatrix& a, const MArray<double>& b,
              octave_idx_type& info);
 
-    extern SparseComplexMatrix
+    extern OCTAVE_API SparseComplexMatrix
     qrsolve (const SparseComplexMatrix& a, const SparseMatrix& b,
              octave_idx_type& info);
 
-    extern ComplexMatrix
+    extern OCTAVE_API ComplexMatrix
     qrsolve (const SparseComplexMatrix& a, const MArray<Complex>& b,
              octave_idx_type& info);
 
-    extern SparseComplexMatrix
+    extern OCTAVE_API SparseComplexMatrix
     qrsolve (const SparseComplexMatrix& a, const SparseComplexMatrix& b,
              octave_idx_type& info);
 
--- a/liboctave/numeric/svd.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/svd.cc	Sun May 16 09:44:35 2021 +0200
@@ -30,6 +30,7 @@
 #include <cassert>
 
 #include <algorithm>
+#include <unordered_map>
 
 #include "CMatrix.h"
 #include "dDiagMatrix.h"
@@ -41,6 +42,265 @@
 #include "lo-lapack-proto.h"
 #include "svd.h"
 
+// class to compute optimal work space size (lwork) for DGEJSV and SGEJSV
+template<typename T>
+class
+gejsv_lwork
+{
+public:
+  gejsv_lwork () = delete;
+
+  // Unfortunately, dgejsv and sgejsv do not provide estimation of 'lwork'.
+  // Thus, we have to estimate it according to corresponding LAPACK
+  // documentation and related source codes (e.g. cgejsv).
+  // In LAPACKE (C interface to LAPACK), the memory handling code in
+  // LAPACKE_dgejsv() (lapacke_dgejsv.c, last visit 2019-02-17) uses
+  // the minimum required working space.  In contrast, here the optimal
+  // working space size is computed, at the cost of much longer code.
+
+  static F77_INT optimal (char& joba, char& jobu, char& jobv,
+                          F77_INT m, F77_INT n);
+
+private:
+  typedef typename T::element_type P;
+
+  // functions could be called from GEJSV
+  static F77_INT geqp3_lwork (F77_INT m, F77_INT n,
+                              P *a, F77_INT lda,
+                              F77_INT* jpvt, P *tau, P *work,
+                              F77_INT lwork, F77_INT& info);
+
+  static F77_INT geqrf_lwork (F77_INT m, F77_INT n,
+                              P *a, F77_INT lda,
+                              P *tau, P *work,
+                              F77_INT lwork, F77_INT& info);
+
+  static F77_INT gelqf_lwork (F77_INT m, F77_INT n,
+                              P *a, F77_INT lda,
+                              P *tau, P *work,
+                              F77_INT lwork, F77_INT& info);
+
+  static F77_INT ormlq_lwork (char& side, char& trans,
+                              F77_INT m, F77_INT n, F77_INT k,
+                              P *a, F77_INT lda,
+                              P *tau, P *c, F77_INT ldc,
+                              P *work, F77_INT lwork, F77_INT& info);
+
+  static F77_INT ormqr_lwork (char& side, char& trans,
+                              F77_INT m, F77_INT n, F77_INT k,
+                              P *a, F77_INT lda,
+                              P *tau, P *c, F77_INT ldc,
+                              P *work, F77_INT lwork, F77_INT& info);
+};
+
+#define GEJSV_REAL_QP3_LWORK(f, F)                              \
+  F77_XFCN (f, F, (m, n, a, lda, jpvt, tau, work, lwork, info))
+
+#define GEJSV_REAL_QR_LWORK(f, F)                               \
+  F77_XFCN (f, F, (m, n, a, lda, tau, work, lwork, info))
+
+#define GEJSV_REAL_ORM_LWORK(f, F)                              \
+  F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&side,  1),             \
+                   F77_CONST_CHAR_ARG2 (&trans, 1),             \
+                   m, n, k, a, lda, tau,                        \
+                   c, ldc, work, lwork, info                    \
+                   F77_CHAR_ARG_LEN (1)                         \
+                   F77_CHAR_ARG_LEN (1)))
+
+// For Matrix
+template<>
+F77_INT
+gejsv_lwork<Matrix>::geqp3_lwork (F77_INT m, F77_INT n,
+                                  P *a, F77_INT lda,
+                                  F77_INT* jpvt, P *tau, P *work,
+                                  F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_QP3_LWORK (dgeqp3, DGEQP3);
+  return static_cast<F77_INT> (work[0]);
+}
+
+template<>
+F77_INT
+gejsv_lwork<Matrix>::geqrf_lwork (F77_INT m, F77_INT n,
+                                  P *a, F77_INT lda,
+                                  P *tau, P *work,
+                                  F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_QR_LWORK (dgeqrf, DGEQRF);
+  return static_cast<F77_INT> (work[0]);
+}
+
+template<>
+F77_INT
+gejsv_lwork<Matrix>::gelqf_lwork (F77_INT m, F77_INT n,
+                                  P *a, F77_INT lda,
+                                  P *tau, P *work,
+                                  F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_QR_LWORK (dgelqf, DGELQF);
+  return static_cast<F77_INT> (work[0]);
+}
+
+template<>
+F77_INT
+gejsv_lwork<Matrix>::ormlq_lwork (char& side, char& trans,
+                                  F77_INT m, F77_INT n, F77_INT k,
+                                  P *a, F77_INT lda,
+                                  P *tau, P *c, F77_INT ldc,
+                                  P *work, F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_ORM_LWORK (dormlq, DORMLQ);
+  return static_cast<F77_INT> (work[0]);
+}
+
+template<>
+F77_INT
+gejsv_lwork<Matrix>::ormqr_lwork (char& side, char& trans,
+                                  F77_INT m, F77_INT n, F77_INT k,
+                                  P *a, F77_INT lda,
+                                  P *tau, P *c, F77_INT ldc,
+                                  P *work, F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_ORM_LWORK (dormqr, DORMQR);
+  return static_cast<F77_INT> (work[0]);
+}
+
+// For FloatMatrix
+template<>
+F77_INT
+gejsv_lwork<FloatMatrix>::geqp3_lwork (F77_INT m, F77_INT n,
+                                       P *a, F77_INT lda,
+                                       F77_INT* jpvt, P *tau, P *work,
+                                       F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_QP3_LWORK (sgeqp3, SGEQP3);
+  return static_cast<F77_INT> (work[0]);
+}
+
+template<>
+F77_INT
+gejsv_lwork<FloatMatrix>::geqrf_lwork (F77_INT m, F77_INT n,
+                                       P *a, F77_INT lda,
+                                       P *tau, P *work,
+                                       F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_QR_LWORK (sgeqrf, SGEQRF);
+  return static_cast<F77_INT> (work[0]);
+}
+
+template<>
+F77_INT
+gejsv_lwork<FloatMatrix>::gelqf_lwork (F77_INT m, F77_INT n,
+                                       P *a, F77_INT lda,
+                                       P *tau, P *work,
+                                       F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_QR_LWORK (sgelqf, SGELQF);
+  return static_cast<F77_INT> (work[0]);
+}
+
+template<>
+F77_INT
+gejsv_lwork<FloatMatrix>::ormlq_lwork (char& side, char& trans,
+                                       F77_INT m, F77_INT n, F77_INT k,
+                                       P *a, F77_INT lda,
+                                       P *tau, P *c, F77_INT ldc,
+                                       P *work, F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_ORM_LWORK (sormlq, SORMLQ);
+  return static_cast<F77_INT> (work[0]);
+}
+
+template<>
+F77_INT
+gejsv_lwork<FloatMatrix>::ormqr_lwork (char& side, char& trans,
+                                       F77_INT m, F77_INT n, F77_INT k,
+                                       P *a, F77_INT lda,
+                                       P *tau, P *c, F77_INT ldc,
+                                       P *work, F77_INT lwork, F77_INT& info)
+{
+  GEJSV_REAL_ORM_LWORK (sormqr, SORMQR);
+  return static_cast<F77_INT> (work[0]);
+}
+
+#undef GEJSV_REAL_QP3_LWORK
+#undef GEJSV_REAL_QR_LWORK
+#undef GEJSV_REAL_ORM_LWORK
+
+template<typename T>
+F77_INT
+gejsv_lwork<T>::optimal (char& joba, char& jobu, char& jobv,
+                         F77_INT m, F77_INT n)
+{
+  F77_INT lwork = -1;
+  std::vector<P> work (2);  // dummy work space
+
+  // variables that mimic running environment of gejsv
+  F77_INT lda  = std::max<F77_INT> (m, 1);
+  F77_INT ierr = 0;
+  char side  = 'L';
+  char trans = 'N';
+  std::vector<P> mat_a (1);
+  P *a = mat_a.data ();    // dummy input matrix
+  std::vector<F77_INT> vec_jpvt = {0};
+  P *tau = work.data ();
+  P *u   = work.data ();
+  P *v   = work.data ();
+
+  bool need_lsvec = jobu == 'U' || jobu == 'F';
+  bool need_rsvec = jobv == 'V' || jobv == 'J';
+
+  F77_INT lw_pocon = 3 * n;  // for [s,d]pocon
+  F77_INT lw_geqp3 = geqp3_lwork (m, n, a, lda, vec_jpvt.data (),
+                                  tau, work.data (), -1, ierr);
+  F77_INT lw_geqrf = geqrf_lwork (m, n, a, lda,
+                                  tau, work.data (), -1, ierr);
+
+  if (! (need_lsvec || need_rsvec) )
+    {
+      // only SIGMA is needed
+      if (! (joba == 'E' || joba == 'G') )
+        lwork = std::max<F77_INT> ({2*m + n, n + lw_geqp3, n + lw_geqrf, 7});
+      else
+        lwork = std::max<F77_INT> ({2*m + n, n + lw_geqp3, n + lw_geqrf,
+                                    n + n*n + lw_pocon, 7});
+    }
+  else if (need_rsvec && ! need_lsvec)
+    {
+      // SIGMA and the right singular vectors are needed
+      F77_INT lw_gelqf = gelqf_lwork (n, n, a, lda,
+                                      tau, work.data (), -1, ierr);
+      trans = 'T';
+      F77_INT lw_ormlq = ormlq_lwork (side, trans, n, n, n, a, lda,
+                                      tau, v, n, work.data (), -1, ierr);
+      lwork = std::max<F77_INT> ({2*m + n, n + lw_geqp3, n + lw_pocon,
+                                  n + lw_gelqf, 2*n + lw_geqrf, n + lw_ormlq});
+    }
+  else if (need_lsvec && ! need_rsvec)
+    {
+      // SIGMA and the left singular vectors are needed
+      F77_INT n1 = (jobu == 'U') ? n : m;  // size of U is m x n1
+      F77_INT lw_ormqr = ormqr_lwork (side, trans, m, n1, n, a, lda,
+                                      tau, u, m, work.data (), -1, ierr);
+      lwork = std::max<F77_INT> ({2*m + n, n + lw_geqp3, n + lw_pocon,
+                                  2*n + lw_geqrf, n + lw_ormqr});
+    }
+  else  // full SVD is needed
+    {
+      if (jobv == 'V')
+        lwork = std::max (2*m + n, 6*n + 2*n*n);
+      else if (jobv == 'J')
+        lwork = std::max<F77_INT> ({2*m + n, 4*n + n*n, 2*n + n*n + 6});
+
+      F77_INT n1 = (jobu == 'U') ? n : m;  // size of U is m x n1
+      F77_INT lw_ormqr = ormqr_lwork (side, trans, m, n1, n, a, lda,
+                                      tau, u, m, work.data (), -1, ierr);
+      lwork = std::max (lwork, n + lw_ormqr);
+    }
+
+  return lwork;
+}
+
 namespace octave
 {
   namespace math
@@ -70,27 +330,27 @@
     // GESVD specializations
 
 #define GESVD_REAL_STEP(f, F)                                   \
-    F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&jobu, 1),            \
-                     F77_CONST_CHAR_ARG2 (&jobv, 1),            \
-                     m, n, tmp_data, m1, s_vec, u, m1, vt,      \
-                     nrow_vt1, work.data (), lwork, info        \
-                     F77_CHAR_ARG_LEN (1)                       \
-                     F77_CHAR_ARG_LEN (1)))
+  F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&jobu, 1),              \
+                   F77_CONST_CHAR_ARG2 (&jobv, 1),              \
+                   m, n, tmp_data, m1, s_vec, u, m1, vt,        \
+                   nrow_vt1, work.data (), lwork, info          \
+                   F77_CHAR_ARG_LEN (1)                         \
+                   F77_CHAR_ARG_LEN (1)))
 
 #define GESVD_COMPLEX_STEP(f, F, CMPLX_ARG)             \
-    F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&jobu, 1),    \
-                     F77_CONST_CHAR_ARG2 (&jobv, 1),    \
-                     m, n, CMPLX_ARG (tmp_data),        \
-                     m1, s_vec, CMPLX_ARG (u), m1,      \
-                     CMPLX_ARG (vt), nrow_vt1,          \
-                     CMPLX_ARG (work.data ()),          \
-                     lwork, rwork.data (), info         \
-                     F77_CHAR_ARG_LEN (1)               \
-                     F77_CHAR_ARG_LEN (1)))
+  F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&jobu, 1),      \
+                   F77_CONST_CHAR_ARG2 (&jobv, 1),      \
+                   m, n, CMPLX_ARG (tmp_data),          \
+                   m1, s_vec, CMPLX_ARG (u), m1,        \
+                   CMPLX_ARG (vt), nrow_vt1,            \
+                   CMPLX_ARG (work.data ()),            \
+                   lwork, rwork.data (), info           \
+                   F77_CHAR_ARG_LEN (1)                 \
+                   F77_CHAR_ARG_LEN (1)))
 
     // DGESVD
     template<>
-    void
+    OCTAVE_API void
     svd<Matrix>::gesvd (char& jobu, char& jobv, F77_INT m, F77_INT n,
                         double *tmp_data, F77_INT m1, double *s_vec,
                         double *u, double *vt, F77_INT nrow_vt1,
@@ -107,7 +367,7 @@
 
     // SGESVD
     template<>
-    void
+    OCTAVE_API void
     svd<FloatMatrix>::gesvd (char& jobu, char& jobv, F77_INT m, F77_INT n,
                              float *tmp_data, F77_INT m1, float *s_vec,
                              float *u, float *vt, F77_INT nrow_vt1,
@@ -124,7 +384,7 @@
 
     // ZGESVD
     template<>
-    void
+    OCTAVE_API void
     svd<ComplexMatrix>::gesvd (char& jobu, char& jobv, F77_INT m, F77_INT n,
                                Complex *tmp_data, F77_INT m1, double *s_vec,
                                Complex *u, Complex *vt, F77_INT nrow_vt1,
@@ -143,7 +403,7 @@
 
     // CGESVD
     template<>
-    void
+    OCTAVE_API void
     svd<FloatComplexMatrix>::gesvd (char& jobu, char& jobv, F77_INT m,
                                     F77_INT n, FloatComplex *tmp_data,
                                     F77_INT m1, float *s_vec, FloatComplex *u,
@@ -183,7 +443,7 @@
 
     // DGESDD
     template<>
-    void
+    OCTAVE_API void
     svd<Matrix>::gesdd (char& jobz, F77_INT m, F77_INT n, double *tmp_data,
                         F77_INT m1, double *s_vec, double *u, double *vt,
                         F77_INT nrow_vt1, std::vector<double>& work,
@@ -199,7 +459,7 @@
 
     // SGESDD
     template<>
-    void
+    OCTAVE_API void
     svd<FloatMatrix>::gesdd (char& jobz, F77_INT m, F77_INT n, float *tmp_data,
                              F77_INT m1, float *s_vec, float *u, float *vt,
                              F77_INT nrow_vt1, std::vector<float>& work,
@@ -215,7 +475,7 @@
 
     // ZGESDD
     template<>
-    void
+    OCTAVE_API void
     svd<ComplexMatrix>::gesdd (char& jobz, F77_INT m, F77_INT n,
                                Complex *tmp_data, F77_INT m1, double *s_vec,
                                Complex *u, Complex *vt, F77_INT nrow_vt1,
@@ -244,7 +504,7 @@
 
     // CGESDD
     template<>
-    void
+    OCTAVE_API void
     svd<FloatComplexMatrix>::gesdd (char& jobz, F77_INT m, F77_INT n,
                                     FloatComplex *tmp_data, F77_INT m1,
                                     float *s_vec, FloatComplex *u,
@@ -274,9 +534,140 @@
 #undef GESDD_REAL_STEP
 #undef GESDD_COMPLEX_STEP
 
+    // GEJSV specializations
+
+#define GEJSV_REAL_STEP(f, F)                                         \
+    F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&joba, 1),                  \
+                     F77_CONST_CHAR_ARG2 (&jobu, 1),                  \
+                     F77_CONST_CHAR_ARG2 (&jobv, 1),                  \
+                     F77_CONST_CHAR_ARG2 (&jobr, 1),                  \
+                     F77_CONST_CHAR_ARG2 (&jobt, 1),                  \
+                     F77_CONST_CHAR_ARG2 (&jobp, 1),                  \
+                     m, n, tmp_data, m1, s_vec, u, m1, v, nrow_v1,    \
+                     work.data (), lwork, iwork.data (), info         \
+                     F77_CHAR_ARG_LEN (1)                             \
+                     F77_CHAR_ARG_LEN (1)                             \
+                     F77_CHAR_ARG_LEN (1)                             \
+                     F77_CHAR_ARG_LEN (1)                             \
+                     F77_CHAR_ARG_LEN (1)                             \
+                     F77_CHAR_ARG_LEN (1)))
+
+#define GEJSV_COMPLEX_STEP(f, F, CMPLX_ARG)                       \
+    F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&joba, 1),              \
+                     F77_CONST_CHAR_ARG2 (&jobu, 1),              \
+                     F77_CONST_CHAR_ARG2 (&jobv, 1),              \
+                     F77_CONST_CHAR_ARG2 (&jobr, 1),              \
+                     F77_CONST_CHAR_ARG2 (&jobt, 1),              \
+                     F77_CONST_CHAR_ARG2 (&jobp, 1),              \
+                     m, n, CMPLX_ARG (tmp_data), m1,              \
+                     s_vec, CMPLX_ARG (u), m1,                    \
+                     CMPLX_ARG (v), nrow_v1,                      \
+                     CMPLX_ARG (work.data ()), lwork,             \
+                     rwork.data (), lrwork, iwork.data (), info   \
+                     F77_CHAR_ARG_LEN (1)                         \
+                     F77_CHAR_ARG_LEN (1)                         \
+                     F77_CHAR_ARG_LEN (1)                         \
+                     F77_CHAR_ARG_LEN (1)                         \
+                     F77_CHAR_ARG_LEN (1)                         \
+                     F77_CHAR_ARG_LEN (1)))
+
+    // DGEJSV
+    template<>
+    void
+    svd<Matrix>::gejsv (char& joba, char& jobu, char& jobv,
+                        char& jobr, char& jobt, char& jobp,
+                        F77_INT m, F77_INT n,
+                        P *tmp_data, F77_INT m1, DM_P *s_vec, P *u,
+                        P *v, F77_INT nrow_v1, std::vector<P>& work,
+                        F77_INT& lwork, std::vector<F77_INT>& iwork,
+                        F77_INT& info)
+    {
+      lwork = gejsv_lwork<Matrix>::optimal (joba, jobu, jobv, m, n);
+      work.reserve (lwork);
+
+      GEJSV_REAL_STEP (dgejsv, DGEJSV);
+    }
+
+    // SGEJSV
+    template<>
+    void
+    svd<FloatMatrix>::gejsv (char& joba, char& jobu, char& jobv,
+                             char& jobr, char& jobt, char& jobp,
+                             F77_INT m, F77_INT n,
+                             P *tmp_data, F77_INT m1, DM_P *s_vec, P *u,
+                             P *v, F77_INT nrow_v1, std::vector<P>& work,
+                             F77_INT& lwork, std::vector<F77_INT>& iwork,
+                             F77_INT& info)
+    {
+      lwork = gejsv_lwork<FloatMatrix>::optimal (joba, jobu, jobv, m, n);
+      work.reserve (lwork);
+
+      GEJSV_REAL_STEP (sgejsv, SGEJSV);
+    }
+
+    // ZGEJSV
+    template<>
+    void
+    svd<ComplexMatrix>::gejsv (char& joba, char& jobu, char& jobv,
+                               char& jobr, char& jobt, char& jobp,
+                               F77_INT m, F77_INT n,
+                               P *tmp_data, F77_INT m1, DM_P *s_vec, P *u,
+                               P *v, F77_INT nrow_v1, std::vector<P>& work,
+                               F77_INT& lwork, std::vector<F77_INT>& iwork,
+                               F77_INT& info)
+    {
+      F77_INT lrwork = -1;          // work space size query
+      std::vector<double> rwork (1);
+      work.reserve (2);
+
+      GEJSV_COMPLEX_STEP (zgejsv, ZGEJSV, F77_DBLE_CMPLX_ARG);
+
+      lwork = static_cast<F77_INT> (work[0].real ());
+      work.reserve (lwork);
+
+      lrwork = static_cast<F77_INT> (rwork[0]);
+      rwork.reserve (lrwork);
+
+      F77_INT liwork = static_cast<F77_INT> (iwork[0]);
+      iwork.reserve (liwork);
+
+      GEJSV_COMPLEX_STEP (zgejsv, ZGEJSV, F77_DBLE_CMPLX_ARG);
+    }
+
+    // CGEJSV
+    template<>
+    void
+    svd<FloatComplexMatrix>::gejsv (char& joba, char& jobu, char& jobv,
+                                    char& jobr, char& jobt, char& jobp,
+                                    F77_INT m, F77_INT n, P *tmp_data,
+                                    F77_INT m1, DM_P *s_vec, P *u, P *v,
+                                    F77_INT nrow_v1, std::vector<P>& work,
+                                    F77_INT& lwork,
+                                    std::vector<F77_INT>& iwork, F77_INT& info)
+    {
+      F77_INT lrwork = -1;          // work space size query
+      std::vector<float> rwork (1);
+      work.reserve (2);
+
+      GEJSV_COMPLEX_STEP (cgejsv, CGEJSV, F77_CMPLX_ARG);
+
+      lwork = static_cast<F77_INT> (work[0].real ());
+      work.reserve (lwork);
+
+      lrwork = static_cast<F77_INT> (rwork[0]);
+      rwork.reserve (lrwork);
+
+      F77_INT liwork = static_cast<F77_INT> (iwork[0]);
+      iwork.reserve (liwork);
+
+      GEJSV_COMPLEX_STEP (cgejsv, CGEJSV, F77_CMPLX_ARG);
+    }
+
+#undef GEJSV_REAL_STEP
+#undef GEJSV_COMPLEX_STEP
+
     template<typename T>
-    svd<T>::svd (const T& a, svd::Type type,
-                 svd::Driver driver)
+    svd<T>::svd (const T& a, svd::Type type, svd::Driver driver)
       : m_type (type), m_driver (driver), left_sm (), sigma (), right_sm ()
     {
       F77_INT info;
@@ -301,7 +692,7 @@
             case svd::Type::economy:
               left_sm = T (m, 0, 0);
               sigma = DM_T (0, 0);
-              right_sm = T (0, n, 0);
+              right_sm = T (n, 0, 0);
               break;
 
             case svd::Type::sigma_only:
@@ -358,7 +749,12 @@
       DM_P *s_vec = sigma.fortran_vec ();
 
       if (! (jobv == 'N' || jobv == 'O'))
-        right_sm.resize (nrow_vt, n);
+        {
+          if (m_driver == svd::Driver::GEJSV)
+            right_sm.resize (n, nrow_vt);
+          else
+            right_sm.resize (nrow_vt, n);
+        }
 
       P *vt = right_sm.fortran_vec ();
 
@@ -368,8 +764,9 @@
 
       std::vector<P> work (1);
 
-      F77_INT m1 = std::max (m, static_cast<F77_INT> (1));
-      F77_INT nrow_vt1 = std::max (nrow_vt, static_cast<F77_INT> (1));
+      const F77_INT f77_int_one = static_cast<F77_INT> (1);
+      F77_INT m1 = std::max (m, f77_int_one);
+      F77_INT nrow_vt1 = std::max (nrow_vt, f77_int_one);
 
       if (m_driver == svd::Driver::GESVD)
         gesvd (jobu, jobv, m, n, tmp_data, m1, s_vec, u, vt, nrow_vt1,
@@ -384,6 +781,66 @@
           gesdd (jobz, m, n, tmp_data, m1, s_vec, u, vt, nrow_vt1,
                  work, lwork, iwork.data (), info);
         }
+      else if (m_driver == svd::Driver::GEJSV)
+        {
+          bool transposed = false;
+          if (n > m)
+            {
+              // GEJSV only accepts m >= n, thus we need to transpose here
+              transposed = true;
+
+              std::swap (m, n);
+              m1 = std::max (m, f77_int_one);
+              nrow_vt1 = std::max (n, f77_int_one);  // we have m > n
+              if (m_type == svd::Type::sigma_only)
+                nrow_vt1 = 1;
+              std::swap (jobu, jobv);
+
+              atmp = atmp.hermitian ();
+              tmp_data = atmp.fortran_vec ();
+
+              // Swap pointers of U and V.
+              u  = right_sm.fortran_vec ();
+              vt = left_sm.fortran_vec ();
+            }
+
+          // translate jobu and jobv from gesvd to gejsv.
+          std::unordered_map<char, std::string> job_svd2jsv;
+          job_svd2jsv['A'] = "FJ";
+          job_svd2jsv['S'] = "UV";
+          job_svd2jsv['O'] = "WW";
+          job_svd2jsv['N'] = "NN";
+          jobu = job_svd2jsv[jobu][0];
+          jobv = job_svd2jsv[jobv][1];
+
+          char joba = 'F';  // 'F': most conservative
+          char jobr = 'R';  // 'R' is recommended.
+          char jobt = 'N';  // or 'T', but that requires U and V appear together
+          char jobp = 'N';  // use 'P' if denormal is poorly implemented.
+
+          std::vector<F77_INT> iwork (std::max<F77_INT> (m + 3*n, 1));
+
+          gejsv (joba, jobu, jobv, jobr, jobt, jobp, m, n, tmp_data, m1,
+                 s_vec, u, vt, nrow_vt1, work, lwork, iwork, info);
+
+          if (iwork[2] == 1)
+            (*current_liboctave_warning_with_id_handler)
+            ("Octave:convergence", "svd: (driver: GEJSV) "
+             "Denormal occured, possible loss of accuracy.");
+
+          if (info < 0)
+            (*current_liboctave_error_handler)
+            ("svd: (driver: GEJSV) Illegal argument at #%d",
+             static_cast<int> (-info));
+          else if (info > 0)
+            (*current_liboctave_warning_with_id_handler)
+            ("Octave:convergence", "svd: (driver: GEJSV) "
+             "Fail to converge within max sweeps, "
+             "possible inaccurate result.");
+
+          if (transposed)  // put things that need to transpose back here
+            std::swap (m, n);
+        }
       else
         (*current_liboctave_error_handler) ("svd: unknown driver");
 
@@ -394,7 +851,8 @@
             sigma.dgxelem (i) = DM_P (0);
         }
 
-      if (! (jobv == 'N' || jobv == 'O'))
+      // GESVD and GESDD return VT instead of V, GEJSV return V.
+      if (! (jobv == 'N' || jobv == 'O') && (m_driver != svd::Driver::GEJSV))
         right_sm = right_sm.hermitian ();
     }
 
--- a/liboctave/numeric/svd.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/numeric/svd.h	Sun May 16 09:44:35 2021 +0200
@@ -36,6 +36,7 @@
   {
     template <typename T>
     class
+    OCTAVE_API
     svd
     {
     public:
@@ -52,7 +53,8 @@
       enum class Driver
       {
         GESVD,
-        GESDD
+        GESDD,
+        GEJSV
       };
 
       svd (void)
@@ -112,6 +114,14 @@
                   P *vt, octave_f77_int_type nrow_vt1, std::vector<P>& work,
                   octave_f77_int_type& lwork, octave_f77_int_type *iwork,
                   octave_f77_int_type& info);
+
+      void gejsv (char& joba, char& jobu, char& jobv, char& jobr, char& jobt,
+                  char& jobp, octave_f77_int_type m, octave_f77_int_type n,
+                  P *tmp_data, octave_f77_int_type m1, DM_P *s_vec, P *u,
+                  P *v, octave_f77_int_type nrow_v1, std::vector<P>& work,
+                  octave_f77_int_type& lwork,
+                  std::vector<octave_f77_int_type>& iwork,
+                  octave_f77_int_type& info);
     };
   }
 }
--- a/liboctave/operators/mx-op-defs.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/operators/mx-op-defs.h	Sun May 16 09:44:35 2021 +0200
@@ -607,7 +607,7 @@
     else                                                                \
       {                                                                 \
         result = M (nr, nc);                                            \
-        result.assign (p.col_perm_vec (), idx_vector::colon, x);        \
+        result.assign (p.col_perm_vec (), octave::idx_vector::colon, x);        \
       }                                                                 \
                                                                         \
     return result;                                                      \
@@ -622,7 +622,7 @@
     if (p.rows () != nc)                                                \
       octave::err_nonconformant ("operator *", nr, nc, p.rows (), p.columns ()); \
                                                                         \
-    result = x.index (idx_vector::colon, p.col_perm_vec ());            \
+    result = x.index (octave::idx_vector::colon, p.col_perm_vec ());            \
                                                                         \
     return result;                                                      \
   }
--- a/liboctave/system/dir-ops.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/dir-ops.h	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
       // NOTE: This class cannot be used safely cross-platform (Windows) with
       // non-ASCII characters in paths.
       // Consider replacing the implementation using std::filesystem (C++ 17).
-      // In the meantime, consider using octave::sys::get_dirlist instead.
+      // In the meantime, consider using sys::get_dirlist instead.
 
     public:
 
--- a/liboctave/system/file-ops.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/file-ops.cc	Sun May 16 09:44:35 2021 +0200
@@ -36,17 +36,12 @@
 
 #if defined (OCTAVE_USE_WINDOWS_API)
 #  include <windows.h>
-#  include <shlwapi.h>
-#endif
-
-#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
-#  include <algorithm>
-#  include "localcharset-wrapper.h"
-#  include "uniconv-wrappers.h"
+#  include "unwind-prot.h"
+#else
+#  include "canonicalize-file-name-wrapper.h"
 #endif
 
 #include "areadlink-wrapper.h"
-#include "canonicalize-file-name-wrapper.h"
 #include "dir-ops.h"
 #include "file-ops.h"
 #include "file-stat.h"
@@ -702,44 +697,45 @@
 
       std::string retval;
 
-#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
-      // On Windows, convert to locale charset before passing to
-      // canonicalize_file_name, and convert back to UTF-8 after that.
-
-      // FIXME: This only allows non-ASCII characters in the file or path that
-      // can be encoded in the locale charset.
-      // Consider replacing this with std::filesystem::canonical once we allow
-      // using C++17.
+      // FIXME:  Consider replacing this with std::filesystem::canonical on all
+      // platforms once we allow using C++17.
 
-      const char *locale = octave_locale_charset_wrapper ();
-      const uint8_t *name_u8 = reinterpret_cast<const uint8_t *>
-                                 (name.c_str ());
-      std::size_t length = 0;
-      char *name_locale = octave_u8_conv_to_encoding (locale, name_u8,
-                                                      name.length () + 1,
-                                                      &length);
+#if defined (OCTAVE_USE_WINDOWS_API)
+      // open file handle
+      std::wstring wname = u8_to_wstring (name);
+      HANDLE h_file = CreateFileW (wname.c_str (), GENERIC_READ,
+                                   FILE_SHARE_READ, nullptr, OPEN_EXISTING,
+                                   FILE_FLAG_BACKUP_SEMANTICS, nullptr);
 
-      if (name_locale)
+      if (h_file == INVALID_HANDLE_VALUE)
         {
-          char *tmp_locale =
-            octave_canonicalize_file_name_wrapper (name_locale);
-          free (name_locale);
+          msg = "Unable to open file \"" + name + "\"";
+          return retval;
+        }
+
+      octave::unwind_action close_file_handle (CloseHandle, h_file);
+
+      const std::size_t buf_size = 32767;
+      wchar_t buffer[buf_size] = L"";
 
-          if (tmp_locale)
-            {
-              char *tmp = reinterpret_cast<char *>
-                            (octave_u8_conv_from_encoding (locale, tmp_locale,
-                                                           strlen (tmp_locale),
-                                                           &length));
-              free (tmp_locale);
+      // query canonical name
+      DWORD len = GetFinalPathNameByHandleW (h_file, buffer, buf_size,
+                                             FILE_NAME_NORMALIZED);
+      if (len >= buf_size)
+      {
+          msg = "Error querying normalized name for \"" + name + "\"";
+          return retval;
+      }
 
-              if (tmp)
-                {
-                  retval = std::string (tmp, length);
-                  free (tmp);
-                }
-            }
-        }
+      retval = u8_from_wstring (std::wstring (buffer, len));
+
+      // remove prefix
+      // "Normal" paths are prefixed by "\\?\".
+      // UNC paths are prefixed by "\\?\UNC\".
+      if (retval.compare (0, 8, R"(\\?\UNC\)") == 0)
+        retval = retval.erase (2, 6);
+      else if (retval.compare (0, 4, R"(\\?\)") == 0)
+        retval = retval.erase (0, 4);
 #else
       char *tmp = octave_canonicalize_file_name_wrapper (name.c_str ());
 
@@ -748,63 +744,10 @@
           retval = tmp;
           free (tmp);
         }
-#endif
-
-#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
-      // Canonical Windows file separator is backslash.
-      std::replace (retval.begin (), retval.end (), '/', '\\');
-#endif
-
-#if defined (OCTAVE_USE_WINDOWS_API)
-      std::wstring w_tmp;
-      bool strip_marker = true;
-      if (retval.empty ())
-        {
-          // For UNC paths, take the input as is.
-          // Also translate forward slashes to backslashes.
-          std::string name_backsl = name;
-          std::replace (name_backsl.begin (), name_backsl.end (), '/', '\\');
-          if (name_backsl.compare (0, 2, "\\\\") == 0)
-            {
-              w_tmp = u8_to_wstring (name_backsl);
-              strip_marker = false;
-              wchar_t canon_path[MAX_PATH];
-              if (PathCanonicalizeW (canon_path, w_tmp.c_str ()))
-                w_tmp = std::wstring (canon_path);
-            }
-        }
-      else
-        w_tmp = L"\\\\?\\" + u8_to_wstring (retval);
-
-      if (! w_tmp.empty ())
-        {
-          // Get a more canonical name wrt case and full names
-          // FIXME: To make this work on partitions that don't store short file
-          // names, use FindFirstFileW on each component of the path.
-          // Insufficient access permissions on parent folders might make this
-          // tricky.
-
-          // Parts of the path that wouldn't fit into a short 8.3 file name are
-          // copied as is by GetLongPathNameW.  To also get the correct case
-          // for these parts, first convert to short file names and than back
-          // to long.
-          wchar_t buffer[32767] = L"";
-          int w_len = GetShortPathNameW (w_tmp.c_str (), buffer, 32767);
-          w_len = GetLongPathNameW (buffer, buffer, 32767);
-
-          if (! strip_marker)
-            retval = u8_from_wstring (std::wstring (buffer, w_len));
-          else if (w_len > 4)
-            retval = u8_from_wstring (std::wstring (buffer+4, w_len-4));
-
-          // If root is a drive, use an upper case letter for the drive letter.
-          if (retval.length () > 1 && retval[1] == ':')
-            retval[0] = toupper (retval[0]);
-        }
-#endif
 
       if (retval.empty ())
         msg = std::strerror (errno);
+#endif
 
       return retval;
     }
--- a/liboctave/system/file-ops.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/file-ops.h	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
       // returns a malloc()'ed string which is the expansion, or a NULL
       // pointer if the expansion fails.
 
-      extern tilde_expansion_hook tilde_expansion_preexpansion_hook;
+      extern OCTAVE_API tilde_expansion_hook tilde_expansion_preexpansion_hook;
 
       // If non-null, this contains the address of a function to call if the
       // standard meaning for expanding a tilde fails.  The function is
@@ -56,61 +56,63 @@
       // malloc()'ed string which is the expansion, or a NULL pointer if
       // there is no expansion.
 
-      extern tilde_expansion_hook tilde_expansion_failure_hook;
+      extern OCTAVE_API tilde_expansion_hook tilde_expansion_failure_hook;
 
       // When non-null, this is a NULL terminated array of strings which are
       // duplicates for a tilde prefix.  Bash uses this to expand '=~' and
       // ':~'.
 
-      extern string_vector tilde_additional_prefixes;
+      extern OCTAVE_API string_vector tilde_additional_prefixes;
 
       // When non-null, this is a NULL terminated array of strings which
       // match the end of a username, instead of just "/".  Bash sets this
       // to ':' and '=~'.
 
-      extern string_vector tilde_additional_suffixes;
+      extern OCTAVE_API string_vector tilde_additional_suffixes;
 
       // Find the start of a tilde expansion in S, and return the index
       // of the tilde which starts the expansion.  Place the length of the
       // text which identified this tilde starter in LEN, excluding the
       // tilde itself.
 
-      char dev_sep_char (void);
+      extern OCTAVE_API char dev_sep_char (void);
 
-      bool is_dev_sep (char c);
+      extern OCTAVE_API bool is_dev_sep (char c);
 
-      char dir_sep_char (void);
+      extern OCTAVE_API char dir_sep_char (void);
 
-      std::string dir_sep_str (void);
+      extern OCTAVE_API std::string dir_sep_str (void);
 
-      std::string dir_sep_chars (void);
+      extern OCTAVE_API std::string dir_sep_chars (void);
 
-      bool is_dir_sep (char c);
+      extern OCTAVE_API bool is_dir_sep (char c);
 
       // If NAME has a leading ~ or ~user, Unix-style, expand it to the
       // user's home directory.  If no ~, or no <pwd.h>, just return NAME.
 
-      std::string tilde_expand (const std::string&);
+      extern OCTAVE_API std::string tilde_expand (const std::string&);
 
       // A vector version of the above.
 
-      string_vector tilde_expand (const string_vector&);
+      extern OCTAVE_API string_vector tilde_expand (const string_vector&);
 
-      std::string concat (const std::string&, const std::string&);
+      extern OCTAVE_API std::string concat (const std::string&, const std::string&);
 
       // Return the directory part of a filename or an empty string if
       // there is no directory component.  Does not check to see
       // whether the file exists or is a directory.
 
-      std::string dirname (const std::string& path);
+      extern OCTAVE_API std::string dirname (const std::string& path);
 
       // Return the tail member of a filename.
 
-      std::string tail (const std::string& path);
+      extern OCTAVE_API std::string tail (const std::string& path);
 
-      // convert path from UNIX type separators to whatever is the system separators
+      // Convert path from UNIX type separators to whatever is the
+      // system separators.
 
-      std::string native_separator_path (const std::string& path);
+      extern OCTAVE_API std::string
+      native_separator_path (const std::string& path);
     }
 
     extern OCTAVE_API int
--- a/liboctave/system/file-stat.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/file-stat.cc	Sun May 16 09:44:35 2021 +0200
@@ -206,7 +206,7 @@
           // trailing backslash.
           // FIXME: This pattern does not match all possible UNC roots:
           //        https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/62e862f4-2a51-452e-8eeb-dc4ff5ee33cc
-          static regexp pat (R"(^\\\\[\w.-]+\\[\w\$-]+$)");
+          static const regexp pat (R"(^\\\\[\w.-]+\\[\w\$-]+$)");
           if ((full_file_name.length () == 2 && full_file_name[1] == ':')
               || (full_file_name.length () > 4  && full_file_name[0] == '\\'
                   && full_file_name[1] == '\\' && pat.is_match (full_file_name)))
--- a/liboctave/system/lo-sysdep.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/lo-sysdep.cc	Sun May 16 09:44:35 2021 +0200
@@ -27,12 +27,16 @@
 #  include "config.h"
 #endif
 
+#include <cstdlib>
+#include <locale>
+#include <codecvt>
+
 #include "dir-ops.h"
 #include "file-ops.h"
 #include "lo-error.h"
 #include "lo-sysdep.h"
+#include "localcharset-wrapper.h"
 #include "putenv-wrapper.h"
-#include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 #include "unsetenv-wrapper.h"
 
@@ -40,8 +44,10 @@
 #  include <windows.h>
 #  include <wchar.h>
 
+#  include "filepos-wrappers.h"
 #  include "lo-hash.h"
-#  include "filepos-wrappers.h"
+#  include "oct-locbuf.h"
+#  include "uniconv-wrappers.h"
 #  include "unwind-prot.h"
 #endif
 
@@ -49,6 +55,18 @@
 {
   namespace sys
   {
+    int
+    system (const std::string& cmd_str)
+    {
+#if defined (OCTAVE_USE_WINDOWS_API)
+      const std::wstring wcmd_str =  u8_to_wstring (cmd_str);
+
+      return _wsystem (wcmd_str.c_str ());
+#else
+      return ::system (cmd_str.c_str ());
+#endif
+    }
+
     std::string
     getcwd (void)
     {
@@ -219,7 +237,8 @@
           return false;
         }
 
-      unwind_action act ([fptr, tmpname] () {
+      unwind_action act ([=] ()
+                         {
                            std::fclose (fptr);
                            sys::unlink (tmpname);
                          });
@@ -408,31 +427,34 @@
     void
     putenv_wrapper (const std::string& name, const std::string& value)
     {
-      // This function was adapted from xputenv from Karl Berry's kpathsearch
-      // library.
-      // FIXME: make this do the right thing if we don't have a SMART_PUTENV.
+      std::string new_env = name + "=" + value;
 
-      int new_len = name.length () + value.length () + 2;
-
-      // FIXME: This leaks memory, but so would a call to setenv.
+      // FIXME: The malloc leaks memory, but so would a call to setenv.
       // Short of extreme measures to track memory, altering the environment
       // always leaks memory, but the saving grace is that the leaks are small.
 
-      char *new_item = static_cast<char *> (std::malloc (new_len));
-
-      if (new_item)
-        sprintf (new_item, "%s=%s", name.c_str (), value.c_str ());
-
       // As far as I can see there's no way to distinguish between the
       // various errors; putenv doesn't have errno values.
 
 #if defined (OCTAVE_USE_WINDOWS_API)
-      wchar_t *wnew_item = u8_to_wchar (new_item);
-      unwind_protect frame;
-      frame.add_fcn (std::free, static_cast<void *> (new_item));
-      if (_wputenv (wnew_item) < 0)
-        (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
+      std::wstring new_wenv = u8_to_wstring (new_env);
+
+      int len = (new_wenv.length () + 1) * sizeof (wchar_t);
+
+      wchar_t *new_item = static_cast<wchar_t *> (std::malloc (len));
+
+      wcscpy (new_item, new_wenv.c_str());
+
+      if (_wputenv (new_item) < 0)
+        (*current_liboctave_error_handler)
+          ("putenv (%s) failed", new_env.c_str());
 #else
+      int len = new_env.length () + 1;
+
+      char *new_item = static_cast<char *> (std::malloc (len));
+
+      std::strcpy (new_item, new_env.c_str());
+
       if (octave_putenv_wrapper (new_item) < 0)
         (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
 #endif
@@ -467,20 +489,21 @@
     std::wstring
     u8_to_wstring (const std::string& utf8_string)
     {
-      std::size_t srclen = utf8_string.length ();
-      const uint8_t *src = reinterpret_cast<const uint8_t *>
-                           (utf8_string.c_str ());
-
-      std::size_t length = 0;
-      wchar_t *wchar = reinterpret_cast<wchar_t *>
-                       (octave_u8_conv_to_encoding ("wchar_t", src, srclen,
-                                                    &length));
+      // convert multibyte UTF-8 string to wide character string
+      static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>
+        wchar_conv;
 
       std::wstring retval = L"";
-      if (wchar != nullptr)
+
+      try
         {
-          retval = std::wstring (wchar, length / sizeof (wchar_t));
-          free (static_cast<void *> (wchar));
+          retval = wchar_conv.from_bytes (utf8_string);
+        }
+      catch (const std::range_error& e)
+        {
+          // What to do in case of error?
+          // error ("u8_to_wstring: converting from UTF-8 to wchar_t: %s",
+          //        e.what ());
         }
 
       return retval;
@@ -489,19 +512,21 @@
     std::string
     u8_from_wstring (const std::wstring& wchar_string)
     {
-      std::size_t srclen = wchar_string.length () * sizeof (wchar_t);
-      const char *src = reinterpret_cast<const char *> (wchar_string.c_str ());
-
-      std::size_t length = 0;
-      char *mbchar = reinterpret_cast<char *>
-                     (octave_u8_conv_from_encoding ("wchar_t", src, srclen,
-                                                    &length));
+      // convert wide character string to multibyte UTF-8 string
+      static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>
+        wchar_conv;
 
       std::string retval = "";
-      if (mbchar != nullptr)
+
+      try
         {
-          retval = std::string (mbchar, length);
-          free (static_cast<void *> (mbchar));
+          retval = wchar_conv.to_bytes (wchar_string);
+        }
+      catch (const std::range_error& e)
+        {
+          // What to do in case of error?
+          // error ("u8_from_wstring: converting from wchar_t to UTF-8: %s",
+          //        e.what ());
         }
 
       return retval;
@@ -523,11 +548,16 @@
     // checks whether there are any non-ASCII characters in the passed
     // file name.  If there are not, it returns the original name.
 
-    // Otherwise, it tries to obtain the short file name (8.3 naming
-    // scheme) which only consists of ASCII characters and are safe to
-    // pass.  However, short file names can be disabled for performance
-    // reasons on the file system level with NTFS.  So there is no
-    // guarantee that these exist.
+    // Otherwise, it optionally tries to convert the file name to the locale
+    // charset.
+
+    // If the file name contains characters that cannot be converted to the
+    // locale charset (or that step is skipped), it tries to obtain the short
+    // file name (8.3 naming scheme) which only consists of ASCII characters
+    // and are safe to pass.  However, short file names can be disabled for
+    // performance reasons on the file system level with NTFS and they are not
+    // stored on other file systems (e.g. ExFAT).  So there is no guarantee
+    // that these exist.
 
     // If short file names are not stored, a hard link to the file is
     // created.  For this the path to the file is split at the deepest
@@ -548,7 +578,8 @@
     // For Unixy systems, this function does nothing.
 
     std::string
-    get_ASCII_filename (const std::string& orig_file_name)
+    get_ASCII_filename (const std::string& orig_file_name,
+                        const bool allow_locale)
     {
 #if defined (OCTAVE_USE_WINDOWS_API)
 
@@ -558,7 +589,7 @@
       // This is useful for passing file names to functions that are not
       // aware of the character encoding we are using.
 
-      // 1. Check whether filename contains non-ASCII (UTF-8) characters.
+      // 0. Check whether filename contains non-ASCII (UTF-8) characters.
 
       std::string::const_iterator first_non_ASCII
         = std::find_if (orig_file_name.begin (), orig_file_name.end (),
@@ -567,8 +598,29 @@
       if (first_non_ASCII == orig_file_name.end ())
         return orig_file_name;
 
-      // 2. Check if file system stores short filenames (always
-      // ASCII-only).
+      // 1. Optionally, check if all characters in the path can be successfully
+      // converted to the locale charset
+      if (allow_locale)
+        {
+          const char *locale = octave_locale_charset_wrapper ();
+          if (locale)
+            {
+              const uint8_t *name_u8 = reinterpret_cast<const uint8_t *>
+                                         (orig_file_name.c_str ());
+              std::size_t length = 0;
+              char *name_locale = octave_u8_conv_to_encoding_strict
+                                    (locale, name_u8,
+                                     orig_file_name.length () + 1, &length);
+              if (name_locale)
+                {
+                  std::string file_name_locale (name_locale, length);
+                  free (name_locale);
+                  return file_name_locale;
+                }
+            }
+        }
+
+      // 2. Check if file system stores short filenames (might be ASCII-only).
 
       std::wstring w_orig_file_name_str = u8_to_wstring (orig_file_name);
       const wchar_t *w_orig_file_name = w_orig_file_name_str.c_str ();
@@ -589,15 +641,24 @@
           // Dynamically allocate the correct size (terminating null char
           // was included in length).
 
-          wchar_t *w_short_file_name = new wchar_t[length];
+          OCTAVE_LOCAL_BUFFER (wchar_t, w_short_file_name, length);
           GetShortPathNameW (w_full_file_name, w_short_file_name, length);
 
           std::wstring w_short_file_name_str
             = std::wstring (w_short_file_name, length);
-          std::string short_file_name = u8_from_wstring (w_short_file_name_str);
 
           if (w_short_file_name_str.compare (0, length-1, w_full_file_name_str) != 0)
-            return short_file_name;
+            {
+              // Check whether short file name contains non-ASCII characters
+              std::string short_file_name
+                = u8_from_wstring (w_short_file_name_str);
+              first_non_ASCII
+                = std::find_if (short_file_name.begin (),
+                                short_file_name.end (),
+                                [](char c) { return (c < 0 || c >= 128); });
+              if (first_non_ASCII == short_file_name.end ())
+                return short_file_name;
+            }
         }
 
       // 3. Create hard link with only-ASCII characters.
@@ -651,6 +712,10 @@
       if (CreateHardLinkW (w_filename_hash, w_orig_file_name, nullptr))
         return filename_hash;
 
+#else
+
+      octave_unused_parameter (allow_locale);
+
 #endif
 
       return orig_file_name;
--- a/liboctave/system/lo-sysdep.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/lo-sysdep.h	Sun May 16 09:44:35 2021 +0200
@@ -41,37 +41,45 @@
 {
   namespace sys
   {
-    extern std::string getcwd (void);
+    extern OCTAVE_API int system (const std::string& cmd_str);
 
-    extern int chdir (const std::string&);
+    extern OCTAVE_API std::string getcwd (void);
 
-    extern bool get_dirlist (const std::string& dirname, string_vector& dirlist,
-                             std::string& msg);
+    extern OCTAVE_API int chdir (const std::string&);
 
-    extern std::FILE * fopen (const std::string& name, const std::string& mode);
+    extern OCTAVE_API bool
+    get_dirlist (const std::string& dirname, string_vector& dirlist,
+                 std::string& msg);
 
-    extern std::fstream fstream (const std::string& name,
-                                 const std::ios::openmode mode =
-                                   std::ios::in | std::ios::out);
+    extern OCTAVE_API std::FILE *
+    fopen (const std::string& name, const std::string& mode);
 
-    extern std::ifstream ifstream (const std::string& name,
-                                   const std::ios::openmode mode = std::ios::in);
+    extern OCTAVE_API std::fstream
+    fstream (const std::string& name,
+             const std::ios::openmode mode = std::ios::in | std::ios::out);
 
-    extern std::ofstream ofstream (const std::string& name,
-                                   const std::ios::openmode mode = std::ios::out);
+    extern OCTAVE_API std::ifstream
+    ifstream (const std::string& name,
+              const std::ios::openmode mode = std::ios::in);
 
-    extern void putenv_wrapper (const std::string& name,
-                                const std::string& value);
+    extern OCTAVE_API std::ofstream
+    ofstream (const std::string& name,
+              const std::ios::openmode mode = std::ios::out);
 
-    extern std::string getenv_wrapper (const std::string&);
+    extern OCTAVE_API void
+    putenv_wrapper (const std::string& name, const std::string& value);
 
-    extern int unsetenv_wrapper (const std::string&);
+    extern OCTAVE_API std::string getenv_wrapper (const std::string&);
 
-    extern std::wstring u8_to_wstring (const std::string&);
+    extern OCTAVE_API int unsetenv_wrapper (const std::string&);
+
+    extern OCTAVE_API std::wstring u8_to_wstring (const std::string&);
 
-    extern std::string u8_from_wstring (const std::wstring&);
+    extern OCTAVE_API std::string u8_from_wstring (const std::wstring&);
 
-    extern std::string get_ASCII_filename (const std::string& long_file_name);
+    extern OCTAVE_API std::string
+    get_ASCII_filename (const std::string& long_file_name,
+                        const bool allow_locale = false);
   }
 }
 
--- a/liboctave/system/lo-sysinfo.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/lo-sysinfo.h	Sun May 16 09:44:35 2021 +0200
@@ -34,9 +34,9 @@
 {
   namespace sys
   {
-    extern std::string blas_version (void);
+    extern OCTAVE_API std::string blas_version (void);
 
-    extern std::string lapack_version (void);
+    extern OCTAVE_API std::string lapack_version (void);
   }
 }
 
--- a/liboctave/system/mach-info.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/mach-info.h	Sun May 16 09:44:35 2021 +0200
@@ -44,15 +44,15 @@
       flt_fmt_ieee_big_endian = 2,
     };
 
-    float_format native_float_format (void);
+    OCTAVE_API float_format native_float_format (void);
 
-    bool words_big_endian (void);
+    OCTAVE_API bool words_big_endian (void);
 
-    bool words_little_endian (void);
+    OCTAVE_API bool words_little_endian (void);
 
-    float_format string_to_float_format (const std::string&);
+    OCTAVE_API float_format string_to_float_format (const std::string&);
 
-    std::string float_format_as_string (float_format);
+    OCTAVE_API std::string float_format_as_string (float_format);
   }
 }
 
--- a/liboctave/system/oct-env.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/oct-env.cc	Sun May 16 09:44:35 2021 +0200
@@ -61,8 +61,6 @@
 #include "unistd-wrappers.h"
 
 #if defined (OCTAVE_USE_WINDOWS_API)
-#  include "uniconv-wrappers.h"
-
 #  include <windows.h>
 #  include <shlobj.h>
 #endif
@@ -165,6 +163,13 @@
     }
 
     std::string
+    env::get_user_data_directory ()
+    {
+      return (instance_ok ())
+        ? instance->do_get_user_data_directory () : "";
+    }
+
+    std::string
     env::get_program_name (void)
     {
       return (instance_ok ())
@@ -247,22 +252,40 @@
       wchar_t path[MAX_PATH+1];
       if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
                             nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
-        {
-          char *local_app_data = u8_from_wchar (path);
-          cfg_dir = local_app_data;
-          free (local_app_data);
-        }
+        cfg_dir = u8_from_wstring (path);
 #else
       cfg_dir = do_getenv ("XDG_CONFIG_HOME");
+#endif
 
       if (cfg_dir.empty ())
         cfg_dir = do_get_home_directory () + sys::file_ops::dir_sep_str ()
              + ".config";
-#endif
 
       return cfg_dir;
     }
 
+  std::string
+  env::do_get_user_data_directory (void) const
+  {
+      std::string data_dir;
+
+#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && defined (OCTAVE_USE_WINDOWS_API)
+      wchar_t path[MAX_PATH+1];
+      if (SHGetFolderPathW (nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
+                            nullptr, SHGFP_TYPE_CURRENT, path) == S_OK)
+        data_dir = u8_from_wstring (path);
+#else
+      data_dir = do_getenv ("XDG_DATA_HOME");
+#endif
+
+      if (data_dir.empty ())
+        data_dir = do_get_home_directory () + sys::file_ops::dir_sep_str ()
+             + ".local" + sys::file_ops::dir_sep_str () + "share";
+
+      return data_dir;
+  }
+
+
     // FIXME: this leaves no way to distinguish between a
     // variable that is not set and one that is set to the empty string.
     // Is this a problem?
--- a/liboctave/system/oct-env.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/oct-env.h	Sun May 16 09:44:35 2021 +0200
@@ -70,6 +70,8 @@
 
       static std::string get_user_config_directory (void);
 
+      static std::string get_user_data_directory (void);
+
       static std::string get_program_name (void);
 
       static std::string get_program_invocation_name (void);
@@ -111,6 +113,8 @@
 
       std::string do_get_user_config_directory (void) const;
 
+      std::string do_get_user_data_directory (void) const;
+
       std::string do_get_user_name (void) const;
 
       std::string do_get_host_name (void) const;
--- a/liboctave/system/oct-time.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/oct-time.cc	Sun May 16 09:44:35 2021 +0200
@@ -34,8 +34,13 @@
 #include <limits>
 #include <ostream>
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#endif
+
 #include "lo-error.h"
 #include "lo-utils.h"
+#include "lo-sysdep.h"
 #include "oct-locbuf.h"
 #include "oct-time.h"
 #include "octave-preserve-stream-state.h"
@@ -238,11 +243,25 @@
 
 #if defined (HAVE_TM_GMTOFF)
       m_gmtoff = t->tm_gmtoff;
+#elif defined (OCTAVE_USE_WINDOWS_API)
+      TIME_ZONE_INFORMATION tzi;
+
+      GetTimeZoneInformationForYear (m_year, nullptr, &tzi);
+
+      if (m_isdst)
+        m_gmtoff = -60 * (tzi.Bias + tzi.DaylightBias);
+      else
+        m_gmtoff = -60 * (tzi.Bias + tzi.StandardBias);
 #endif
 
 #if defined (HAVE_STRUCT_TM_TM_ZONE)
       if (t->tm_zone)
         m_zone = t->tm_zone;
+#elif defined (OCTAVE_USE_WINDOWS_API)
+      if (m_isdst)
+        m_zone = sys::u8_from_wstring (tzi.DaylightName);
+      else
+        m_zone = sys::u8_from_wstring (tzi.StandardName);
 #elif defined (HAVE_TZNAME)
       if (t->tm_isdst == 0 || t->tm_isdst == 1)
         m_zone = tzname[t->tm_isdst];
--- a/liboctave/system/oct-time.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/system/oct-time.h	Sun May 16 09:44:35 2021 +0200
@@ -50,7 +50,6 @@
     class base_tm;
 
     class
-    OCTAVE_API
     time
     {
     public:
@@ -83,9 +82,9 @@
         ot_unix_time += extra;
       }
 
-      time (double d);
+      OCTAVE_API time (double d);
 
-      time (const base_tm& tm);
+      OCTAVE_API time (const base_tm& tm);
 
       time (const time& ot)
         : ot_unix_time (ot.ot_unix_time), ot_usec (ot.ot_usec) { }
@@ -103,7 +102,7 @@
 
       ~time (void) = default;
 
-      void stamp (void);
+      OCTAVE_API void stamp (void);
 
       double double_value (void) const
       {
@@ -114,9 +113,9 @@
 
       long usec (void) const { return ot_usec; }
 
-      std::string ctime (void) const;
+      OCTAVE_API std::string ctime (void) const;
 
-      friend std::ostream& operator << (std::ostream& os, const time& ot);
+      friend OCTAVE_API std::ostream& operator << (std::ostream& os, const time& ot);
 
     private:
 
@@ -185,7 +184,6 @@
     }
 
     class
-    OCTAVE_API
     base_tm
     {
     public:
@@ -239,20 +237,20 @@
       long gmtoff (void) const { return m_gmtoff; }
       std::string zone (void) const { return m_zone; }
 
-      base_tm& usec (int v);
-      base_tm& sec (int v);
-      base_tm& min (int v);
-      base_tm& hour (int v);
-      base_tm& mday (int v);
-      base_tm& mon (int v);
-      base_tm& year (int v);
-      base_tm& wday (int v);
-      base_tm& yday (int v);
-      base_tm& isdst (int v);
-      base_tm& gmtoff (long v);
-      base_tm& zone (const std::string& s);
+      OCTAVE_API base_tm& usec (int v);
+      OCTAVE_API base_tm& sec (int v);
+      OCTAVE_API base_tm& min (int v);
+      OCTAVE_API base_tm& hour (int v);
+      OCTAVE_API base_tm& mday (int v);
+      OCTAVE_API base_tm& mon (int v);
+      OCTAVE_API base_tm& year (int v);
+      OCTAVE_API base_tm& wday (int v);
+      OCTAVE_API base_tm& yday (int v);
+      OCTAVE_API base_tm& isdst (int v);
+      OCTAVE_API base_tm& gmtoff (long v);
+      OCTAVE_API base_tm& zone (const std::string& s);
 
-      std::string strftime (const std::string& fmt) const;
+      OCTAVE_API std::string strftime (const std::string& fmt) const;
 
       std::string asctime (void) const
       { return strftime ("%a %b %d %H:%M:%S %Y\n"); }
@@ -295,11 +293,10 @@
       // Time zone.
       std::string m_zone;
 
-      void init (void *p);
+      OCTAVE_API void init (void *p);
     };
 
     class
-    OCTAVE_API
     localtime : public base_tm
     {
     public:
@@ -323,11 +320,10 @@
 
     private:
 
-      void init (const time& ot);
+      OCTAVE_API void init (const time& ot);
     };
 
     class
-    OCTAVE_API
     gmtime : public base_tm
     {
     public:
@@ -348,11 +344,10 @@
 
     private:
 
-      void init (const time& ot);
+      OCTAVE_API void init (const time& ot);
     };
 
     class
-    OCTAVE_API
     strptime : public base_tm
     {
     public:
@@ -381,11 +376,10 @@
 
       int nchars;
 
-      void init (const std::string& str, const std::string& fmt);
+      OCTAVE_API void init (const std::string& str, const std::string& fmt);
     };
 
     class
-    OCTAVE_API
     cpu_time
     {
     public:
@@ -416,7 +410,7 @@
         return *this;
       }
 
-      void stamp (void);
+      OCTAVE_API void stamp (void);
 
       double user (void) const
       {
@@ -498,7 +492,7 @@
         return *this;
       }
 
-      void stamp (void);
+      OCTAVE_API void stamp (void);
 
       cpu_time cpu (void) const { return m_cpu; }
 
--- a/liboctave/util/action-container.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/action-container.cc	Sun May 16 09:44:35 2021 +0200
@@ -23,6 +23,10 @@
 //
 ////////////////////////////////////////////////////////////////////////
 
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
 #include "action-container.h"
 #include "cmd-edit.h"
 
--- a/liboctave/util/action-container.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/action-container.h	Sun May 16 09:44:35 2021 +0200
@@ -70,6 +70,9 @@
     {
     public:
 
+      // FIXME: Do we need to apply std::forward to the arguments to
+      // std::bind here?
+
       template <typename F, typename... Args>
       fcn_elem (F&& fcn, Args&&... args)
         : m_fcn (std::bind (fcn, args...))
@@ -193,7 +196,7 @@
 
     virtual void run_first (void) = 0;
 
-    void run (std::size_t num);
+    OCTAVE_API void run (std::size_t num);
 
     void run (void) { run (size ()); }
 
--- a/liboctave/util/cmd-edit.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/cmd-edit.cc	Sun May 16 09:44:35 2021 +0200
@@ -562,7 +562,7 @@
   char *
   gnu_readline::do_completer_word_break_hook ()
   {
-    static char *dir_sep = octave_strdup_wrapper (" '\"");
+    static char *dir_sep = octave_strdup_wrapper (R"( '")");
 
     std::string word;
     std::string line = get_line_buffer ();
--- a/liboctave/util/cmd-hist.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/cmd-hist.cc	Sun May 16 09:44:35 2021 +0200
@@ -46,6 +46,7 @@
 
 #include "oct-rl-hist.h"
 
+#include "file-ops.h"
 #include "file-stat.h"
 #endif
 
@@ -364,6 +365,17 @@
 
         if (! f.empty ())
           {
+            // Try to create the folder if it does not exist
+            std::string hist_dir = sys::file_ops::dirname (f);
+            if (! hist_dir.empty ())
+              {
+                sys::file_stat fs (hist_dir);
+                if (! fs.is_dir () && (sys::mkdir (hist_dir, 0777) < 0))
+                  (*current_liboctave_error_handler)
+                    ("%s: Could not create directory \"%s\" for history",
+                     "gnu_history::do_write", hist_dir.c_str ());
+              }
+
             int status = ::octave_write_history (f.c_str ());
 
             if (status != 0)
--- a/liboctave/util/data-conv.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/data-conv.cc	Sun May 16 09:44:35 2021 +0200
@@ -819,9 +819,10 @@
         std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
         is.read (reinterpret_cast<char *> (data), n_bytes);
         do_double_format_conversion (data, len, fmt);
-
-        for (int i = 0; i < len; i++)
-          data[i] = __lo_ieee_replace_old_NA (data[i]);
+        // FIXME: Potentially add conversion code for MIPS NA here, Bug #59830.
+        //
+        // for (int i = 0; i < len; i++)
+        //   data[i] = __lo_ieee_replace_MIPS_NA (data[i]);
       }
       break;
 
--- a/liboctave/util/file-info.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/file-info.h	Sun May 16 09:44:35 2021 +0200
@@ -62,9 +62,10 @@
 
     ~file_info (void) = default;
 
-    std::string get_line (std::size_t line) const;
+    OCTAVE_API std::string get_line (std::size_t line) const;
 
-    std::deque<std::string> get_lines (std::size_t line, std::size_t num_lines) const;
+    OCTAVE_API std::deque<std::string>
+    get_lines (std::size_t line, std::size_t num_lines) const;
 
     std::size_t num_lines (void) const { return m_offsets.size (); }
 
@@ -87,9 +88,10 @@
     sys::time m_timestamp;
 
     // Read entire file called fname and return the contents as a string
-    static std::string snarf_file (const std::string& fname);
+    static OCTAVE_API std::string snarf_file (const std::string& fname);
 
-    static std::vector<std::size_t> get_line_offsets (const std::string& buf);
+    static OCTAVE_API std::vector<std::size_t>
+    get_line_offsets (const std::string& buf);
   };
 }
 
--- a/liboctave/util/lo-array-errwarn.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-array-errwarn.h	Sun May 16 09:44:35 2021 +0200
@@ -96,7 +96,7 @@
   protected:
 
     // Show what's wrong, e.g.,  A(-1,_), A(0+1i).
-    std::string expression (void) const;
+    OCTAVE_API std::string expression (void) const;
 
     // Number of dimensions of indexed object.
     octave_idx_type m_nd;
@@ -108,57 +108,57 @@
     std::string m_var;
   };
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_nan_to_logical_conversion (void);
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_nan_to_character_conversion (void);
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_nonconformant (const char *op, octave_idx_type op1_len,
                      octave_idx_type op2_len);
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_nonconformant (const char *op,
                      octave_idx_type op1_nr, octave_idx_type op1_nc,
                      octave_idx_type op2_nr, octave_idx_type op2_nc);
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_nonconformant (const char *op,
                      const dim_vector& op1_dims, const dim_vector& op2_dims);
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_index_out_of_range (int ndims, int dim, octave_idx_type idx,
                           octave_idx_type ext, const dim_vector& dv);
 
   OCTAVE_DEPRECATED (6, "use err_index_out_of_range (int, int, octave_idx_type, octave_idx_type, const dim_vector&) instead")
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_index_out_of_range (int ndims, int dim, octave_idx_type idx,
                           octave_idx_type ext);
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_del_index_out_of_range (bool is1d, octave_idx_type iext,
                               octave_idx_type ext);
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_invalid_index (double n, octave_idx_type nd = 0,
                      octave_idx_type dim = 0,
                      const std::string& var = "");
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_invalid_index (octave_idx_type n, octave_idx_type nd = 0,
                      octave_idx_type dim = 0,
                      const std::string& var = "");
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_invalid_index (const std::string& idx, octave_idx_type nd = 0,
                      octave_idx_type dim = 0,
                      const std::string& var = "");
 
-  OCTAVE_NORETURN OCTAVE_API extern void
+  OCTAVE_NORETURN extern OCTAVE_API void
   err_invalid_resize (void);
 
-  OCTAVE_API extern void
+  extern OCTAVE_API void
   warn_singular_matrix (double rcond = 0.0);
 }
 
--- a/liboctave/util/lo-error.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-error.h	Sun May 16 09:44:35 2021 +0200
@@ -32,16 +32,16 @@
 extern "C" {
 #endif
 
-OCTAVE_NORETURN extern void
+OCTAVE_NORETURN extern OCTAVE_API void
 liboctave_fatal (const char *fmt, ...);
 
-OCTAVE_NORETURN extern
-void liboctave_fatal_with_id (const char *id, const char *fmt, ...);
+OCTAVE_NORETURN extern OCTAVE_API void
+liboctave_fatal_with_id (const char *id, const char *fmt, ...);
 
-extern void
+extern OCTAVE_API void
 liboctave_warning (const char *fmt, ...);
 
-extern void
+extern OCTAVE_API void
 liboctave_warning_with_id (const char *id, const char *fmt, ...);
 
 typedef void (*liboctave_error_handler) (const char *, ...);
@@ -57,30 +57,30 @@
 /* Would be nice to make these pointers private, but we want to share
    them among all the liboctave classes. */
 OCTAVE_FORMAT_PRINTF (1, 2)
-OCTAVE_NORETURN OCTAVE_API extern liboctave_error_handler
+OCTAVE_NORETURN extern OCTAVE_API liboctave_error_handler
   current_liboctave_error_handler;
 
 OCTAVE_FORMAT_PRINTF (2, 3)
-OCTAVE_NORETURN OCTAVE_API extern liboctave_error_with_id_handler
+OCTAVE_NORETURN extern OCTAVE_API liboctave_error_with_id_handler
   current_liboctave_error_with_id_handler;
 
 OCTAVE_FORMAT_PRINTF (1, 2)
-OCTAVE_API extern liboctave_warning_handler current_liboctave_warning_handler;
+extern OCTAVE_API liboctave_warning_handler current_liboctave_warning_handler;
 
 OCTAVE_FORMAT_PRINTF (2, 3)
-OCTAVE_API extern liboctave_warning_with_id_handler
+extern OCTAVE_API liboctave_warning_with_id_handler
   current_liboctave_warning_with_id_handler;
 
-OCTAVE_API extern void
+extern OCTAVE_API void
 set_liboctave_error_handler (OCTAVE_NORETURN liboctave_error_handler f);
 
-OCTAVE_API extern void
+extern OCTAVE_API void
 set_liboctave_error_with_id_handler (OCTAVE_NORETURN liboctave_error_with_id_handler f);
 
-OCTAVE_API extern void
+extern OCTAVE_API void
 set_liboctave_warning_handler (liboctave_warning_handler f);
 
-OCTAVE_API extern void
+extern OCTAVE_API void
 set_liboctave_warning_with_id_handler (liboctave_warning_with_id_handler f);
 
 #if defined (__cplusplus)
--- a/liboctave/util/lo-hash.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-hash.h	Sun May 16 09:44:35 2021 +0200
@@ -36,28 +36,29 @@
   {
     typedef void * (hash_fptr) (const char *buffer, std::size_t len, void *res);
 
-    std::string
+    OCTAVE_API std::string
     hash (hash_fptr hash_fcn, const std::string& str, int result_buf_len);
 
-    int md2_digest_size (void);
-    int md4_digest_size (void);
-    int md5_digest_size (void);
-    int sha1_digest_size (void);
-    int sha224_digest_size (void);
-    int sha256_digest_size (void);
-    int sha384_digest_size (void);
-    int sha512_digest_size (void);
+    OCTAVE_API int md2_digest_size (void);
+    OCTAVE_API int md4_digest_size (void);
+    OCTAVE_API int md5_digest_size (void);
+    OCTAVE_API int sha1_digest_size (void);
+    OCTAVE_API int sha224_digest_size (void);
+    OCTAVE_API int sha256_digest_size (void);
+    OCTAVE_API int sha384_digest_size (void);
+    OCTAVE_API int sha512_digest_size (void);
 
-    std::string md2_hash (const std::string& str);
-    std::string md4_hash (const std::string& str);
-    std::string md5_hash (const std::string& str);
-    std::string sha1_hash (const std::string& str);
-    std::string sha224_hash (const std::string& str);
-    std::string sha256_hash (const std::string& str);
-    std::string sha384_hash (const std::string& str);
-    std::string sha512_hash (const std::string& str);
+    OCTAVE_API std::string md2_hash (const std::string& str);
+    OCTAVE_API std::string md4_hash (const std::string& str);
+    OCTAVE_API std::string md5_hash (const std::string& str);
+    OCTAVE_API std::string sha1_hash (const std::string& str);
+    OCTAVE_API std::string sha224_hash (const std::string& str);
+    OCTAVE_API std::string sha256_hash (const std::string& str);
+    OCTAVE_API std::string sha384_hash (const std::string& str);
+    OCTAVE_API std::string sha512_hash (const std::string& str);
 
-    std::string hash (const std::string& hash_type, const std::string& str);
+    OCTAVE_API std::string
+    hash (const std::string& hash_type, const std::string& str);
   }
 }
 
--- a/liboctave/util/lo-ieee.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-ieee.cc	Sun May 16 09:44:35 2021 +0200
@@ -56,24 +56,6 @@
           && t.word[lo_ieee_lw] == LO_IEEE_NA_LW) ? 1 : 0;
 }
 
-int
-__lo_ieee_is_old_NA (double x)
-{
-  lo_ieee_double t;
-  t.value = x;
-  return (__lo_ieee_isnan (x) && t.word[lo_ieee_lw] == LO_IEEE_NA_LW_OLD
-          && t.word[lo_ieee_hw] == LO_IEEE_NA_HW_OLD) ? 1 : 0;
-}
-
-double
-__lo_ieee_replace_old_NA (double x)
-{
-  if (__lo_ieee_is_old_NA (x))
-    return lo_ieee_na_value ();
-  else
-    return x;
-}
-
 double
 lo_ieee_inf_value (void)
 {
--- a/liboctave/util/lo-ieee.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-ieee.h	Sun May 16 09:44:35 2021 +0200
@@ -67,8 +67,6 @@
   unsigned int word;
 } lo_ieee_float;
 
-#define LO_IEEE_NA_HW_OLD 0x7ff00000
-#define LO_IEEE_NA_LW_OLD 1954
 #if defined (HAVE_MIPS_NAN)
   #define LO_IEEE_NA_HW 0x7FF040F4
 #else
@@ -84,8 +82,6 @@
 inline int __lo_ieee_isinf (double x) { return std::isinf (x); }
 
 extern OCTAVE_API int __lo_ieee_is_NA (double);
-extern OCTAVE_API int __lo_ieee_is_old_NA (double);
-extern OCTAVE_API double __lo_ieee_replace_old_NA (double);
 
 extern OCTAVE_API double lo_ieee_inf_value (void);
 extern OCTAVE_API double lo_ieee_na_value (void);
--- a/liboctave/util/lo-regexp.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-regexp.cc	Sun May 16 09:44:35 2021 +0200
@@ -247,7 +247,7 @@
   }
 
   regexp::match_data
-  regexp::match (const std::string& buffer)
+  regexp::match (const std::string& buffer) const
   {
     // check if input is valid utf-8
     const uint8_t *buf_str = reinterpret_cast<const uint8_t *> (buffer.c_str ());
@@ -437,7 +437,7 @@
   }
 
   bool
-  regexp::is_match (const std::string& buffer)
+  regexp::is_match (const std::string& buffer) const
   {
     regexp::match_data rx_lst = match (buffer);
 
@@ -445,7 +445,7 @@
   }
 
   Array<bool>
-  regexp::is_match (const string_vector& buffer)
+  regexp::is_match (const string_vector& buffer) const
   {
     octave_idx_type len = buffer.numel ();
 
@@ -465,7 +465,8 @@
   } rep_token_t;
 
   std::string
-  regexp::replace (const std::string& buffer, const std::string& replacement)
+  regexp::replace (const std::string& buffer,
+                   const std::string& replacement) const
   {
     std::string retval;
 
--- a/liboctave/util/lo-regexp.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-regexp.h	Sun May 16 09:44:35 2021 +0200
@@ -71,16 +71,16 @@
       compile_internal ();
     }
 
-    match_data match (const std::string& buffer);
+    match_data match (const std::string& buffer) const;
 
-    bool is_match (const std::string& buffer);
+    bool is_match (const std::string& buffer) const;
 
-    Array<bool> is_match (const string_vector& buffer);
+    Array<bool> is_match (const string_vector& buffer) const;
 
     std::string replace (const std::string& buffer,
-                         const std::string& replacement);
+                         const std::string& replacement) const;
 
-    static regexp::match_data
+    static match_data
     match (const std::string& pat, const std::string& buffer,
            const regexp::opts& opt = regexp::opts (),
            const std::string& who = "regexp")
--- a/liboctave/util/lo-utils.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-utils.cc	Sun May 16 09:44:35 2021 +0200
@@ -38,20 +38,16 @@
 
 #include "quit.h"
 
+#include "intprops-wrappers.h"
 #include "lo-error.h"
 #include "lo-ieee.h"
 #include "lo-mappers.h"
 #include "lo-utils.h"
+#include "oct-inttypes.h"
 
 bool xis_int_or_inf_or_nan (double x)
 { return octave::math::isnan (x) || octave::math::x_nint (x) == x; }
 
-bool xis_one_or_zero (double x)
-{ return x == 0 || x == 1; }
-
-bool xis_zero (double x)
-{ return x == 0; }
-
 bool xtoo_large_for_float (double x)
 {
   return (octave::math::isfinite (x)
@@ -67,12 +63,6 @@
 bool xis_int_or_inf_or_nan (float x)
 { return octave::math::isnan (x) || octave::math::x_nint (x) == x; }
 
-bool xis_one_or_zero (float x)
-{ return x == 0 || x == 1; }
-
-bool xis_zero (float x)
-{ return x == 0; }
-
 // Save a string.
 
 char *
@@ -187,244 +177,345 @@
   return retval;
 }
 
-// Note that the caller is responsible for repositioning the stream on failure.
+namespace octave
+{
+  template <typename T>
+  T
+  read_value (std::istream& is)
+  {
+    T retval;
+    is >> retval;
+    return retval;
+  }
+
+  template OCTAVE_API bool read_value<bool> (std::istream& is);
+  template OCTAVE_API octave_int8 read_value<octave_int8> (std::istream& is);
+  template OCTAVE_API octave_int16 read_value<octave_int16> (std::istream& is);
+  template OCTAVE_API octave_int32 read_value<octave_int32> (std::istream& is);
+  template OCTAVE_API octave_int64 read_value<octave_int64> (std::istream& is);
+  template OCTAVE_API octave_uint8 read_value<octave_uint8> (std::istream& is);
+  template OCTAVE_API octave_uint16 read_value<octave_uint16> (std::istream& is);
+  template OCTAVE_API octave_uint32 read_value<octave_uint32> (std::istream& is);
+  template OCTAVE_API octave_uint64 read_value<octave_uint64> (std::istream& is);
+
+  // Note that the caller is responsible for repositioning the stream on
+  // failure.
+
+  template <typename T>
+  T
+  read_inf_nan_na (std::istream& is, char c0)
+  {
+    T val = 0.0;
 
-template <typename T>
-T
-read_inf_nan_na (std::istream& is, char c0)
-{
-  T val = 0.0;
+    switch (c0)
+      {
+      case 'i': case 'I':
+        {
+          char c1 = is.get ();
+          if (c1 == 'n' || c1 == 'N')
+            {
+              char c2 = is.get ();
+              if (c2 == 'f' || c2 == 'F')
+                val = std::numeric_limits<T>::infinity ();
+              else
+                is.setstate (std::ios::failbit);
+            }
+          else
+            is.setstate (std::ios::failbit);
+        }
+        break;
+
+      case 'n': case 'N':
+        {
+          char c1 = is.get ();
+          if (c1 == 'a' || c1 == 'A')
+            {
+              char c2 = is.get ();
+              if (c2 == 'n' || c2 == 'N')
+                val = std::numeric_limits<T>::quiet_NaN ();
+              else
+                {
+                  val = numeric_limits<T>::NA ();
+                  if (c2 != std::istream::traits_type::eof ())
+                    is.putback (c2);
+                  else
+                    is.clear (is.rdstate () & ~std::ios::failbit);
+                }
+            }
+          else
+            is.setstate (std::ios::failbit);
+        }
+        break;
+
+      default:
+        (*current_liboctave_error_handler)
+          ("read_inf_nan_na: invalid character '%c'", c0);
+      }
+
+    return val;
+  }
+
+  // Read a double value.  Discard any sign on NaN and NA.
+
+  template <typename T>
+  double
+  read_fp_value (std::istream& is)
+  {
+    T val = 0.0;
+
+    // FIXME: resetting stream position is likely to fail unless we are
+    // reading from a file.
+    std::streampos pos = is.tellg ();
 
-  switch (c0)
-    {
-    case 'i': case 'I':
+    char c1 = ' ';
+
+    while (isspace (c1))
+      c1 = is.get ();
+
+    bool neg = false;
+
+    switch (c1)
+      {
+      case '-':
+        neg = true;
+        OCTAVE_FALLTHROUGH;
+
+      case '+':
+        {
+          char c2 = 0;
+          c2 = is.get ();
+          if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
+            val = read_inf_nan_na<T> (is, c2);
+          else
+            {
+              is.putback (c2);
+              is >> val;
+            }
+
+          if (neg && ! is.fail ())
+            val = -val;
+        }
+        break;
+
+      case 'i': case 'I':
+      case 'n': case 'N':
+        val = read_inf_nan_na<T> (is, c1);
+        break;
+
+      default:
+        is.putback (c1);
+        is >> val;
+        break;
+      }
+
+    std::ios::iostate status = is.rdstate ();
+    if (status & std::ios::failbit)
       {
-        char c1 = is.get ();
-        if (c1 == 'n' || c1 == 'N')
+        // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
+        if (val == std::numeric_limits<T>::max ())
+          {
+            if (neg)
+              val = -std::numeric_limits<T>::infinity ();
+            else
+              val = std::numeric_limits<T>::infinity ();
+            is.clear (status & ~std::ios::failbit);
+          }
+        else
           {
-            char c2 = is.get ();
-            if (c2 == 'f' || c2 == 'F')
-              val = std::numeric_limits<T>::infinity ();
+            // True error.  Reset stream to original position and pass status on.
+            is.clear ();
+            is.seekg (pos);
+            is.setstate (status);
+          }
+      }
+
+    return val;
+  }
+
+  template <typename T>
+  std::complex<T>
+  read_cx_fp_value (std::istream& is)
+  {
+    T re = 0.0;
+    T im = 0.0;
+
+    std::complex<T> cx = 0.0;
+
+    char ch = ' ';
+
+    while (isspace (ch))
+      ch = is.get ();
+
+    if (ch == '(')
+      {
+        re = read_value<T> (is);
+        ch = is.get ();
+
+        if (ch == ',')
+          {
+            im = read_value<T> (is);
+            ch = is.get ();
+
+            if (ch == ')')
+              cx = std::complex<T> (re, im);
             else
               is.setstate (std::ios::failbit);
           }
-        else
-          is.setstate (std::ios::failbit);
-      }
-      break;
-
-    case 'n': case 'N':
-      {
-        char c1 = is.get ();
-        if (c1 == 'a' || c1 == 'A')
-          {
-            char c2 = is.get ();
-            if (c2 == 'n' || c2 == 'N')
-              val = std::numeric_limits<T>::quiet_NaN ();
-            else
-              {
-                val = octave::numeric_limits<T>::NA ();
-                if (c2 != std::istream::traits_type::eof ())
-                  is.putback (c2);
-                else
-                  is.clear (is.rdstate () & ~std::ios::failbit);
-              }
-          }
+        else if (ch == ')')
+          cx = re;
         else
           is.setstate (std::ios::failbit);
       }
-      break;
-
-    default:
-      (*current_liboctave_error_handler)
-        ("read_inf_nan_na: invalid character '%c'", c0);
-    }
-
-  return val;
-}
-
-// Read a double value.  Discard any sign on NaN and NA.
-
-template <typename T>
-double
-octave_read_fp_value (std::istream& is)
-{
-  T val = 0.0;
-
-  // FIXME: resetting stream position is likely to fail unless we are
-  // reading from a file.
-  std::streampos pos = is.tellg ();
-
-  char c1 = ' ';
-
-  while (isspace (c1))
-    c1 = is.get ();
-
-  bool neg = false;
-
-  switch (c1)
-    {
-    case '-':
-      neg = true;
-      OCTAVE_FALLTHROUGH;
-
-    case '+':
+    else
       {
-        char c2 = 0;
-        c2 = is.get ();
-        if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          val = read_inf_nan_na<T> (is, c2);
-        else
-          {
-            is.putback (c2);
-            is >> val;
-          }
+        is.putback (ch);
+        cx = read_value<T> (is);
+      }
+
+    return cx;
+  }
+
+  // FIXME: Could we use traits and enable_if to avoid duplication in the
+  // following specializations?
+
+  template <> OCTAVE_API double read_value (std::istream& is)
+  {
+    return read_fp_value<double> (is);
+  }
+
+  template <> OCTAVE_API Complex read_value (std::istream& is)
+  {
+    return read_cx_fp_value<double> (is);
+  }
+
+  template <> OCTAVE_API float read_value (std::istream& is)
+  {
+    return read_fp_value<float> (is);
+  }
 
-        if (neg && ! is.fail ())
-          val = -val;
-      }
-      break;
+  template <> OCTAVE_API FloatComplex read_value (std::istream& is)
+  {
+    return read_cx_fp_value<float> (is);
+  }
+
+  template <typename T>
+  void
+  write_value (std::ostream& os, const T& value)
+  {
+    os << value;
+  }
 
-    case 'i': case 'I':
-    case 'n': case 'N':
-      val = read_inf_nan_na<T> (is, c1);
-      break;
+  template OCTAVE_API void
+  write_value<bool> (std::ostream& os, const bool& value);
+  template OCTAVE_API void
+  write_value<octave_int8> (std::ostream& os, const octave_int8& value);
+  template OCTAVE_API void
+  write_value<octave_int16> (std::ostream& os, const octave_int16& value);
+  template OCTAVE_API void
+  write_value<octave_int32> (std::ostream& os, const octave_int32& value);
+  template OCTAVE_API void
+  write_value<octave_int64> (std::ostream& os, const octave_int64& value);
+  template OCTAVE_API void
+  write_value<octave_uint8> (std::ostream& os, const octave_uint8& value);
+  template OCTAVE_API void
+  write_value<octave_uint16> (std::ostream& os, const octave_uint16& value);
+  template OCTAVE_API void
+  write_value<octave_uint32> (std::ostream& os, const octave_uint32& value);
+  template OCTAVE_API void
+  write_value<octave_uint64> (std::ostream& os, const octave_uint64& value);
 
-    default:
-      is.putback (c1);
-      is >> val;
-      break;
-    }
+  // Note: precision is supposed to be managed outside of this function by
+  // setting stream parameters.
+
+  template <> OCTAVE_API void
+  write_value (std::ostream& os, const double& value)
+  {
+    if (lo_ieee_is_NA (value))
+      os << "NA";
+    else if (lo_ieee_isnan (value))
+      os << "NaN";
+    else if (lo_ieee_isinf (value))
+      os << (value < 0 ? "-Inf" : "Inf");
+    else
+      os << value;
+  }
+
+  template <> OCTAVE_API void
+  write_value (std::ostream& os, const Complex& value)
+  {
+    os << '(';
+    write_value<double> (os, real (value));
+    os << ',';
+    write_value<double> (os, imag (value));
+    os << ')';
+  }
 
-  std::ios::iostate status = is.rdstate ();
-  if (status & std::ios::failbit)
+  // Note: precision is supposed to be managed outside of this function by
+  // setting stream parameters.
+
+  template <> OCTAVE_API void
+  write_value (std::ostream& os, const float& value)
+  {
+    if (lo_ieee_is_NA (value))
+      os << "NA";
+    else if (lo_ieee_isnan (value))
+      os << "NaN";
+    else if (lo_ieee_isinf (value))
+      os << (value < 0 ? "-Inf" : "Inf");
+    else
+      os << value;
+  }
+
+  template <> OCTAVE_API void
+  write_value (std::ostream& os, const FloatComplex& value)
+  {
+    os << '(';
+    write_value<float> (os, real (value));
+    os << ',';
+    write_value<float> (os, imag (value));
+    os << ')';
+  }
+
+  namespace math
+  {
+    bool int_multiply_overflow (int a, int b, int *r)
     {
-      // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
-      if (val == std::numeric_limits<T>::max ())
-        {
-          if (neg)
-            val = -std::numeric_limits<T>::infinity ();
-          else
-            val = std::numeric_limits<T>::infinity ();
-          is.clear (status & ~std::ios::failbit);
-        }
-      else
-        {
-          // True error.  Reset stream to original position and pass status on.
-          is.clear ();
-          is.seekg (pos);
-          is.setstate (status);
-        }
+      return octave_i_multiply_overflow_wrapper (a, b, r);
     }
 
-  return val;
-}
-
-template <typename T>
-std::complex<T>
-octave_read_cx_fp_value (std::istream& is)
-{
-  T re = 0.0;
-  T im = 0.0;
-
-  std::complex<T> cx = 0.0;
-
-  char ch = ' ';
-
-  while (isspace (ch))
-    ch = is.get ();
-
-  if (ch == '(')
+    bool int_multiply_overflow (long int a, long int b, long int *r)
     {
-      re = octave_read_value<T> (is);
-      ch = is.get ();
-
-      if (ch == ',')
-        {
-          im = octave_read_value<T> (is);
-          ch = is.get ();
-
-          if (ch == ')')
-            cx = std::complex<T> (re, im);
-          else
-            is.setstate (std::ios::failbit);
-        }
-      else if (ch == ')')
-        cx = re;
-      else
-        is.setstate (std::ios::failbit);
-    }
-  else
-    {
-      is.putback (ch);
-      cx = octave_read_value<double> (is);
+      return octave_li_multiply_overflow_wrapper (a, b, r);
     }
 
-  return cx;
-}
-
-template <> OCTAVE_API double octave_read_value (std::istream& is)
-{
-  return octave_read_fp_value<double> (is);
-}
+#if defined (OCTAVE_HAVE_LONG_LONG_INT)
+    bool int_multiply_overflow (long long int a, long long int b,
+                                long long int *r)
+    {
+      return octave_lli_multiply_overflow_wrapper (a, b, r);
+    }
+#endif
 
-template <> OCTAVE_API Complex octave_read_value (std::istream& is)
-{
-  return octave_read_cx_fp_value<double> (is);
-}
-
-template <> OCTAVE_API float octave_read_value (std::istream& is)
-{
-  return octave_read_fp_value<float> (is);
-}
-
-template <> OCTAVE_API FloatComplex octave_read_value (std::istream& is)
-{
-  return octave_read_cx_fp_value<float> (is);
-}
+    bool int_multiply_overflow (unsigned int a, unsigned int b,
+                                unsigned int *r)
+    {
+      return octave_ui_multiply_overflow_wrapper (a, b, r);
+    }
 
-void
-octave_write_double (std::ostream& os, double d)
-{
-  if (lo_ieee_is_NA (d))
-    os << "NA";
-  else if (lo_ieee_isnan (d))
-    os << "NaN";
-  else if (lo_ieee_isinf (d))
-    os << (d < 0 ? "-Inf" : "Inf");
-  else
-    os << d;
-}
-
-void
-octave_write_complex (std::ostream& os, const Complex& c)
-{
-  os << '(';
-  octave_write_double (os, real (c));
-  os << ',';
-  octave_write_double (os, imag (c));
-  os << ')';
-}
+    bool int_multiply_overflow (unsigned long int a, unsigned long int b,
+                          unsigned long int *r)
+    {
+      return octave_uli_multiply_overflow_wrapper (a, b, r);
+    }
 
-void
-octave_write_float (std::ostream& os, float d)
-{
-  if (lo_ieee_is_NA (d))
-    os << "NA";
-  else if (lo_ieee_isnan (d))
-    os << "NaN";
-  else if (lo_ieee_isinf (d))
-    os << (d < 0 ? "-Inf" : "Inf");
-  else
-    os << d;
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+    bool int_multiply_overflow (unsigned long long int a,
+                          unsigned long long int b,
+                          unsigned long long int *r)
+    {
+      return octave_ulli_multiply_overflow_wrapper (a, b, r);
+    }
+#endif
+
+  }
 }
-
-void
-octave_write_float_complex (std::ostream& os, const FloatComplex& c)
-{
-  os << '(';
-  octave_write_float (os, real (c));
-  os << ',';
-  octave_write_float (os, imag (c));
-  os << ')';
-}
--- a/liboctave/util/lo-utils.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/lo-utils.h	Sun May 16 09:44:35 2021 +0200
@@ -66,15 +66,26 @@
 }
 
 extern OCTAVE_API bool xis_int_or_inf_or_nan (double x);
-extern OCTAVE_API bool xis_one_or_zero (double x);
-extern OCTAVE_API bool xis_zero (double x);
+
+template <typename T>
+bool
+xis_one_or_zero (const T& x)
+{
+  return x == T (0) || x == T (1);
+}
+
+template <typename T>
+bool
+xis_zero (const T& x)
+{
+  return x == T (0);
+}
+
 extern OCTAVE_API bool xtoo_large_for_float (double x);
 
 extern OCTAVE_API bool xtoo_large_for_float (const Complex&  x);
 
 extern OCTAVE_API bool xis_int_or_inf_or_nan (float x);
-extern OCTAVE_API bool xis_one_or_zero (float x);
-extern OCTAVE_API bool xis_zero (float x);
 extern OCTAVE_API bool xtoo_large_for_float (float x);
 
 extern OCTAVE_API char * strsave (const char *);
@@ -85,55 +96,103 @@
 extern OCTAVE_API std::string octave_fgets (std::FILE *, bool& eof);
 extern OCTAVE_API std::string octave_fgetl (std::FILE *, bool& eof);
 
-template <typename T>
-T
-octave_read_value (std::istream& is)
+namespace octave
 {
-  T retval;
-  is >> retval;
-  return retval;
+  template <typename T> OCTAVE_API T read_value (std::istream& is);
+
+  template <> OCTAVE_API double read_value (std::istream& is);
+  template <> OCTAVE_API Complex read_value (std::istream& is);
+  template <> OCTAVE_API float read_value (std::istream& is);
+  template <> OCTAVE_API FloatComplex read_value (std::istream& is);
+
+  template <typename T> OCTAVE_API void write_value (std::ostream& os, const T& value);
+
+  template <> OCTAVE_API void write_value (std::ostream& os, const double& value);
+  template <> OCTAVE_API void write_value (std::ostream& os, const Complex& value);
+  template <> OCTAVE_API void write_value (std::ostream& os, const float& value);
+  template <> OCTAVE_API void write_value (std::ostream& os, const FloatComplex& value);
+
+  namespace math
+  {
+    extern OCTAVE_API bool int_multiply_overflow (int a, int b, int *r);
+
+    extern OCTAVE_API bool
+    int_multiply_overflow (long int a, long int b, long int *r);
+
+#if defined (OCTAVE_HAVE_LONG_LONG_INT)
+    extern OCTAVE_API bool
+    int_multiply_overflow (long long int a, long long int b, long long int *r);
+#endif
+
+    extern OCTAVE_API bool
+    int_multiply_overflow (unsigned int a, unsigned int b, unsigned int *r);
+
+    extern OCTAVE_API bool
+    int_multiply_overflow (unsigned long int a, unsigned long int b,
+                           unsigned long int *r);
+
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+    extern OCTAVE_API bool
+    int_multiply_overflow (unsigned long long int a, unsigned long long int b,
+                           unsigned long long int *r);
+#endif
+  }
 }
 
-template <> OCTAVE_API double octave_read_value (std::istream& is);
-template <> OCTAVE_API Complex octave_read_value (std::istream& is);
-template <> OCTAVE_API float octave_read_value (std::istream& is);
-template <> OCTAVE_API FloatComplex octave_read_value (std::istream& is);
-
-// The next four functions are provided for backward compatibility.
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline double
 octave_read_double (std::istream& is)
 {
-  return octave_read_value<double> (is);
+  return octave::read_value<double> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline Complex
 octave_read_complex (std::istream& is)
 {
-  return octave_read_value<Complex> (is);
+  return octave::read_value<Complex> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline float
 octave_read_float (std::istream& is)
 {
-  return octave_read_value<float> (is);
+  return octave::read_value<float> (is);
 }
 
+OCTAVE_DEPRECATED (7, "use 'octave::read_value<T>' instead")
 inline FloatComplex
 octave_read_float_complex (std::istream& is)
 {
-  return octave_read_value<FloatComplex> (is);
+  return octave::read_value<FloatComplex> (is);
+}
+
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_double (std::ostream& os, double value)
+{
+  octave::write_value<double> (os, value);
 }
 
-extern OCTAVE_API void
-octave_write_double (std::ostream& os, double dval);
-
-extern OCTAVE_API void
-octave_write_complex (std::ostream& os, const Complex& cval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_complex (std::ostream& os, const Complex& value)
+{
+  octave::write_value<Complex> (os, value);
+}
 
-extern OCTAVE_API void
-octave_write_float (std::ostream& os, float dval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_float (std::ostream& os, float value)
+{
+  octave::write_value<float> (os, value);
+}
 
-extern OCTAVE_API void
-octave_write_float_complex (std::ostream& os, const FloatComplex& cval);
+OCTAVE_DEPRECATED (7, "use 'octave::write_value<T>' instead")
+inline void
+octave_write_float_complex (std::ostream& os, const FloatComplex& value)
+{
+  octave::write_value<FloatComplex> (os, value);
+}
 
 #endif
--- a/liboctave/util/oct-atomic.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-atomic.h	Sun May 16 09:44:35 2021 +0200
@@ -32,9 +32,11 @@
 extern "C" {
 #endif
 
-  extern octave_idx_type octave_atomic_increment (octave_idx_type *x);
+  extern OCTAVE_API octave_idx_type
+  octave_atomic_increment (octave_idx_type *x);
 
-  extern octave_idx_type octave_atomic_decrement (octave_idx_type *x);
+  extern OCTAVE_API octave_idx_type
+  octave_atomic_decrement (octave_idx_type *x);
 
 #if defined __cplusplus
 }
--- a/liboctave/util/oct-base64.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-base64.cc	Sun May 16 09:44:35 2021 +0200
@@ -94,4 +94,31 @@
 
     return retval;
   }
+
+  intNDArray<octave_uint8>
+  base64_decode_bytes (const std::string& str)
+  {
+    intNDArray<octave_uint8> retval;
+
+    char *out;
+    std::size_t outlen;
+
+    bool ok
+      = octave_base64_decode_alloc_wrapper (str.data (), str.length (),
+                                            &out, &outlen);
+
+    if (! ok)
+      (*current_liboctave_error_handler)
+        ("base64_decode: input was not valid base64");
+
+    if (! out)
+      (*current_liboctave_error_handler)
+        ("base64_decode: memory allocation error");
+
+    retval.resize (dim_vector (1, outlen));
+    std::copy (out, out + outlen, retval.fortran_vec ());
+    ::free (out);
+
+    return retval;
+  }
 }
--- a/liboctave/util/oct-base64.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-base64.h	Sun May 16 09:44:35 2021 +0200
@@ -30,6 +30,8 @@
 
 #include <string>
 
+#include "intNDArray.h"
+
 template <typename T> class Array;
 
 namespace octave
@@ -39,6 +41,9 @@
 
   extern OCTAVE_API Array<double>
   base64_decode (const std::string& str);
+
+  extern OCTAVE_API intNDArray<octave_uint8>
+  base64_decode_bytes (const std::string& str);
 }
 
 #endif
--- a/liboctave/util/oct-glob.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-glob.cc	Sun May 16 09:44:35 2021 +0200
@@ -33,9 +33,18 @@
 #include "glob-wrappers.h"
 
 #include "oct-glob.h"
+#include "file-ops.h"
 #include "file-stat.h"
 #include "unwind-prot.h"
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <windows.h>
+#  include <shlwapi.h>
+#  include <wchar.h>
+
+#  include "lo-sysdep.h"
+#endif
+
 // These functions are defined here and not in glob_match.cc so that we
 // can include the glob.h file from gnulib, which defines glob to
 // be rpl_glob.  If we include glob.h in glob_match.cc, then it
@@ -78,11 +87,10 @@
 
       int k = 0;
 
-      unwind_protect frame;
-
       void *glob_info = octave_create_glob_info_struct ();
 
-      frame.add_fcn (octave_destroy_glob_info_struct, glob_info);
+      unwind_action cleanup_glob_info_struct
+        ([=] () { octave_destroy_glob_info_struct (glob_info); });
 
       for (int i = 0; i < npat; i++)
         {
@@ -143,6 +151,56 @@
       return retval.sort ();
     }
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+
+    static void
+    find_files (std::list<std::string>& dirlist, const std::string& dir,
+                const std::string& pat, std::string& file)
+    {
+      // remove leading file separators
+      while (file.length () > 1 && sys::file_ops::is_dir_sep (file[0]))
+        file = file.substr (1, std::string::npos);
+
+      // find first file in directory that matches pattern in PAT
+      std::wstring wpat = u8_to_wstring (sys::file_ops::concat (dir, pat));
+      _WIN32_FIND_DATAW ffd;
+      HANDLE h_find = FindFirstFileW (wpat.c_str (), &ffd);
+      // ignore any error
+      if (h_find == INVALID_HANDLE_VALUE)
+        return;
+
+      unwind_action close_h_find ([=] () { FindClose (h_find); });
+
+      // find all files that match pattern
+      do
+        {
+          std::string found_dir = u8_from_wstring (ffd.cFileName);
+
+          if (file.empty ())
+            {
+              if (found_dir.compare (".") && found_dir.compare (".."))
+                dirlist.push_back (sys::file_ops::concat (dir, found_dir));
+            }
+          else
+            {
+              // get next component of path (or file name)
+              std::size_t sep_pos
+                = file.find_first_of (sys::file_ops::dir_sep_chars ());
+              std::string pat_str = file.substr (0, sep_pos);
+              std::string file_str = (sep_pos != std::string::npos
+                                      && file.length () > sep_pos+1)
+                                     ? file.substr (sep_pos+1) : "";
+
+              // call this function recursively with next path component in PAT
+              find_files (dirlist, sys::file_ops::concat (dir, found_dir),
+                          pat_str, file_str);
+            }
+        }
+      while (FindNextFileW (h_find, &ffd) != 0);
+    }
+
+#endif
+
     // Glob like Windows "dir".  Treat only * and ? as wildcards,
     // and "*.*" matches filenames even if they do not contain ".".
     string_vector
@@ -152,13 +210,69 @@
 
       int npat = pat.numel ();
 
-      int k = 0;
+#if defined (OCTAVE_USE_WINDOWS_API)
+
+      std::list<std::string> dirlist;
+
+      for (int i = 0; i < npat; i++)
+        {
+          std::string xpat = pat(i);
+          if (xpat.empty ())
+            continue;
+
+          // separate component until first dir separator
+          std::size_t sep_pos
+            = xpat.find_first_of (sys::file_ops::dir_sep_chars ());
+          std::string file = (sep_pos != std::string::npos
+                              && xpat.length () > sep_pos+1)
+                             ? xpat.substr (sep_pos+1) : "";
+          xpat = xpat.substr (0, sep_pos);
+
+          std::string dir = "";
+
+          if ((sep_pos == 2 || xpat.length () == 2) && xpat[1] == ':')
+            {
+              // include disc root with first file or folder
+
+              // remove leading file separators in path without disc root
+              while (file.length () > 1 && sys::file_ops::is_dir_sep (file[0]))
+                file = file.substr (1, std::string::npos);
 
-      unwind_protect frame;
+              sep_pos = file.find_first_of (sys::file_ops::dir_sep_chars ());
+              dir = xpat;
+              xpat = file.substr (0, sep_pos);
+              file = (sep_pos != std::string::npos
+                      && file.length () > sep_pos+1)
+                     ? file.substr (sep_pos+1) : "";
+              if (xpat.empty ())
+                {
+                  // don't glob if input is only disc root
+                  std::wstring wpat = u8_to_wstring (pat(i));
+                  if (PathFileExistsW (wpat.c_str ()))
+                    {
+                      if (sys::file_ops::is_dir_sep (pat(i).back ()))
+                        dirlist.push_back (dir +
+                                           sys::file_ops::dir_sep_char ());
+                      else
+                        dirlist.push_back (dir);
+                    }
+                  continue;
+                }
+            }
+
+          find_files (dirlist, dir, xpat, file);
+        }
+
+      retval = string_vector (dirlist);
+
+#else
+
+      int k = 0;
 
       void *glob_info = octave_create_glob_info_struct ();
 
-      frame.add_fcn (octave_destroy_glob_info_struct, glob_info);
+      unwind_action cleanup_glob_info_struct
+        ([=] () { octave_destroy_glob_info_struct (glob_info); });
 
       for (int i = 0; i < npat; i++)
         {
@@ -171,12 +285,12 @@
 
               for (std::size_t j = 0; j < xpat.length (); j++)
                 {
-#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
-     && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
+#  if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
+       && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
                   if (xpat[j] == '\\')
                     escaped += '/';
                   else
-#endif
+#  endif
                     {
                       if (xpat[j] == ']' || xpat[j] == '[')
                         escaped += '\\';
@@ -221,12 +335,12 @@
 
                           for (std::size_t m = 0; m < tmp.length (); m++)
                             {
-#if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
+#  if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
      && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
                               if (tmp[m] == '/')
                                 unescaped += '\\';
                               else
-#endif
+#  endif
                                 {
                                   if (tmp[m] == '\\'
                                       && ++m == tmp.length ())
@@ -244,6 +358,7 @@
                 }
             }
         }
+#endif
 
       return retval.sort ();
     }
--- a/liboctave/util/oct-glob.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-glob.h	Sun May 16 09:44:35 2021 +0200
@@ -34,14 +34,14 @@
 {
   namespace sys
   {
-    extern bool
+    extern OCTAVE_API bool
     fnmatch (const string_vector& pat, const std::string& str,
              int fnmatch_flags);
 
-    extern string_vector
+    extern OCTAVE_API string_vector
     glob (const string_vector&);
 
-    extern string_vector
+    extern OCTAVE_API string_vector
     windows_glob (const string_vector&);
   }
 }
--- a/liboctave/util/oct-inttypes.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-inttypes.cc	Sun May 16 09:44:35 2021 +0200
@@ -793,7 +793,7 @@
 }
 
 #define INSTANTIATE_INTTYPE(T)                                          \
-  template class OCTAVE_API octave_int<T>;                              \
+  template class octave_int<T>;                                         \
                                                                         \
   template OCTAVE_API octave_int<T>                                     \
   pow (const octave_int<T>&, const octave_int<T>&);                     \
--- a/liboctave/util/oct-inttypes.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-inttypes.h	Sun May 16 09:44:35 2021 +0200
@@ -427,7 +427,7 @@
   // Convert a real number (check NaN and non-int).
 
   template <typename S>
-  static T convert_real (const S& value);
+  static OCTAVE_API T convert_real (const S& value);
 };
 
 // Saturated (homogeneous) integer arithmetics.  The signed and
@@ -791,6 +791,7 @@
 
 template <typename T>
 class
+OCTAVE_API
 octave_int : public octave_int_base<T>
 {
 public:
@@ -906,7 +907,7 @@
 
   static int byte_size (void) { return sizeof (T); }
 
-  static const char * type_name ();
+  static const OCTAVE_API char * type_name ();
 
   // The following are provided for convenience.
   static const octave_int zero, one;
@@ -1330,4 +1331,29 @@
   return octave_int<T> (xv <= yv ? xv : yv);
 }
 
+// Ints are handled by converting to octave_int type.
+
+#define OCTAVE_INT_IDX_TYPE_BIN_OP(OP)                          \
+  template <typename T>                                         \
+  inline octave_int<T>                                          \
+  operator OP (const octave_int<T>& x, octave_idx_type y)       \
+  {                                                             \
+    return x OP octave_int<T> (y);                              \
+  }                                                             \
+                                                                \
+  template <typename T>                                         \
+  inline octave_int<T>                                          \
+  operator OP (octave_idx_type x, const octave_int<T>& y)       \
+  {                                                             \
+    return octave_int<T> (x) OP y;                              \
+  }
+
+OCTAVE_INT_IDX_TYPE_BIN_OP (+)
+OCTAVE_INT_IDX_TYPE_BIN_OP (-)
+OCTAVE_INT_IDX_TYPE_BIN_OP (*)
+OCTAVE_INT_IDX_TYPE_BIN_OP (/)
+
+#undef OCTAVE_INT_IDX_TYPE_BIN_OP
+
+
 #endif
--- a/liboctave/util/oct-mutex.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-mutex.h	Sun May 16 09:44:35 2021 +0200
@@ -28,7 +28,7 @@
 
 #include "octave-config.h"
 
-#include "oct-refcount.h"
+#include <memory>
 
 namespace octave
 {
@@ -40,7 +40,7 @@
   public:
     friend class mutex;
 
-    base_mutex (void) : m_count (1) { }
+    base_mutex (void) = default;
 
     virtual ~base_mutex (void) = default;
 
@@ -49,9 +49,6 @@
     virtual void unlock (void);
 
     virtual bool try_lock (void);
-
-  private:
-    refcount<octave_idx_type> m_count;
   };
 
   class
@@ -61,31 +58,11 @@
   public:
     mutex (void);
 
-    mutex (const mutex& m)
-      : m_rep (m.m_rep)
-    {
-      m_rep->m_count++;
-    }
-
-    ~mutex (void)
-    {
-      if (--m_rep->m_count == 0)
-        delete m_rep;
-    }
+    mutex (const mutex& m) = default;
 
-    mutex& operator = (const mutex& m)
-    {
-      if (m_rep != m.m_rep)
-        {
-          if (--m_rep->m_count == 0)
-            delete m_rep;
+    ~mutex (void) = default;
 
-          m_rep = m.m_rep;
-          m_rep->m_count++;
-        }
-
-      return *this;
-    }
+    mutex& operator = (const mutex& m) = default;
 
     void lock (void)
     {
@@ -103,7 +80,7 @@
     }
 
   protected:
-    base_mutex *m_rep;
+    std::shared_ptr<base_mutex> m_rep;
   };
 
   class
--- a/liboctave/util/oct-shlib.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-shlib.h	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,6 @@
 namespace octave
 {
   class
-  OCTAVE_API
   dynamic_library
   {
   public: // FIXME: make this class private?
@@ -57,6 +56,7 @@
 
     protected:
 
+      OCTAVE_API
       dynlib_rep (const std::string& f);
 
     public:
@@ -73,12 +73,12 @@
                              const name_mangler& = name_mangler ())
       { return nullptr; }
 
-      bool is_out_of_date (void) const;
+      OCTAVE_API bool is_out_of_date (void) const;
 
       // This method will be overridden conditionally.
-      static dynlib_rep * new_instance (const std::string& f);
+      static OCTAVE_API dynlib_rep * new_instance (const std::string& f);
 
-      static dynlib_rep * get_instance (const std::string& f, bool fake);
+      static OCTAVE_API dynlib_rep * get_instance (const std::string& f, bool fake);
 
       sys::time time_loaded (void) const
       { return m_time_loaded; }
@@ -88,11 +88,11 @@
 
       std::size_t num_fcn_names (void) const { return m_fcn_names.size (); }
 
-      std::list<std::string> function_names (void) const;
+      OCTAVE_API std::list<std::string> function_names (void) const;
 
-      void add_fcn_name (const std::string&);
+      OCTAVE_API void add_fcn_name (const std::string&);
 
-      bool remove_fcn_name (const std::string&);
+      OCTAVE_API bool remove_fcn_name (const std::string&);
 
       void clear_fcn_names (void) { m_fcn_names.clear (); }
 
@@ -102,9 +102,9 @@
 
     protected:
 
-      void fake_reload (void);
+      OCTAVE_API void fake_reload (void);
 
-      static std::map<std::string, dynlib_rep *> s_instances;
+      static OCTAVE_API std::map<std::string, dynlib_rep *> s_instances;
 
       // Set of hooked function names.
       typedef std::map<std::string, std::size_t>::iterator fcn_names_iterator;
@@ -118,7 +118,7 @@
 
   private:
 
-    static dynlib_rep s_nil_rep;
+    static OCTAVE_API dynlib_rep s_nil_rep;
 
   public:
 
--- a/liboctave/util/oct-sort.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-sort.cc	Sun May 16 09:44:35 2021 +0200
@@ -109,7 +109,6 @@
 
 #include <cassert>
 #include <algorithm>
-#include <functional>
 #include <cstring>
 #include <stack>
 
@@ -125,7 +124,7 @@
 { }
 
 template <typename T>
-octave_sort<T>::octave_sort (compare_fcn_type comp)
+octave_sort<T>::octave_sort (const compare_fcn_type& comp)
   : m_compare (comp), m_ms (nullptr)
 { }
 
@@ -144,7 +143,7 @@
   else if (mode == DESCENDING)
     m_compare = descending_compare;
   else
-    m_compare = nullptr;
+    m_compare = compare_fcn_type ();
 }
 
 template <typename T>
@@ -1513,16 +1512,20 @@
 }
 
 template <typename T>
+using compare_fcn_ptr = bool (*) (typename ref_param<T>::type,
+                                  typename ref_param<T>::type);
+
+template <typename T>
 void
 octave_sort<T>::sort (T *data, octave_idx_type nel)
 {
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     sort (data, nel, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       sort (data, nel, std::greater<T> ());
     else
 #endif
@@ -1535,12 +1538,12 @@
 octave_sort<T>::sort (T *data, octave_idx_type *idx, octave_idx_type nel)
 {
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     sort (data, idx, nel, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       sort (data, idx, nel, std::greater<T> ());
     else
 #endif
@@ -1575,12 +1578,12 @@
 {
   bool retval = false;
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     retval = issorted (data, nel, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       retval = issorted (data, nel, std::greater<T> ());
     else
 #endif
@@ -1662,12 +1665,12 @@
                            octave_idx_type rows, octave_idx_type cols)
 {
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     sort_rows (data, idx, rows, cols, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       sort_rows (data, idx, rows, cols, std::greater<T> ());
     else
 #endif
@@ -1739,14 +1742,13 @@
                                 octave_idx_type cols)
 {
   bool retval = false;
-
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     retval = is_sorted_rows (data, rows, cols, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       retval = is_sorted_rows (data, rows, cols, std::greater<T> ());
     else
 #endif
@@ -1785,19 +1787,18 @@
                         const T& value)
 {
   octave_idx_type retval = 0;
-
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     retval = lookup (data, nel, value, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       retval = lookup (data, nel, value, std::greater<T> ());
     else
 #endif
       if (m_compare)
-        retval = lookup (data, nel, value, std::ptr_fun (m_compare));
+        retval = lookup (data, nel, value, m_compare);
 
   return retval;
 }
@@ -1823,17 +1824,17 @@
                         octave_idx_type *idx)
 {
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     lookup (data, nel, values, nvalues, idx, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       lookup (data, nel, values, nvalues, idx, std::greater<T> ());
     else
 #endif
       if (m_compare)
-        lookup (data, nel, values, nvalues, idx, std::ptr_fun (m_compare));
+        lookup (data, nel, values, nvalues, idx, m_compare);
 }
 
 template <typename T>
@@ -1898,18 +1899,17 @@
                                octave_idx_type *idx, bool rev)
 {
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     lookup_sorted (data, nel, values, nvalues, idx, rev, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       lookup_sorted (data, nel, values, nvalues, idx, rev, std::greater<T> ());
     else
 #endif
       if (m_compare)
-        lookup_sorted (data, nel, values, nvalues, idx, rev,
-                       std::ptr_fun (m_compare));
+        lookup_sorted (data, nel, values, nvalues, idx, rev, m_compare);
 }
 
 template <typename T>
@@ -1946,18 +1946,19 @@
 {
   if (up < 0)
     up = lo + 1;
+
 #if defined (INLINE_ASCENDING_SORT)
-  if (m_compare == ascending_compare)
+  if (*m_compare.template target<compare_fcn_ptr<T>> () == ascending_compare)
     nth_element (data, nel, lo, up, std::less<T> ());
   else
 #endif
 #if defined (INLINE_DESCENDING_SORT)
-    if (m_compare == descending_compare)
+    if (*m_compare.template target<compare_fcn_ptr<T>> () == descending_compare)
       nth_element (data, nel, lo, up, std::greater<T> ());
     else
 #endif
       if (m_compare)
-        nth_element (data, nel, lo, up, std::ptr_fun (m_compare));
+        nth_element (data, nel, lo, up, m_compare);
 }
 
 template <typename T>
--- a/liboctave/util/oct-sort.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-sort.h	Sun May 16 09:44:35 2021 +0200
@@ -87,6 +87,8 @@
 #if ! defined (octave_oct_sort_h)
 #define octave_oct_sort_h 1
 
+#include <functional>
+
 #include "octave-config.h"
 
 #include "lo-traits.h"
@@ -100,12 +102,12 @@
 {
 public:
 
-  typedef bool (*compare_fcn_type) (typename ref_param<T>::type,
-                                    typename ref_param<T>::type);
+  typedef std::function<bool (typename ref_param<T>::type,
+                              typename ref_param<T>::type)> compare_fcn_type;
 
   octave_sort (void);
 
-  octave_sort (compare_fcn_type);
+  octave_sort (const compare_fcn_type&);
 
   // No copying!
 
@@ -115,7 +117,7 @@
 
   ~octave_sort (void);
 
-  void set_compare (compare_fcn_type comp) { m_compare = comp; }
+  void set_compare (const compare_fcn_type& comp) { m_compare = comp; }
 
   void set_compare (sortmode mode);
 
--- a/liboctave/util/oct-sparse.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-sparse.h	Sun May 16 09:44:35 2021 +0200
@@ -28,6 +28,13 @@
 
 #include "octave-config.h"
 
+#include <limits>
+
+#if defined (HAVE_CHOLMOD)
+#  include "dSparse.h"
+#  include "CSparse.h"
+#endif
+
 #if defined (HAVE_SUITESPARSE_AMD_H)
 #  include <suitesparse/amd.h>
 #elif defined (HAVE_UFSPARSE_AMD_H)
@@ -88,6 +95,12 @@
 #  include <umfpack.h>
 #endif
 
+#if defined (HAVE_SUITESPARSE_SUITESPARSEQR_HPP)
+#  include <suitesparse/SuiteSparseQR.hpp>
+#elif defined (HAVE_SUITESPARSEQR_HPP)
+#  include <SuiteSparseQR.hpp>
+#endif
+
 // Cope with new SuiteSparse versions
 
 #if defined (SUITESPARSE_VERSION)
@@ -161,7 +174,8 @@
 
 #if (defined (HAVE_AMD) || defined (HAVE_CCOLAMD)               \
      || defined (HAVE_CHOLMOD) || defined (HAVE_COLAMD)         \
-     || defined (HAVE_CXSPARSE) || defined (HAVE_UMFPACK))
+     || defined (HAVE_CXSPARSE) || defined (HAVE_SPQR)          \
+     || defined (HAVE_UMFPACK))
 
 namespace octave
 {
@@ -171,17 +185,39 @@
   typedef int suitesparse_integer;
 #  endif
 
-  extern suitesparse_integer *
+  extern OCTAVE_API suitesparse_integer *
   to_suitesparse_intptr (octave_idx_type *i);
 
-  extern const suitesparse_integer *
+  extern const OCTAVE_API suitesparse_integer *
   to_suitesparse_intptr (const octave_idx_type *i);
 
-  extern octave_idx_type*
+  extern OCTAVE_API octave_idx_type*
   to_octave_idx_type_ptr (suitesparse_integer *i);
 
-  extern const octave_idx_type*
+  extern const OCTAVE_API octave_idx_type*
   to_octave_idx_type_ptr (const suitesparse_integer *i);
+
+  inline octave_idx_type
+  from_suitesparse_long (SuiteSparse_long x)
+  {
+    if (x < std::numeric_limits<octave_idx_type>::min ()
+        || x > std::numeric_limits<octave_idx_type>::max ())
+      (*current_liboctave_error_handler)
+        ("integer dimension or index out of range for Octave's indexing type");
+
+    return static_cast<octave_idx_type> (x);
+  }
+
+  inline octave_idx_type
+  from_size_t (std::size_t x)
+  {
+    // std::size_t is guaranteed to be unsigned
+    if (x > std::numeric_limits<octave_idx_type>::max ())
+      (*current_liboctave_error_handler)
+        ("integer dimension or index out of range for Octave's index type");
+
+    return static_cast<octave_idx_type> (x);
+  }
 }
 
 #endif
--- a/liboctave/util/oct-string.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-string.cc	Sun May 16 09:44:35 2021 +0200
@@ -210,28 +210,30 @@
 
 
 // Instantiations we need
-#define INSTANTIATE_OCTAVE_STRING(T)                                          \
-  template bool octave::string::strcmp<T> (const T&, const T&);               \
-  template bool octave::string::strcmp<T> (const T&,                          \
-                                           const typename T::value_type*);    \
-  template bool octave::string::strcmpi<T> (const T&, const T&);              \
-  template bool octave::string::strcmpi<T> (const T&,                         \
-                                            const typename T::value_type*);   \
-  template bool octave::string::strncmp<T> (const T&, const T&,               \
-                                            const typename T::size_type);     \
-  template bool octave::string::strncmp<T> (const T&,                         \
-                                            const typename T::value_type*,    \
-                                            const typename T::size_type);     \
-  template bool octave::string::strncmpi<T> (const T&, const T&,              \
-                                             const typename T::size_type n);  \
-  template bool octave::string::strncmpi<T> (const T&,                        \
-                                             const typename T::value_type*,   \
-                                             const typename T::size_type);
+#define INSTANTIATE_OCTAVE_STRING(T, API)                                     \
+  template API bool octave::string::strcmp<T> (const T&, const T&);           \
+  template API bool                                                           \
+  octave::string::strcmp<T> (const T&, const typename T::value_type*);        \
+  template API bool octave::string::strcmpi<T> (const T&, const T&);          \
+  template API bool                                                           \
+  octave::string::strcmpi<T> (const T&, const typename T::value_type*);       \
+  template API bool                                                           \
+  octave::string::strncmp<T> (const T&, const T&,                             \
+                              const typename T::size_type);                   \
+  template API bool                                                           \
+  octave::string::strncmp<T> (const T&, const typename T::value_type*,        \
+                              const typename T::size_type);                   \
+  template API bool                                                           \
+  octave::string::strncmpi<T> (const T&, const T&,                            \
+                               const typename T::size_type n);                \
+  template API bool                                                           \
+  octave::string::strncmpi<T> (const T&, const typename T::value_type*,       \
+                               const typename T::size_type);
 
 // We could also instantiate std::vector<char> but would it be
 // useful for anyone?
-INSTANTIATE_OCTAVE_STRING(std::string)
-INSTANTIATE_OCTAVE_STRING(Array<char>)
+INSTANTIATE_OCTAVE_STRING(std::string, OCTAVE_API)
+INSTANTIATE_OCTAVE_STRING(Array<char>, OCTAVE_API)
 
 #undef INSTANTIATE_OCTAVE_STRING
 
@@ -516,8 +518,7 @@
            who.c_str (), encoding.c_str (), std::strerror (errno));
     }
 
-  octave::unwind_protect frame;
-  frame.add_fcn (::free, static_cast<void *> (native_str));
+  octave::unwind_action free_native_str ([=] () { ::free (native_str); });
 
   std::string retval = std::string (native_str, length);
 
@@ -547,8 +548,7 @@
            who.c_str (), encoding.c_str (), std::strerror (errno));
     }
 
-  octave::unwind_protect frame;
-  frame.add_fcn (::free, static_cast<void *> (utf8_str));
+  octave::unwind_action free_utf8_str ([=] () { ::free (utf8_str); });
 
   std::string retval = std::string (reinterpret_cast<char *> (utf8_str), length);
 
@@ -594,8 +594,8 @@
                   ("%s: converting from codepage '%s' to UTF-8 failed: %s",
                    who.c_str (), fallback.c_str (), std::strerror (errno));
 
-              octave::unwind_protect frame;
-              frame.add_fcn (::free, static_cast<void *> (val_utf8));
+              octave::unwind_action free_val_utf8
+                ([=] () { ::free (val_utf8); });
 
               out_str.append (reinterpret_cast<const char *> (val_utf8),
                               lengthp);
@@ -711,5 +711,5 @@
 }
 
 // instantiate the template for float and double
-template std::string rational_approx <float> (float val, int len);
-template std::string rational_approx <double> (double val, int len);
+template OCTAVE_API std::string rational_approx <float> (float val, int len);
+template OCTAVE_API std::string rational_approx <double> (double val, int len);
--- a/liboctave/util/oct-string.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/oct-string.h	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,8 @@
     //! char array, will still return false.
 
     template <typename T>
-    bool strcmp (const T& str_a, const T& str_b);
+    OCTAVE_API bool
+    strcmp (const T& str_a, const T& str_b);
 
     //! True if string is the same as character sequence.
     //!
@@ -70,7 +71,8 @@
     //! is considered to be a row vector.
 
     template <typename T>
-    bool strcmp (const T& str_a, const typename T::value_type *str_b);
+    OCTAVE_API bool
+    strcmp (const T& str_a, const typename T::value_type *str_b);
 
     //! True if strings are the same, ignoring case.
     //!
@@ -81,7 +83,8 @@
     //! char array, will still return false.
 
     template <typename T>
-    bool strcmpi (const T& str_a, const T& str_b);
+    OCTAVE_API bool
+    strcmpi (const T& str_a, const T& str_b);
 
     //! True if string is the same as character sequence, ignoring case.
     //!
@@ -91,7 +94,8 @@
     //! is considered to be a row vector.
 
     template <typename T>
-    bool strcmpi (const T& str_a, const typename T::value_type *str_b);
+    OCTAVE_API bool
+    strcmpi (const T& str_a, const typename T::value_type *str_b);
 
     //! True if the first N characters are the same.
     //!
@@ -102,13 +106,15 @@
     //! a column vector of the same still return true.
 
     template <typename T>
-    bool strncmp (const T& str_a, const T& str_b,
-                  const typename T::size_type n);
+    OCTAVE_API bool
+    strncmp (const T& str_a, const T& str_b,
+             const typename T::size_type n);
 
     //! True if the first N characters are the same.
     template <typename T>
-    bool strncmp (const T& str_a, const typename T::value_type *str_b,
-                  const typename T::size_type n);
+    OCTAVE_API bool
+    strncmp (const T& str_a, const typename T::value_type *str_b,
+             const typename T::size_type n);
 
     //! True if the first N characters are the same, ignoring case.
     //!
@@ -119,13 +125,15 @@
     //! a column vector of the same still return true.
 
     template <typename T>
-    bool strncmpi (const T& str_a, const T& str_b,
-                   const typename T::size_type n);
+    OCTAVE_API bool
+    strncmpi (const T& str_a, const T& str_b,
+              const typename T::size_type n);
 
     //! True if the first N characters are the same, ignoring case.
     template <typename T>
-    bool strncmpi (const T& str_a, const typename T::value_type *str_b,
-                   const typename T::size_type n);
+    OCTAVE_API bool
+    strncmpi (const T& str_a, const typename T::value_type *str_b,
+              const typename T::size_type n);
 
     extern OCTAVE_API Complex
     str2double (const std::string& str_arg);
--- a/liboctave/util/quit.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/quit.h	Sun May 16 09:44:35 2021 +0200
@@ -89,7 +89,7 @@
             && a.column () == b.column ());
   }
 
-  class execution_exception : public std::runtime_error
+  class OCTAVE_API execution_exception : public std::runtime_error
   {
   public:
 
@@ -222,26 +222,26 @@
     0: no interrupt pending
   < 0: handling interrupt
 */
-OCTAVE_API extern sig_atomic_t octave_interrupt_state;
+extern OCTAVE_API sig_atomic_t octave_interrupt_state;
 
 OCTAVE_DEPRECATED (6, "'octave_exception_state' is an obsolete internal variable; any uses should be removed")
-OCTAVE_API extern sig_atomic_t octave_exception_state;
+extern OCTAVE_API sig_atomic_t octave_exception_state;
 
-OCTAVE_API extern volatile sig_atomic_t octave_signal_caught;
+extern OCTAVE_API volatile sig_atomic_t octave_signal_caught;
 
-OCTAVE_API extern void octave_handle_signal (void);
+extern OCTAVE_API void octave_handle_signal (void);
 
 OCTAVE_DEPRECATED (6, "use 'throw octave::interrupt_exception' instead")
-OCTAVE_NORETURN OCTAVE_API extern void octave_throw_interrupt_exception (void);
+OCTAVE_NORETURN extern OCTAVE_API void octave_throw_interrupt_exception (void);
 
 OCTAVE_DEPRECATED (6, "use 'throw octave::execution_exception' instead")
-OCTAVE_NORETURN OCTAVE_API extern void octave_throw_execution_exception (void);
+OCTAVE_NORETURN extern OCTAVE_API void octave_throw_execution_exception (void);
 
 OCTAVE_DEPRECATED (6, "use 'throw std::bad_alloc' instead")
-OCTAVE_NORETURN OCTAVE_API extern void octave_throw_bad_alloc (void);
+OCTAVE_NORETURN extern OCTAVE_API void octave_throw_bad_alloc (void);
 
 OCTAVE_DEPRECATED (6, "use 'throw' instead")
-OCTAVE_API extern void octave_rethrow_exception (void);
+extern OCTAVE_API void octave_rethrow_exception (void);
 
 #if defined (__cplusplus)
 
@@ -252,7 +252,7 @@
       octave_signal_caught = 0;
       octave_handle_signal ();
     }
-};
+}
 
 #define OCTAVE_QUIT octave_quit ()
 
--- a/liboctave/util/unwind-prot.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/unwind-prot.cc	Sun May 16 09:44:35 2021 +0200
@@ -40,4 +40,13 @@
        "It is a bug in Octave for this to happen.  "
        "Please help improve Octave by reporting it.");
   }
+
+  void
+  unwind_action_safe::warn_unhandled_exception (void) const
+  {
+    (*current_liboctave_warning_handler)
+      ("unhandled exception in unwind_action_safe handler.  "
+       "It is a bug in Octave for this to happen.  "
+       "Please help improve Octave by reporting it.");
+  }
 }
--- a/liboctave/util/unwind-prot.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/unwind-prot.h	Sun May 16 09:44:35 2021 +0200
@@ -147,7 +147,7 @@
   //     int val = 42;
   //
   //     // template parameters, std::bind and std::function provide
-  //     // flexibility in calling forms:
+  //     // flexibility in calling forms (function pointer or lambda):
   //
   //     unwind_action act1 (fcn, val);
   //     unwind_action act2 ([val] (void) { fcn (val); });
@@ -162,10 +162,15 @@
   // called immediately after the object is constructed instead of at
   // the end of the current scope.
 
-  class unwind_action
+  class OCTAVE_API unwind_action
   {
   public:
 
+    unwind_action (void) : m_fcn () { }
+
+    // FIXME: Do we need to apply std::forward to the arguments to
+    // std::bind here?
+
     template <typename F, typename... Args>
     unwind_action (F&& fcn, Args&&... args)
       : m_fcn (std::bind (fcn, args...))
@@ -177,7 +182,95 @@
 
     unwind_action& operator = (const unwind_action&) = delete;
 
-    ~unwind_action (void) { m_fcn (); }
+    ~unwind_action (void) { run (); }
+
+    // FIXME: Do we need to apply std::forward to the arguments to
+    // std::bind here?
+
+    template <typename F, typename... Args>
+    void set (F&& fcn, Args&&... args)
+    {
+      m_fcn = std::bind (fcn, args...);
+    }
+
+    void set (void) { m_fcn = nullptr; }
+
+    // Alias for set() which is clearer about programmer intention.
+    void discard (void) { set (); }
+
+    void run (void)
+    {
+      if (m_fcn)
+        m_fcn ();
+
+      // Invalidate so action won't run again when object is deleted.
+      discard ();
+    }
+
+  private:
+
+    std::function<void (void)> m_fcn;
+  };
+
+  // Like unwind_action, but this one will guard against the possibility
+  // of seeing an exception (or interrupt) in the cleanup actions.
+  // Not that we can do much about it, but at least we won't crash.
+
+  class OCTAVE_API unwind_action_safe
+  {
+  private:
+
+    void warn_unhandled_exception (void) const;
+
+  public:
+
+    unwind_action_safe (void) : m_fcn () { }
+
+    // FIXME: Do we need to apply std::forward to the arguments to
+    // std::bind here?
+
+    template <typename F, typename... Args>
+    unwind_action_safe (F&& fcn, Args&&... args)
+      : m_fcn (std::bind (fcn, args...))
+    { }
+
+    // No copying!
+
+    unwind_action_safe (const unwind_action_safe&) = delete;
+
+    unwind_action_safe& operator = (const unwind_action_safe&) = delete;
+
+    ~unwind_action_safe (void) { run (); }
+
+    // FIXME: Do we need to apply std::forward to the arguments to
+    // std::bind here?
+
+    template <typename F, typename... Args>
+    void set (F&& fcn, Args&&... args)
+    {
+      m_fcn = std::bind (fcn, args...);
+    }
+
+    void set (void) { m_fcn = nullptr; }
+
+    // Alias for set() which is clearer about programmer intention.
+    void discard (void) { set (); }
+
+    void run (void)
+    {
+      try
+        {
+          if (m_fcn)
+            m_fcn ();
+        }
+      catch (...) // Yes, the black hole.  Remember we're in a destructor.
+        {
+          warn_unhandled_exception ();
+        }
+
+      // Invalidate so action won't run again when object is deleted.
+      discard ();
+    }
 
   private:
 
--- a/liboctave/util/url-transfer.cc	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/url-transfer.cc	Sun May 16 09:44:35 2021 +0200
@@ -71,12 +71,6 @@
   { }
 
   void
-  base_url_transfer::delete_file (const std::string& file)
-  {
-    sys::unlink (file);
-  }
-
-  void
   base_url_transfer::mget_directory (const std::string& directory,
                                      const std::string& target)
   {
@@ -101,9 +95,7 @@
 
     if (good ())
       {
-        unwind_protect_safe frame;
-
-        frame.add_fcn (reset_path, this);
+        unwind_action_safe reset_path (&base_url_transfer::cwd, this, "..");
 
         string_vector sv = list ();
 
@@ -131,17 +123,15 @@
                     m_errmsg = "__ftp_mget__: unable to open file";
                     break;
                   }
-
-                unwind_protect_safe frame2;
-
-                frame2.add_fcn (delete_file, realfile);
+                int(*unlink_fptr)(const std::string&) = sys::unlink;
+                unwind_action_safe delete_file (unlink_fptr, realfile);
 
                 get (sv(i), ofile);
 
                 ofile.close ();
 
                 if (good ())
-                  frame2.discard ();
+                  delete_file.discard ();
               }
 
             if (! good ())
@@ -169,9 +159,7 @@
 
     if (good ())
       {
-        unwind_protect_safe frame;
-
-        frame.add_fcn (reset_path, this);
+        unwind_action_safe reset_path (&base_url_transfer::cwd, this, "..");
 
         string_vector files;
         std::string msg;
@@ -378,8 +366,6 @@
 
     void perform (void)
     {
-      BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-
       m_errnum = curl_easy_perform (m_curl);
 
       if (m_errnum != CURLE_OK)
@@ -387,8 +373,6 @@
           m_ok = false;
           m_errmsg = curl_easy_strerror (m_errnum);
         }
-
-      END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
     }
 
     std::string lasterror (void) const
@@ -448,8 +432,7 @@
     {
       struct curl_slist *slist = nullptr;
 
-      unwind_protect frame;
-      frame.add_fcn (curl_slist_free_all, slist);
+      unwind_action cleanup_slist ([=] () { curl_slist_free_all (slist); });
 
       std::string cmd = "rnfr " + oldname;
       slist = curl_slist_append (slist, cmd.c_str ());
@@ -616,8 +599,7 @@
 
       struct curl_slist *slist = nullptr;
 
-      unwind_protect frame;
-      frame.add_fcn (curl_slist_free_all, slist);
+      unwind_action cleanup_slist ([=] () { curl_slist_free_all (slist); });
 
       slist = curl_slist_append (slist, "pwd");
       SETOPTR (CURLOPT_POSTQUOTE, slist);
@@ -708,9 +690,7 @@
     {
       struct curl_slist *slist = nullptr;
 
-      unwind_protect frame;
-
-      frame.add_fcn (curl_slist_free_all, slist);
+      unwind_action cleanup_slist ([=] () { curl_slist_free_all (slist); });
 
       if (param.numel () >= 2)
         {
@@ -732,13 +712,12 @@
     // path of the file as its value.
     void form_data_post (const Array<std::string>& param)
     {
-      struct curl_httppost *post = nullptr, *last = nullptr;
+      struct curl_httppost *post = nullptr;
+      struct curl_httppost *last = nullptr;
 
       SETOPT (CURLOPT_URL, m_host_or_url.c_str ());
 
-      unwind_protect frame;
-
-      frame.add_fcn (curl_formfree, post);
+      unwind_action cleanup_httppost ([=] () { curl_formfree (post); });
 
       if (param.numel () >= 2)
         {
@@ -912,9 +891,7 @@
     {
       struct curl_slist *slist = nullptr;
 
-      unwind_protect frame;
-
-      frame.add_fcn (curl_slist_free_all, slist);
+      unwind_action cleanup_slist ([=] () { curl_slist_free_all (slist); });
 
       std::string cmd = action + ' ' + file_or_dir;
 
--- a/liboctave/util/url-transfer.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/util/url-transfer.h	Sun May 16 09:44:35 2021 +0200
@@ -56,15 +56,6 @@
   OCTAVE_API
   base_url_transfer
   {
-  private:
-
-    static void delete_file (const std::string& file);
-
-    static void reset_path (base_url_transfer *curl_xfer)
-    {
-      curl_xfer->cwd ("..");
-    }
-
   public:
 
     friend class url_transfer;
--- a/liboctave/version.in.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/version.in.h	Sun May 16 09:44:35 2021 +0200
@@ -56,22 +56,22 @@
 
 #include <string>
 
-extern OCTINTERP_API std::string octave_www_statement (bool html = false);
+extern OCTAVE_API std::string octave_www_statement (bool html = false);
 
-extern OCTINTERP_API std::string octave_contrib_statement (bool html = false);
+extern OCTAVE_API std::string octave_contrib_statement (bool html = false);
 
-extern OCTINTERP_API std::string octave_bugs_statement (bool html = false);
+extern OCTAVE_API std::string octave_bugs_statement (bool html = false);
 
-extern OCTINTERP_API std::string octave_name_version_and_copyright (void);
+extern OCTAVE_API std::string octave_name_version_and_copyright (void);
 
-extern OCTINTERP_API std::string
+extern OCTAVE_API std::string
 octave_name_version_copyright_copying_and_warranty
   (bool html = false, const std::string& extra_info = "");
 
-extern OCTINTERP_API std::string
+extern OCTAVE_API std::string
 octave_name_version_copyright_copying_warranty_and_bugs
   (bool html = false, const std::string& extra_info = "");
 
-extern OCTINTERP_API std::string octave_startup_message (bool html = false);
+extern OCTAVE_API std::string octave_startup_message (bool html = false);
 
 #endif
--- a/liboctave/wrappers/areadlink-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/areadlink-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,8 +30,7 @@
 extern "C" {
 #endif
 
-extern char *
-octave_areadlink_wrapper (const char *name);
+extern OCTAVE_API char * octave_areadlink_wrapper (const char *name);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/async-system-wrapper.c	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/async-system-wrapper.c	Sun May 16 09:44:35 2021 +0200
@@ -43,6 +43,10 @@
 
 #include "async-system-wrapper.h"
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include "uniconv-wrappers.h"
+#endif
+
 pid_t
 octave_async_system_wrapper (const char *cmd)
 {
@@ -53,17 +57,15 @@
 
 #if defined (OCTAVE_USE_WINDOWS_API)
 
-  STARTUPINFO si;
+  STARTUPINFOW si;
   PROCESS_INFORMATION pi;
 
   ZeroMemory (&si, sizeof (si));
   ZeroMemory (&pi, sizeof (pi));
 
-  char *xcmd = (char *) malloc (strlen (cmd) + 1);
+  wchar_t *xcmd = u8_to_wchar (cmd);
 
-  strcpy (xcmd, cmd);
-
-  if (! CreateProcess (0, xcmd, 0, 0, FALSE, 0, 0, 0, &si, &pi))
+  if (! CreateProcessW (NULL, xcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
     retval = -1;
   else
     {
--- a/liboctave/wrappers/async-system-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/async-system-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -32,7 +32,7 @@
 extern "C" {
 #endif
 
-extern pid_t octave_async_system_wrapper (const char *cmd);
+extern OCTAVE_API pid_t octave_async_system_wrapper (const char *cmd);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/base64-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/base64-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -37,10 +37,10 @@
 extern "C" {
 #endif
 
-extern size_t
+extern OCTAVE_API size_t
 octave_base64_encode_alloc_wrapper (const char *in, size_t inlen, char **out);
 
-extern bool
+extern OCTAVE_API bool
 octave_base64_decode_alloc_wrapper (const char *in, size_t inlen,
                                     char **out, size_t *outlen);
 
--- a/liboctave/wrappers/canonicalize-file-name-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/canonicalize-file-name-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,8 @@
 extern "C" {
 #endif
 
-extern char * octave_canonicalize_file_name_wrapper (const char *name);
+extern OCTAVE_API char *
+octave_canonicalize_file_name_wrapper (const char *name);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/dirent-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/dirent-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -34,15 +34,15 @@
 extern "C" {
 #endif
 
-extern void * octave_opendir_wrapper (const char *dname);
+extern OCTAVE_API void * octave_opendir_wrapper (const char *dname);
 
-extern char * octave_readdir_wrapper (void *dir);
+extern OCTAVE_API char * octave_readdir_wrapper (void *dir);
 
-extern void octave_rewinddir_wrapper (void *dir);
+extern OCTAVE_API void octave_rewinddir_wrapper (void *dir);
 
-extern int octave_closedir_wrapper (void *dir);
+extern OCTAVE_API int octave_closedir_wrapper (void *dir);
 
-extern unsigned int octave_name_max_wrapper (void);
+extern OCTAVE_API unsigned int octave_name_max_wrapper (void);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/fcntl-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/fcntl-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -32,39 +32,40 @@
 extern "C" {
 #endif
 
-extern int octave_fcntl_wrapper (int fd, int cmd, int arg);
-
-extern int octave_open_wrapper (const char *nm, int flags, mode_t mode);
+extern OCTAVE_API int octave_fcntl_wrapper (int fd, int cmd, int arg);
 
-extern int octave_f_dupfd_wrapper (void);
+extern OCTAVE_API int
+octave_open_wrapper (const char *nm, int flags, mode_t mode);
 
-extern int octave_f_getfd_wrapper (void);
+extern OCTAVE_API int octave_f_dupfd_wrapper (void);
 
-extern int octave_f_getfl_wrapper (void);
+extern OCTAVE_API int octave_f_getfd_wrapper (void);
 
-extern int octave_f_setfd_wrapper (void);
+extern OCTAVE_API int octave_f_getfl_wrapper (void);
 
-extern int octave_f_setfl_wrapper (void);
+extern OCTAVE_API int octave_f_setfd_wrapper (void);
 
-extern int octave_o_append_wrapper (void);
+extern OCTAVE_API int octave_f_setfl_wrapper (void);
+
+extern OCTAVE_API int octave_o_append_wrapper (void);
 
-extern int octave_o_async_wrapper (void);
+extern OCTAVE_API int octave_o_async_wrapper (void);
 
-extern int octave_o_creat_wrapper (void);
+extern OCTAVE_API int octave_o_creat_wrapper (void);
 
-extern int octave_o_excl_wrapper (void);
+extern OCTAVE_API int octave_o_excl_wrapper (void);
 
-extern int octave_o_nonblock_wrapper (void);
+extern OCTAVE_API int octave_o_nonblock_wrapper (void);
 
-extern int octave_o_rdonly_wrapper (void);
+extern OCTAVE_API int octave_o_rdonly_wrapper (void);
 
-extern int octave_o_rdwr_wrapper (void);
+extern OCTAVE_API int octave_o_rdwr_wrapper (void);
 
-extern int octave_o_sync_wrapper (void);
+extern OCTAVE_API int octave_o_sync_wrapper (void);
 
-extern int octave_o_trunc_wrapper (void);
+extern OCTAVE_API int octave_o_trunc_wrapper (void);
 
-extern int octave_o_wronly_wrapper (void);
+extern OCTAVE_API int octave_o_wronly_wrapper (void);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/filepos-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/filepos-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -38,9 +38,10 @@
 extern "C" {
 #endif
 
-extern int octave_fseeko_wrapper (FILE *fp, off_t offset, int whence);
+extern OCTAVE_API int
+octave_fseeko_wrapper (FILE *fp, off_t offset, int whence);
 
-extern off_t octave_ftello_wrapper (FILE *fp);
+extern OCTAVE_API off_t octave_ftello_wrapper (FILE *fp);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/fpucw-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/fpucw-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -30,13 +30,13 @@
 extern "C" {
 #endif
 
-extern void octave_set_default_fpucw (void);
+extern OCTAVE_API void octave_set_default_fpucw (void);
 
 // unsigned int must match the actual type of fpucw_t.
 
-extern unsigned int octave_begin_long_double_rounding (void);
+extern OCTAVE_API unsigned int octave_begin_long_double_rounding (void);
 
-extern void octave_end_long_double_rounding (unsigned int);
+extern OCTAVE_API void octave_end_long_double_rounding (unsigned int);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/gen-tempname-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/gen-tempname-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern int octave_gen_tempname_wrapper (char *tmpl);
+extern OCTAVE_API int octave_gen_tempname_wrapper (char *tmpl);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/getopt-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/getopt-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -42,15 +42,15 @@
 #define octave_required_arg 1
 #define octave_optional_arg 2
 
-extern int
+extern OCTAVE_API int
 octave_getopt_long_wrapper (int argc, char **argv,
                             const char *shortopts,
                             const struct octave_getopt_options *longopts,
                             int *longind);
 
-extern char * octave_optarg_wrapper (void);
+extern OCTAVE_API char * octave_optarg_wrapper (void);
 
-extern int octave_optind_wrapper (void);
+extern OCTAVE_API int octave_optind_wrapper (void);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/glob-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/glob-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -30,34 +30,34 @@
 extern "C" {
 #endif
 
-extern void * octave_create_glob_info_struct (void);
+extern OCTAVE_API void * octave_create_glob_info_struct (void);
 
 // Does not call globfree.
-extern void octave_destroy_glob_info_struct (void *glob_info);
+extern OCTAVE_API void octave_destroy_glob_info_struct (void *glob_info);
 
 // We don't need the error function pointer that the system glob
 // function allows.
-extern int
+extern OCTAVE_API int
 octave_glob_wrapper (const char *pattern, int flags, void *glob_info);
 
-extern int octave_glob_num_matches (void *glob_info);
+extern OCTAVE_API int octave_glob_num_matches (void *glob_info);
 
-extern char ** octave_glob_match_list (void *glob_info);
+extern OCTAVE_API char ** octave_glob_match_list (void *glob_info);
 
-extern void octave_globfree_wrapper (void *glob_info);
+extern OCTAVE_API void octave_globfree_wrapper (void *glob_info);
 
-extern int octave_glob_nosort_wrapper (void);
+extern OCTAVE_API int octave_glob_nosort_wrapper (void);
 
-extern int
+extern OCTAVE_API int
 octave_fnmatch_wrapper (const char *pattern, const char *name, int flags);
 
-extern int octave_fnm_nomatch_wrapper (void);
+extern OCTAVE_API int octave_fnm_nomatch_wrapper (void);
 
-extern int octave_fnm_pathname_wrapper (void);
+extern OCTAVE_API int octave_fnm_pathname_wrapper (void);
 
-extern int octave_fnm_noescape_wrapper (void);
+extern OCTAVE_API int octave_fnm_noescape_wrapper (void);
 
-extern int octave_fnm_period_wrapper (void);
+extern OCTAVE_API int octave_fnm_period_wrapper (void);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/hash-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/hash-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -36,37 +36,37 @@
 extern "C" {
 #endif
 
-extern int octave_md2_digest_size (void);
-extern int octave_md4_digest_size (void);
-extern int octave_md5_digest_size (void);
-extern int octave_sha1_digest_size (void);
-extern int octave_sha224_digest_size (void);
-extern int octave_sha256_digest_size (void);
-extern int octave_sha384_digest_size (void);
-extern int octave_sha512_digest_size (void);
+extern OCTAVE_API int octave_md2_digest_size (void);
+extern OCTAVE_API int octave_md4_digest_size (void);
+extern OCTAVE_API int octave_md5_digest_size (void);
+extern OCTAVE_API int octave_sha1_digest_size (void);
+extern OCTAVE_API int octave_sha224_digest_size (void);
+extern OCTAVE_API int octave_sha256_digest_size (void);
+extern OCTAVE_API int octave_sha384_digest_size (void);
+extern OCTAVE_API int octave_sha512_digest_size (void);
 
-extern void *
+extern OCTAVE_API void *
 octave_md2_buffer_wrapper (const char *buf, size_t len, void *res);
 
-extern void *
+extern OCTAVE_API void *
 octave_md4_buffer_wrapper (const char *buf, size_t len, void *res);
 
-extern void *
+extern OCTAVE_API void *
 octave_md5_buffer_wrapper (const char *buf, size_t len, void *res);
 
-extern void *
+extern OCTAVE_API void *
 octave_sha1_buffer_wrapper (const char *buf, size_t len, void *res);
 
-extern void *
+extern OCTAVE_API void *
 octave_sha224_buffer_wrapper (const char *buf, size_t len, void *res);
 
-extern void *
+extern OCTAVE_API void *
 octave_sha256_buffer_wrapper (const char *buf, size_t len, void *res);
 
-extern void *
+extern OCTAVE_API void *
 octave_sha384_buffer_wrapper (const char *buf, size_t len, void *res);
 
-extern void *
+extern OCTAVE_API void *
 octave_sha512_buffer_wrapper (const char *buf, size_t len, void *res);
 
 #if defined __cplusplus
--- a/liboctave/wrappers/iconv-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/iconv-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -30,11 +30,10 @@
 extern "C" {
 #endif
 
-extern void *
+extern OCTAVE_API void *
 octave_iconv_open_wrapper (const char *tocode, const char *fromcode);
 
-extern int
-octave_iconv_close_wrapper (void *cd);
+extern OCTAVE_API int octave_iconv_close_wrapper (void *cd);
 
 #if defined __cplusplus
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/intprops-wrappers.c	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,87 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "intprops.h"
+
+#include "intprops-wrappers.h"
+
+// The *_OVERFLOW macros are provided by gnulib.  We don't include gnulib
+// headers directly in Octave's C++ source files to avoid problems that
+// may be caused by the way that gnulib overrides standard library
+// functions.
+
+#if defined (HAVE_PRAGMA_GCC_DIAGNOSTIC)
+#  pragma GCC diagnostic ignored "-Wsign-compare"
+#  pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+int
+octave_i_multiply_overflow_wrapper (int a, int b, int *r)
+{
+  return INT_MULTIPLY_WRAPV (a, b, r);
+}
+
+int
+octave_li_multiply_overflow_wrapper (long int a, long int b, long int *r)
+{
+  return INT_MULTIPLY_WRAPV (a, b, r);
+}
+
+#if defined (OCTAVE_HAVE_LONG_LONG_INT)
+int
+octave_lli_multiply_overflow_wrapper (long long int a, long long int b,
+                                      long long int *r)
+{
+  return INT_MULTIPLY_WRAPV (a, b, r);
+}
+#endif
+
+int
+octave_ui_multiply_overflow_wrapper (unsigned int a, unsigned int b,
+                                     unsigned int *r)
+{
+  return INT_MULTIPLY_WRAPV (a, b, r);
+}
+
+int
+octave_uli_multiply_overflow_wrapper (unsigned long int a, unsigned long int b,
+                                      unsigned long int *r)
+{
+  return INT_MULTIPLY_WRAPV (a, b, r);
+}
+
+#if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+int
+octave_ulli_multiply_overflow_wrapper (unsigned long long int a,
+                                       unsigned long long int b,
+                                       unsigned long long int *r)
+{
+  return INT_MULTIPLY_WRAPV (a, b, r);
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/wrappers/intprops-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,69 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2020-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if ! defined (octave_localcharset_wrapper_h)
+#define octave_localcharset_wrapper_h 1
+
+#include "octave-config.h"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+// These functions return 1 if the operation between the input arguments would
+// overflow.
+
+extern OCTAVE_API int
+octave_i_multiply_overflow_wrapper (int a, int b, int *r);
+
+extern OCTAVE_API int
+octave_li_multiply_overflow_wrapper (long int a, long int b, long int *r);
+
+#  if defined (OCTAVE_HAVE_LONG_LONG_INT)
+extern OCTAVE_API int
+octave_lli_multiply_overflow_wrapper (long long int a, long long int b,
+                                      long long int *r);
+#  endif
+
+extern OCTAVE_API int
+octave_ui_multiply_overflow_wrapper (unsigned int a, unsigned int b,
+                                     unsigned int *r);
+
+extern OCTAVE_API int
+octave_uli_multiply_overflow_wrapper (unsigned long int a, unsigned long int b,
+                                      unsigned long int *r);
+
+#  if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
+extern OCTAVE_API int
+octave_ulli_multiply_overflow_wrapper (unsigned long long int a,
+                                       unsigned long long int b,
+                                       unsigned long long int *r);
+#  endif
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
--- a/liboctave/wrappers/localcharset-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/localcharset-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern const char * octave_locale_charset_wrapper (void);
+extern OCTAVE_API const char * octave_locale_charset_wrapper (void);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/math-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/math-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -30,11 +30,9 @@
 extern "C" {
 #endif
 
-double
-octave_frexp_wrapper (double x, int *expptr);
+extern OCTAVE_API double octave_frexp_wrapper (double x, int *expptr);
 
-float
-octave_frexpf_wrapper (float x, int *expptr);
+extern OCTAVE_API float octave_frexpf_wrapper (float x, int *expptr);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/mkostemp-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/mkostemp-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern int octave_mkostemp_wrapper (char *tmpl);
+extern OCTAVE_API int octave_mkostemp_wrapper (char *tmpl);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/mkostemps-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/mkostemps-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern int octave_mkostemps_wrapper (char *tmpl, int suffixlen);
+extern OCTAVE_API int octave_mkostemps_wrapper (char *tmpl, int suffixlen);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -12,6 +12,7 @@
   %reldir%/glob-wrappers.h \
   %reldir%/hash-wrappers.h \
   %reldir%/iconv-wrappers.h \
+  %reldir%/intprops-wrappers.h \
   %reldir%/localcharset-wrapper.h \
   %reldir%/math-wrappers.h \
   %reldir%/mkostemp-wrapper.h \
@@ -54,6 +55,7 @@
   %reldir%/glob-wrappers.c \
   %reldir%/hash-wrappers.c \
   %reldir%/iconv-wrappers.c \
+  %reldir%/intprops-wrappers.c \
   %reldir%/localcharset-wrapper.c \
   %reldir%/math-wrappers.c \
   %reldir%/mkostemp-wrapper.c \
@@ -88,6 +90,8 @@
 %canon_reldir%_libwrappers_la_SOURCES = $(WRAPPERS_SRC)
 
 %canon_reldir%_libwrappers_la_CPPFLAGS = \
+  @OCTAVE_DLL_DEFS@ \
+  @EXTERNAL_DLL_DEFS@ \
   -Ilibgnu -I$(srcdir)/libgnu
 
 liboctave_liboctave_la_LIBADD += %reldir%/libwrappers.la
--- a/liboctave/wrappers/nanosleep-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/nanosleep-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 extern "C" {
 #endif
 
-extern int
+extern OCTAVE_API int
 octave_nanosleep_wrapper (const struct timespec *requested,
                           struct timespec *remaining);
 
--- a/liboctave/wrappers/nproc-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/nproc-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -37,7 +37,7 @@
   OCTAVE_NPROC_CURRENT_OVERRIDABLE
 };
 
-extern unsigned long int
+extern OCTAVE_API unsigned long int
 octave_num_processors_wrapper (enum octave_nproc_query);
 
 #if defined __cplusplus
--- a/liboctave/wrappers/octave-popen2.c	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/octave-popen2.c	Sun May 16 09:44:35 2021 +0200
@@ -44,6 +44,8 @@
 #  include <io.h>
 #  define WIN32_LEAN_AND_MEAN 1
 #  include <windows.h>
+
+#  include "uniconv-wrappers.h"
 #else
 #  include <errno.h>
 #  include <fcntl.h>
@@ -137,10 +139,15 @@
 
   command = make_command_string (cmd, args);
 
-  status = CreateProcess (0, command, 0, 0, TRUE, 0, 0, 0, &si, &pi);
+  wchar_t *wcmd = u8_to_wchar (command);
 
   free (command);
 
+  status = CreateProcessW (NULL, wcmd, NULL, NULL, TRUE, CREATE_NO_WINDOW,
+                           NULL, NULL, &si, &pi);
+
+  free (wcmd);
+
   if (! status)
     {
       *errmsg = "popen2: process creation failed";
--- a/liboctave/wrappers/octave-popen2.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/octave-popen2.h	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 extern "C" {
 #endif
 
-extern pid_t
+extern OCTAVE_API pid_t
 octave_popen2 (const char *cmd, char *const *args, bool sync_mode,
                int *fildes, const char **errmsg);
 
--- a/liboctave/wrappers/putenv-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/putenv-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern int octave_putenv_wrapper (char *str);
+extern OCTAVE_API int octave_putenv_wrapper (char *str);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/set-program-name-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/set-program-name-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,8 @@
 extern "C" {
 #endif
 
-extern const char * octave_set_program_name_wrapper (const char *pname);
+extern OCTAVE_API const char *
+octave_set_program_name_wrapper (const char *pname);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/signal-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/signal-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -38,66 +38,66 @@
 
 typedef void octave_sig_handler (int);
 
-extern int octave_kill_wrapper (pid_t pid, int signum);
+extern OCTAVE_API int octave_kill_wrapper (pid_t pid, int signum);
 
-extern char * octave_strsignal_wrapper (int signum);
+extern OCTAVE_API char * octave_strsignal_wrapper (int signum);
 
-extern bool octave_have_kill (void);
+extern OCTAVE_API bool octave_have_kill (void);
 
-extern bool octave_get_sig_number (const char *signame, int *signum);
+extern OCTAVE_API bool octave_get_sig_number (const char *signame, int *signum);
 
-octave_sig_handler *
+extern OCTAVE_API octave_sig_handler *
 octave_set_signal_handler_internal (int sig, octave_sig_handler *handler,
                                     bool restart_syscalls);
 
-extern octave_sig_handler *
+extern OCTAVE_API octave_sig_handler *
 octave_set_signal_handler_by_name (const char *signame,
                                    octave_sig_handler *handler,
                                    bool restart_syscalls);
 
-extern octave_sig_handler *
+extern OCTAVE_API octave_sig_handler *
 octave_set_default_signal_handler (int sig);
 
-extern octave_sig_handler *
+extern OCTAVE_API octave_sig_handler *
 octave_set_default_signal_handler_by_name (const char *signame);
 
-extern int octave_num_signals (void);
+extern OCTAVE_API int octave_num_signals (void);
 
-extern void * octave_block_child (void);
+extern OCTAVE_API void * octave_block_child (void);
 
-extern void octave_unblock_child (void *context);
+extern OCTAVE_API void octave_unblock_child (void *context);
 
-extern void octave_block_interrupt_signal (void);
+extern OCTAVE_API void octave_block_interrupt_signal (void);
 
-extern void octave_unblock_interrupt_signal (void);
+extern OCTAVE_API void octave_unblock_interrupt_signal (void);
 
-extern void octave_block_signal_by_name (const char *signame);
+extern OCTAVE_API void octave_block_signal_by_name (const char *signame);
 
-extern void octave_unblock_signal_by_name (const char *signame);
+extern OCTAVE_API void octave_unblock_signal_by_name (const char *signame);
 
-extern void octave_save_signal_mask (void);
+extern OCTAVE_API void octave_save_signal_mask (void);
 
-extern void octave_restore_signal_mask (void);
+extern OCTAVE_API void octave_restore_signal_mask (void);
 
-extern void * octave_alloc_signal_mask (void);
+extern OCTAVE_API void * octave_alloc_signal_mask (void);
 
-extern void octave_free_signal_mask (void *mask);
+extern OCTAVE_API void octave_free_signal_mask (void *mask);
 
-extern void octave_get_signal_mask (void *mask);
+extern OCTAVE_API void octave_get_signal_mask (void *mask);
 
-extern void octave_set_signal_mask (void *mask);
+extern OCTAVE_API void octave_set_signal_mask (void *mask);
 
-extern void octave_block_async_signals (void);
+extern OCTAVE_API void octave_block_async_signals (void);
 
-extern void octave_unblock_async_signals (void);
+extern OCTAVE_API void octave_unblock_async_signals (void);
 
-extern int octave_raise_wrapper (int signum);
+extern OCTAVE_API int octave_raise_wrapper (int signum);
 
-extern void
+extern OCTAVE_API void
 octave_create_interrupt_watcher_thread (octave_sig_handler *handler);
 
 // This can be useful for debugging.
-extern void octave_show_sigmask (const char *);
+extern OCTAVE_API void octave_show_sigmask (const char *);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/stat-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/stat-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -39,44 +39,44 @@
 extern "C" {
 #endif
 
-extern int octave_mkdir_wrapper (const char *name, mode_t mode);
+extern OCTAVE_API int octave_mkdir_wrapper (const char *name, mode_t mode);
 
-extern int octave_mkfifo_wrapper (const char *name, mode_t mode);
+extern OCTAVE_API int octave_mkfifo_wrapper (const char *name, mode_t mode);
 
-extern int octave_umask_wrapper (mode_t mode);
+extern OCTAVE_API int octave_umask_wrapper (mode_t mode);
 
-extern int
+extern OCTAVE_API int
 octave_stat_wrapper (const char *fname, mode_t *mode, ino_t *ino,
                      dev_t *dev, nlink_t *nlink, uid_t *uid,
                      gid_t *gid, off_t *size, time_t *atime,
                      time_t *mtime, time_t *ctime, dev_t *rdev,
                      long *blksize, long *blocks);
 
-extern int
+extern OCTAVE_API int
 octave_lstat_wrapper (const char *lname, mode_t *mode, ino_t *ino,
                       dev_t *dev, nlink_t *nlink, uid_t *uid,
                       gid_t *gid, off_t *size, time_t *atime,
                       time_t *mtime, time_t *ctime, dev_t *rdev,
                       long *blksize, long *blocks);
 
-extern int
+extern OCTAVE_API int
 octave_fstat_wrapper (int fid, mode_t *mode, ino_t *ino,
                       dev_t *dev, nlink_t *nlink, uid_t *uid,
                       gid_t *gid, off_t *size, time_t *atime,
                       time_t *mtime, time_t *ctime, dev_t *rdev,
                       long *blksize, long *blocks);
 
-extern bool octave_is_blk_wrapper (mode_t mode);
-extern bool octave_is_chr_wrapper (mode_t mode);
-extern bool octave_is_dir_wrapper (mode_t mode);
-extern bool octave_is_fifo_wrapper (mode_t mode);
-extern bool octave_is_lnk_wrapper (mode_t mode);
-extern bool octave_is_reg_wrapper (mode_t mode);
-extern bool octave_is_sock_wrapper (mode_t mode);
+extern OCTAVE_API bool octave_is_blk_wrapper (mode_t mode);
+extern OCTAVE_API bool octave_is_chr_wrapper (mode_t mode);
+extern OCTAVE_API bool octave_is_dir_wrapper (mode_t mode);
+extern OCTAVE_API bool octave_is_fifo_wrapper (mode_t mode);
+extern OCTAVE_API bool octave_is_lnk_wrapper (mode_t mode);
+extern OCTAVE_API bool octave_is_reg_wrapper (mode_t mode);
+extern OCTAVE_API bool octave_is_sock_wrapper (mode_t mode);
 
-extern bool octave_have_struct_stat_st_rdev (void);
-extern bool octave_have_struct_stat_st_blksize (void);
-extern bool octave_have_struct_stat_st_blocks (void);
+extern OCTAVE_API bool octave_have_struct_stat_st_rdev (void);
+extern OCTAVE_API bool octave_have_struct_stat_st_blksize (void);
+extern OCTAVE_API bool octave_have_struct_stat_st_blocks (void);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/strdup-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/strdup-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern char * octave_strdup_wrapper (const char *str);
+extern OCTAVE_API char * octave_strdup_wrapper (const char *str);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/strftime-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/strftime-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 extern "C" {
 #endif
 
-extern size_t
+extern OCTAVE_API size_t
 octave_strftime_wrapper (char *buf, size_t len, const char *fmt,
                          const struct tm *t);
 
--- a/liboctave/wrappers/strmode-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/strmode-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 // Expects a buffer with at least 12 characters.
 
-extern void octave_strmode_wrapper (mode_t mode, char *buffer);
+extern OCTAVE_API void octave_strmode_wrapper (mode_t mode, char *buffer);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/strptime-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/strptime-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 extern "C" {
 #endif
 
-extern char *
+extern OCTAVE_API char *
 octave_strptime_wrapper (const char *p, const char *fmt, struct tm *t);
 
 #if defined __cplusplus
--- a/liboctave/wrappers/time-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/time-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -36,13 +36,13 @@
 extern "C" {
 #endif
 
-extern int octave_gettimeofday_wrapper (time_t *sec, long *usec);
+extern OCTAVE_API int octave_gettimeofday_wrapper (time_t *sec, long *usec);
 
-extern int
+extern OCTAVE_API int
 octave_cpu_time (time_t *usr_sec, time_t *sys_sec,
                  long *usr_usec, long *sys_usec);
 
-extern int
+extern OCTAVE_API int
 octave_getrusage_wrapper (time_t *usr_sec, time_t *sys_sec,
                           long *usr_usec, long *sys_usec,
                           long *maxrss, long *ixrss, long *idrss,
@@ -51,7 +51,7 @@
                           long *msgsnd, long *msgrcv, long *nsignals,
                           long *nvcsw, long *nivcsw);
 
-extern time_t
+extern OCTAVE_API time_t
 octave_mktime_wrapper (struct tm *tp);
 
 #if defined __cplusplus
--- a/liboctave/wrappers/tmpfile-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/tmpfile-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,7 @@
 // c++11 provides std::tmpfile but it appears to fail on 64-bit
 // Windows systems.
 
-extern FILE * octave_tmpfile_wrapper (void);
+extern OCTAVE_API FILE * octave_tmpfile_wrapper (void);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/uname-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/uname-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern int
+extern OCTAVE_API int
 octave_uname_wrapper (char **sysname, char **nodename,
                       char **release, char **version, char **machine);
 
--- a/liboctave/wrappers/unicase-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/unicase-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -30,12 +30,12 @@
 extern "C" {
 #endif
 
-extern uint8_t *
+extern OCTAVE_API uint8_t *
 octave_u8_tolower_wrapper (const uint8_t *s, size_t n,
                            const char *iso639_language,
                            uint8_t *resultbuf, size_t *lengthp);
 
-extern uint8_t *
+extern OCTAVE_API uint8_t *
 octave_u8_toupper_wrapper (const uint8_t *s, size_t n,
                            const char *iso639_language,
                            uint8_t *resultbuf, size_t *lengthp);
--- a/liboctave/wrappers/uniconv-wrappers.c	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/uniconv-wrappers.c	Sun May 16 09:44:35 2021 +0200
@@ -57,11 +57,19 @@
 }
 
 char *
+octave_u8_conv_to_encoding_strict (const char *tocode, const uint8_t *src,
+                                   size_t srclen, size_t *lengthp)
+{
+  return u8_conv_to_encoding (tocode, iconveh_error,
+                              src, srclen, NULL, NULL, lengthp);
+}
+
+char *
 octave_u32_conv_to_encoding_strict (const char *tocode, const uint32_t *src,
-                            size_t srclen, size_t *lengthp)
+                                    size_t srclen, size_t *lengthp)
 {
   return u32_conv_to_encoding (tocode, iconveh_error,
-                              src, srclen, NULL, NULL, lengthp);
+                               src, srclen, NULL, NULL, lengthp);
 }
 
 char *
--- a/liboctave/wrappers/uniconv-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/uniconv-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -41,23 +41,25 @@
 // Since we omit arguments we don't care about in Octave, these aren't
 // named with the _wrapper suffix.
 
-extern uint8_t *
+extern OCTAVE_API uint8_t *
 octave_u8_conv_from_encoding (const char *fromcode, const char *src,
                               size_t srclen, size_t *lengthp);
 
-extern char *
+extern OCTAVE_API char *
 octave_u8_conv_to_encoding (const char *tocode, const uint8_t *src,
                             size_t srclen, size_t *lengthp);
 
-extern char *
+extern OCTAVE_API char *
+octave_u8_conv_to_encoding_strict (const char *tocode, const uint8_t *src,
+                                   size_t srclen, size_t *lengthp);
+
+extern OCTAVE_API char *
 octave_u32_conv_to_encoding_strict (const char *tocode, const uint32_t *src,
                                     size_t srclen, size_t *lengthp);
 
-extern char *
-u8_from_wchar (const wchar_t *wc);
+extern OCTAVE_API char * u8_from_wchar (const wchar_t *wc);
 
-extern wchar_t *
-u8_to_wchar (const char *u8_char);
+extern OCTAVE_API wchar_t * u8_to_wchar (const char *u8_char);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/unictype-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/unictype-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -32,41 +32,29 @@
 extern "C" {
 #endif
 
-extern bool
-octave_uc_is_alnum_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_alnum_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_alpha_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_alpha_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_blank_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_blank_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_cntrl_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_cntrl_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_digit_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_digit_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_graph_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_graph_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_lower_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_lower_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_print_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_print_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_punct_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_punct_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_space_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_space_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_upper_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_upper_wrapper (ucs4_t uc);
 
-extern bool
-octave_uc_is_xdigit_wrapper (ucs4_t uc);
+extern OCTAVE_API bool octave_uc_is_xdigit_wrapper (ucs4_t uc);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/unistd-wrappers.c	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/unistd-wrappers.c	Sun May 16 09:44:35 2021 +0200
@@ -46,6 +46,10 @@
 #  include <wchar.h>
 #endif
 
+#if defined (__WIN32__) && ! defined (__CYGWIN__)
+#  include "windows-spawn.h"
+#endif
+
 #include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 
@@ -114,152 +118,54 @@
   return dup2 (fd1, fd2);
 }
 
-#if defined (__WIN32__) && ! defined (__CYGWIN__)
-
-// Adapted from libtool wrapper.
-
-/* Prepares an argument vector before calling spawn().
-
-   Note that spawn() does not by itself call the command interpreter
-     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
-      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-         GetVersionEx(&v);
-         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
-      }) ? "cmd.exe" : "command.com").
-
-   Instead it simply concatenates the arguments, separated by ' ', and calls
-   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
-   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
-   special way:
-
-   - Space and tab are interpreted as delimiters. They are not treated as
-     delimiters if they are surrounded by double quotes: "...".
-
-   - Unescaped double quotes are removed from the input. Their only effect is
-     that within double quotes, space and tab are treated like normal
-     characters.
-
-   - Backslashes not followed by double quotes are not special.
-
-   - But 2*n+1 backslashes followed by a double quote become
-     n backslashes followed by a double quote (n >= 0):
-       \" -> "
-       \\\" -> \"
-       \\\\\" -> \\"
- */
-
-#define SHELL_SPECIAL_CHARS \
-  "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
-
-#define SHELL_SPACE_CHARS \
-  " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
-
-static char **
-prepare_spawn (char *const *argv)
-{
-  size_t argc;
-  char **new_argv;
-  size_t i;
-
-  /* Count number of arguments.  */
-  for (argc = 0; argv[argc] != NULL; argc++)
-    ;
-
-  /* Allocate new argument vector.  */
-  new_argv = (char **) malloc ((argc + 1) * sizeof (char *));
-
-  /* Put quoted arguments into the new argument vector.  */
-  for (i = 0; i < argc; i++)
-    {
-      const char *string = argv[i];
-
-      if (string[0] == '\0')
-        new_argv[i] = strdup ("\"\"");
-      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
-        {
-          int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
-          size_t length;
-          unsigned int backslashes;
-          const char *s;
-          char *quoted_string;
-          char *p;
-
-          length = 0;
-          backslashes = 0;
-          if (quote_around)
-            length++;
-          for (s = string; *s != '\0'; s++)
-            {
-              char c = *s;
-              if (c == '"')
-                length += backslashes + 1;
-              length++;
-              if (c == '\\')
-                backslashes++;
-              else
-                backslashes = 0;
-            }
-          if (quote_around)
-            length += backslashes + 1;
-
-          quoted_string = (char *) malloc (length + 1);
-
-          p = quoted_string;
-          backslashes = 0;
-          if (quote_around)
-            *p++ = '"';
-          for (s = string; *s != '\0'; s++)
-            {
-              char c = *s;
-              if (c == '"')
-                {
-                  unsigned int j;
-                  for (j = backslashes + 1; j > 0; j--)
-                    *p++ = '\\';
-                }
-              *p++ = c;
-              if (c == '\\')
-                backslashes++;
-              else
-                backslashes = 0;
-            }
-          if (quote_around)
-            {
-              unsigned int j;
-              for (j = backslashes; j > 0; j--)
-                *p++ = '\\';
-              *p++ = '"';
-            }
-          *p = '\0';
-
-          new_argv[i] = quoted_string;
-        }
-      else
-        new_argv[i] = strdup (string);
-    }
-
-  new_argv[argc] = NULL;
-
-  return new_argv;
-}
-
-#endif
-
 int
 octave_execv_wrapper (const char *file, char *const *argv)
 {
 #if defined (__WIN32__) && ! defined (__CYGWIN__)
 
-  char **sanitized_argv = prepare_spawn (argv);
+  char *argv_mem_to_free;
+  char **sanitized_argv = prepare_spawn (argv, &argv_mem_to_free);
+
+#  if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+
+  // count number of arguments
+  size_t argc;
+  for (argc = 0; sanitized_argv[argc] != NULL; argc++)
+    ;
+
+  wchar_t *wfile = u8_to_wchar (file);
+  const wchar_t **wargv = malloc ((argc + 1) * sizeof (wchar_t *));
+
+  // convert multibyte UTF-8 strings to wide character strings
+  for (size_t i_arg = 0; i_arg < argc; i_arg++)
+    wargv[i_arg] = u8_to_wchar (sanitized_argv[i_arg]);
+
+  wargv[argc] = NULL;
+
+  free (sanitized_argv);
+  free (argv_mem_to_free);
+
+  int status = _wspawnv (P_OVERLAY, wfile, wargv);
+
+  // This only happens if _wspawnv fails.
+
+  free (wfile);
+  const wchar_t **wp = wargv;
+  // Casting away the const in the loop is ok here.
+  while (*wp)
+    free ((wchar_t *) *wp++);
+  free (wargv);
+
+#  else
 
   int status = spawnv (P_OVERLAY, file, sanitized_argv);
 
   // This only happens if spawnv fails.
 
-  char **p = sanitized_argv;
-  while (*p)
-    free (*p++);
   free (sanitized_argv);
+  free (argv_mem_to_free);
+
+#  endif
 
   return status;
 
--- a/liboctave/wrappers/unistd-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/unistd-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -36,73 +36,73 @@
 extern "C" {
 #endif
 
-extern int octave_access_f_ok (void);
+extern OCTAVE_API int octave_access_f_ok (void);
 
-extern int octave_access_r_ok (void);
+extern OCTAVE_API int octave_access_r_ok (void);
 
-extern int octave_access_w_ok (void);
+extern OCTAVE_API int octave_access_w_ok (void);
 
-extern int octave_access_x_ok (void);
+extern OCTAVE_API int octave_access_x_ok (void);
 
-extern int octave_access_wrapper (const char *nm, int mode);
+extern OCTAVE_API int octave_access_wrapper (const char *nm, int mode);
 
-extern int octave_chdir_wrapper (const char *nm);
+extern OCTAVE_API int octave_chdir_wrapper (const char *nm);
 
-extern int octave_close_wrapper (int fd);
+extern OCTAVE_API int octave_close_wrapper (int fd);
 
-extern const char * octave_ctermid_wrapper (void);
+extern OCTAVE_API const char * octave_ctermid_wrapper (void);
 
-extern int octave_dup2_wrapper (int fd1, int fd2);
+extern OCTAVE_API int octave_dup2_wrapper (int fd1, int fd2);
 
-extern int octave_execv_wrapper (const char *file, char *const *argv);
+extern OCTAVE_API int octave_execv_wrapper (const char *file, char *const *argv);
 
-extern int octave_execvp_wrapper (const char *file, char *const *argv);
+extern OCTAVE_API int octave_execvp_wrapper (const char *file, char *const *argv);
 
-extern pid_t octave_fork_wrapper (void);
+extern OCTAVE_API pid_t octave_fork_wrapper (void);
 
-extern int octave_ftruncate_wrapper (int fd, off_t sz);
+extern OCTAVE_API int octave_ftruncate_wrapper (int fd, off_t sz);
 
-extern char * octave_getcwd_wrapper (char *nm, size_t len);
+extern OCTAVE_API char * octave_getcwd_wrapper (char *nm, size_t len);
 
-extern gid_t octave_getegid_wrapper (void);
+extern OCTAVE_API gid_t octave_getegid_wrapper (void);
 
-extern uid_t octave_geteuid_wrapper (void);
+extern OCTAVE_API uid_t octave_geteuid_wrapper (void);
 
-extern gid_t octave_getgid_wrapper (void);
+extern OCTAVE_API gid_t octave_getgid_wrapper (void);
 
-extern int octave_gethostname_wrapper (char *nm, size_t len);
+extern OCTAVE_API int octave_gethostname_wrapper (char *nm, size_t len);
 
-extern pid_t octave_getpgrp_wrapper (void);
+extern OCTAVE_API pid_t octave_getpgrp_wrapper (void);
 
-extern pid_t octave_getpid_wrapper (void);
+extern OCTAVE_API pid_t octave_getpid_wrapper (void);
 
-extern pid_t octave_getppid_wrapper (void);
+extern OCTAVE_API pid_t octave_getppid_wrapper (void);
 
-extern uid_t octave_getuid_wrapper (void);
+extern OCTAVE_API uid_t octave_getuid_wrapper (void);
 
-extern int octave_isatty_wrapper (int fd);
+extern OCTAVE_API int octave_isatty_wrapper (int fd);
 
-extern int octave_link_wrapper (const char *nm1, const char *nm2);
+extern OCTAVE_API int octave_link_wrapper (const char *nm1, const char *nm2);
 
-extern int octave_pipe_wrapper (int *fd);
+extern OCTAVE_API int octave_pipe_wrapper (int *fd);
 
-extern int octave_rmdir_wrapper (const char *nm);
+extern OCTAVE_API int octave_rmdir_wrapper (const char *nm);
 
-extern pid_t octave_setsid_wrapper (void);
+extern OCTAVE_API pid_t octave_setsid_wrapper (void);
 
-extern int octave_stdin_fileno (void);
+extern OCTAVE_API int octave_stdin_fileno (void);
 
-extern int octave_stdout_fileno (void);
+extern OCTAVE_API int octave_stdout_fileno (void);
 
-extern int octave_symlink_wrapper (const char *nm1, const char *nm2);
+extern OCTAVE_API int octave_symlink_wrapper (const char *nm1, const char *nm2);
 
-extern int octave_unlink_wrapper (const char *nm);
+extern OCTAVE_API int octave_unlink_wrapper (const char *nm);
 
-extern pid_t octave_vfork_wrapper (void);
+extern OCTAVE_API pid_t octave_vfork_wrapper (void);
 
-extern bool octave_have_fork (void);
+extern OCTAVE_API bool octave_have_fork (void);
 
-extern bool octave_have_vfork (void);
+extern OCTAVE_API bool octave_have_vfork (void);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/unistr-wrappers.c	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/unistr-wrappers.c	Sun May 16 09:44:35 2021 +0200
@@ -49,6 +49,27 @@
   return u8_strmbtouc (puc, src);
 }
 
+uint8_t *
+octave_u16_to_u8_wrapper (const uint16_t *src, size_t src_len,
+                          uint8_t *result_buf, size_t *lengthp)
+{
+  return u16_to_u8 (src, src_len, result_buf, lengthp);
+}
+
+uint8_t *
+octave_u32_to_u8_wrapper (const uint32_t *src, size_t src_len,
+                          uint8_t *result_buf, size_t *lengthp)
+{
+  return u32_to_u8 (src, src_len, result_buf, lengthp);
+}
+
+uint16_t *
+octave_u8_to_u16_wrapper (const uint8_t *src, size_t src_len,
+                          uint16_t *result_buf, size_t *lengthp)
+{
+  return u8_to_u16 (src, src_len, result_buf, lengthp);
+}
+
 uint32_t *
 octave_u8_to_u32_wrapper (const uint8_t *src, size_t src_len,
                           uint32_t *result_buf, size_t *lengthp)
--- a/liboctave/wrappers/unistr-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/unistr-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -30,16 +30,27 @@
 extern "C" {
 #endif
 
-const uint8_t *
+extern OCTAVE_API const uint8_t *
 octave_u8_check_wrapper (const uint8_t *src, size_t n);
 
-extern int
-octave_u8_strmblen_wrapper (const uint8_t *src);
+extern OCTAVE_API int octave_u8_strmblen_wrapper (const uint8_t *src);
 
-extern int
+extern OCTAVE_API int
 octave_u8_strmbtouc_wrapper (uint32_t *puc, const uint8_t *src);
 
-extern uint32_t *
+extern OCTAVE_API uint8_t *
+octave_u16_to_u8_wrapper (const uint16_t *src, size_t src_len,
+                          uint8_t *result_buf, size_t *lengthp);
+
+extern OCTAVE_API uint8_t *
+octave_u32_to_u8_wrapper (const uint32_t *src, size_t src_len,
+                          uint8_t *result_buf, size_t *lengthp);
+
+extern OCTAVE_API uint16_t *
+octave_u8_to_u16_wrapper (const uint8_t *src, size_t src_len,
+                          uint16_t *result_buf, size_t *lengthp);
+
+extern OCTAVE_API uint32_t *
 octave_u8_to_u32_wrapper (const uint8_t *src, size_t src_len,
                           uint32_t *result_buf, size_t *lengthp);
 
--- a/liboctave/wrappers/unsetenv-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/unsetenv-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern int octave_unsetenv_wrapper (const char *name);
+extern OCTAVE_API int octave_unsetenv_wrapper (const char *name);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/vasprintf-wrapper.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/vasprintf-wrapper.h	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 extern "C" {
 #endif
 
-extern int
+extern OCTAVE_API int
 octave_vasprintf_wrapper (char **buf, const char *fmt, va_list args);
 
 #if defined __cplusplus
--- a/liboctave/wrappers/wait-for-input.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/wait-for-input.h	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-extern int octave_wait_for_input (int fid);
+extern OCTAVE_API int octave_wait_for_input (int fid);
 
 #if defined __cplusplus
 }
--- a/liboctave/wrappers/wait-wrappers.c	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/wait-wrappers.c	Sun May 16 09:44:35 2021 +0200
@@ -35,6 +35,10 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#if defined (__WIN32__) && ! defined (__CYGWIN__)
+#  include <windows.h>
+#endif
+
 #include "wait-wrappers.h"
 
 #if ! defined (WCONTINUE)
@@ -57,14 +61,42 @@
 octave_waitpid_wrapper (pid_t pid, int *statusp, int options)
 {
 #if defined (__WIN32__) && ! defined (__CYGWIN__)
+  // gnulib's waitpid replacement currently uses _cwait, which
+  // apparently only works with console applications.
+  // Implement our own wrapper using win32 API functions.
 
-  octave_unused_parameter (pid);
   octave_unused_parameter (options);
 
-  // gnulib's waitpid replacement currently uses _cwait, which
-  // apparently only works with console applications.
-  *statusp = 0;
-  return -1;
+  pid_t retval = -1;
+  DWORD status = 0;
+
+  HANDLE hProcess = OpenProcess (PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
+                                 false, pid);
+
+  if (! hProcess)
+    return retval;
+
+  if (WaitForSingleObject (hProcess, INFINITE) != WAIT_OBJECT_0)
+    {
+      CloseHandle (hProcess);
+      return retval;
+    }
+
+  if (! GetExitCodeProcess (hProcess, &status))
+    {
+      CloseHandle (hProcess);
+      return retval;
+    }
+
+  CloseHandle (hProcess);
+
+  if (statusp)
+    *statusp = status;
+
+  retval = pid;
+
+  return retval;
+
 #else
   return waitpid (pid, statusp, options);
 #endif
--- a/liboctave/wrappers/wait-wrappers.h	Sun May 16 09:43:43 2021 +0200
+++ b/liboctave/wrappers/wait-wrappers.h	Sun May 16 09:44:35 2021 +0200
@@ -36,29 +36,30 @@
 extern "C" {
 #endif
 
-extern pid_t octave_waitpid_wrapper (pid_t pid, int *statusp, int options);
+extern OCTAVE_API pid_t
+octave_waitpid_wrapper (pid_t pid, int *statusp, int options);
 
-extern int octave_wcontinue_wrapper (void);
-
-extern int octave_wcoredump_wrapper (int status);
+extern OCTAVE_API int octave_wcontinue_wrapper (void);
 
-extern bool octave_wifcontinued_wrapper (int status);
+extern OCTAVE_API int octave_wcoredump_wrapper (int status);
 
-extern bool octave_wifexited_wrapper (int status);
+extern OCTAVE_API bool octave_wifcontinued_wrapper (int status);
 
-extern bool octave_wifsignaled_wrapper (int status);
+extern OCTAVE_API bool octave_wifexited_wrapper (int status);
 
-extern bool octave_wifstopped_wrapper (int status);
+extern OCTAVE_API bool octave_wifsignaled_wrapper (int status);
 
-extern int octave_wexitstatus_wrapper (int status);
+extern OCTAVE_API bool octave_wifstopped_wrapper (int status);
 
-extern int octave_wnohang_wrapper (void);
+extern OCTAVE_API int octave_wexitstatus_wrapper (int status);
 
-extern int octave_wstopsig_wrapper (int status);
+extern OCTAVE_API int octave_wnohang_wrapper (void);
+
+extern OCTAVE_API int octave_wstopsig_wrapper (int status);
 
-extern int octave_wtermsig_wrapper (int status);
+extern OCTAVE_API int octave_wtermsig_wrapper (int status);
 
-extern int octave_wuntraced_wrapper (void);
+extern OCTAVE_API int octave_wuntraced_wrapper (void);
 
 #if defined __cplusplus
 }
--- a/m4/acinclude.m4	Sun May 16 09:43:43 2021 +0200
+++ b/m4/acinclude.m4	Sun May 16 09:44:35 2021 +0200
@@ -100,6 +100,74 @@
   fi
 ])
 dnl
+dnl Check if pthread stack size accounts for thread-local storage.
+dnl
+dnl This program should succeed if the pthread library allocates memory
+dnl for thread-local (__thread) variables independently of the
+dnl requested thread stack size.
+dnl
+dnl It will fail if (as in the current version of glibc) the storage
+dnl for thread-local variables is subtracted from the memory allocated
+dnl for the thread stack.  (This can cause problems for Java and for
+dnl other libraries.)
+dnl
+dnl This bug is tracked in glibc at:
+dnl https://sourceware.org/bugzilla/show_bug.cgi?id=11787
+dnl
+AC_DEFUN([OCTAVE_CHECK_BROKEN_PTHREAD_STACKSIZE], [
+  AC_CACHE_CHECK([whether pthread stack size does not account for thread-local storage],
+    [octave_cv_broken_pthread_stacksize],
+    [AC_LANG_PUSH(C)
+    AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+static char __thread data[100 * 1024];
+
+static void * threadfunc(void *arg)
+{
+    return data;
+}
+      ]], [[
+  pthread_attr_t attr;
+  pthread_t thread;
+  int errnum;
+
+  pthread_attr_init (&attr);
+  errnum = pthread_attr_setstacksize (&attr, 64 * 1024);
+  if (errnum != 0)
+  {
+    fprintf (stderr, "pthread_attr_setstacksize: %s\n", strerror(errnum));
+    return 1;
+  }
+  errnum = pthread_create (&thread, &attr, &threadfunc, NULL);
+  if (errnum != 0)
+  {
+    fprintf (stderr, "pthread_create: %s\n", strerror(errnum));
+    return 1;
+  }
+  errnum = pthread_join (thread, NULL);
+  if (errnum != 0)
+  {
+    fprintf (stderr, "pthread_join: %s\n", strerror(errnum));
+    return 1;
+  }
+
+  pthread_attr_destroy (&attr);
+  return 0;
+    ]])],
+    octave_cv_broken_pthread_stacksize=no,
+    octave_cv_broken_pthread_stacksize=yes,
+    octave_cv_broken_pthread_stacksize=no)
+    AC_LANG_POP(C)
+  ])
+  if test $octave_cv_broken_pthread_stacksize = yes; then
+    AC_DEFINE(HAVE_BROKEN_PTHREAD_STACKSIZE, 1,
+      [Define to 1 if pthread stack size does not account for thread-local storage.])
+  fi
+])
+dnl
 dnl Check for broken stl_algo.h header file in gcc versions 4.8.0, 4.8.1, 4.8.2
 dnl which leads to failures in nth_element.
 dnl
@@ -187,74 +255,6 @@
   fi
 ])
 dnl
-dnl Check if pthread stack size accounts for thread-local storage.
-dnl
-dnl This program should succeed if the pthread library allocates memory
-dnl for thread-local (__thread) variables independently of the
-dnl requested thread stack size.
-dnl
-dnl It will fail if (as in the current version of glibc) the storage
-dnl for thread-local variables is subtracted from the memory allocated
-dnl for the thread stack.  (This can cause problems for Java and for
-dnl other libraries.)
-dnl
-dnl This bug is tracked in glibc at:
-dnl https://sourceware.org/bugzilla/show_bug.cgi?id=11787
-dnl
-AC_DEFUN([OCTAVE_CHECK_BROKEN_PTHREAD_STACKSIZE], [
-  AC_CACHE_CHECK([whether pthread stack size does not account for thread-local storage],
-    [octave_cv_broken_pthread_stacksize],
-    [AC_LANG_PUSH(C)
-    AC_RUN_IFELSE([AC_LANG_PROGRAM([[
-#include <stdio.h>
-#include <string.h>
-#include <pthread.h>
-
-static char __thread data[100 * 1024];
-
-static void * threadfunc(void *arg)
-{
-    return data;
-}
-      ]], [[
-  pthread_attr_t attr;
-  pthread_t thread;
-  int errnum;
-
-  pthread_attr_init (&attr);
-  errnum = pthread_attr_setstacksize (&attr, 64 * 1024);
-  if (errnum != 0)
-  {
-    fprintf (stderr, "pthread_attr_setstacksize: %s\n", strerror(errnum));
-    return 1;
-  }
-  errnum = pthread_create (&thread, &attr, &threadfunc, NULL);
-  if (errnum != 0)
-  {
-    fprintf (stderr, "pthread_create: %s\n", strerror(errnum));
-    return 1;
-  }
-  errnum = pthread_join (thread, NULL);
-  if (errnum != 0)
-  {
-    fprintf (stderr, "pthread_join: %s\n", strerror(errnum));
-    return 1;
-  }
-
-  pthread_attr_destroy (&attr);
-  return 0;
-    ]])],
-    octave_cv_broken_pthread_stacksize=no,
-    octave_cv_broken_pthread_stacksize=yes,
-    octave_cv_broken_pthread_stacksize=no)
-    AC_LANG_POP(C)
-  ])
-  if test $octave_cv_broken_pthread_stacksize = yes; then
-    AC_DEFINE(HAVE_BROKEN_PTHREAD_STACKSIZE, 1,
-      [Define to 1 if pthread stack size does not account for thread-local storage.])
-  fi
-])
-dnl
 dnl Check whether CXSparse is version 2.2 or later
 dnl FIXME: This test uses a version number.  It potentially could
 dnl        be re-written to actually call a function, but is it worth it?
@@ -343,6 +343,83 @@
   LIBS="$ac_octave_save_LIBS"
 ])
 dnl
+dnl OCTAVE_CHECK_FORTRAN_SYMBOL_AND_CALLING_CONVENTIONS
+dnl
+dnl Set variables related to Fortran symbol names (append underscore,
+dnl use uppercase names, etc.) and calling convention (mostly used for
+dnl determining how character strings are passed).
+dnl
+AC_DEFUN([OCTAVE_CHECK_FORTRAN_SYMBOL_AND_CALLING_CONVENTIONS], [
+  F77_TOLOWER=yes
+  F77_APPEND_UNDERSCORE=yes
+  F77_APPEND_EXTRA_UNDERSCORE=yes
+
+  case $ac_cv_f77_mangling in
+    "upper case") F77_TOLOWER=no ;;
+  esac
+  case $ac_cv_f77_mangling in
+    "no underscore") F77_APPEND_UNDERSCORE=no ;;
+  esac
+  case $ac_cv_f77_mangling in
+    "no extra underscore") F77_APPEND_EXTRA_UNDERSCORE=no ;;
+  esac
+
+  case $canonical_host_type in
+    i[[3456789]]86-*-*)
+      if test $ac_cv_f77_compiler_gnu = yes; then
+        OCTAVE_F77_FLAG([-mieee-fp])
+      fi
+    ;;
+    alpha*-*-*)
+      if test $ac_cv_f77_compiler_gnu = yes; then
+        OCTAVE_F77_FLAG([-mieee])
+      else
+        OCTAVE_F77_FLAG([-ieee])
+        OCTAVE_F77_FLAG([-fpe1])
+      fi
+    ;;
+    powerpc-apple-machten*)
+      FFLAGS=
+    ;;
+  esac
+
+  if test $ac_cv_f77_compiler_gnu = yes; then
+    FORTRAN_CALLING_CONVENTION=gfortran
+  else
+    FORTRAN_CALLING_CONVENTION=unknown
+  fi
+  AC_ARG_ENABLE([fortran-calling-convention],
+    [AS_HELP_STRING([--enable-fortran-calling-convention=OPTION],
+      [Select C++ to Fortran calling convention.  "gfortran" should be detected automatically.  Other options are "cray", "visual-fortran", or "f2c".])],
+    [FORTRAN_CALLING_CONVENTION="$enableval"], [])
+
+  case $FORTRAN_CALLING_CONVENTION in
+    gfortran)
+      AC_DEFINE(F77_USES_GFORTRAN_CALLING_CONVENTION, 1, [Define to 1 if calling Fortran from C++ should use the gfortran calling convention.])
+    ;;
+    cray)
+      AC_DEFINE(F77_USES_CRAY_CALLING_CONVENTION, 1, [Define to 1 if calling Fortran from C++ should use the Cray Fortran calling convention.])
+    ;;
+    visual-fortran)
+      AC_DEFINE(F77_USES_VISUAL_FORTRAN_CALLING_CONVENTION, 1, [Define to 1 if calling Fortran from C++ should use the Visual Fortran calling convention.])
+    ;;
+    f2c)
+      AC_DEFINE(F77_USES_F2C_CALLING_CONVENTION, 1, [Define to 1 if calling Fortran from C++ should use the f2c calling convention.])
+    ;;
+    *)
+      AC_MSG_ERROR([to build Octave, the C++ to Fortran calling convention must be known.])
+    ;;
+  esac
+
+  if test -n "$FFLAGS"; then
+    AC_MSG_NOTICE([defining FFLAGS to be $FFLAGS])
+  fi
+
+  AC_SUBST(F77_TOLOWER)
+  AC_SUBST(F77_APPEND_UNDERSCORE)
+  AC_SUBST(F77_APPEND_EXTRA_UNDERSCORE)
+])
+dnl
 dnl Check if function gluTessCallback is called with "(...)".
 dnl
 AC_DEFUN([OCTAVE_CHECK_FUNC_GLUTESSCALLBACK_THREEDOTS], [
@@ -369,83 +446,36 @@
   fi
 ])
 dnl
-dnl Check whether the Qt class QAbstractItemModel exists and has the
-dnl beginResetModel and endResetModel member functions.  These member
-dnl functions were introduced in Qt 4.6.
+dnl Check whether the Qt class QList has a constructor that accepts
+dnl a pair of iterators.  This constructor was introduced in Qt 5.14.
 dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.6 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QABSTRACTITEMMODEL_BEGINRESETMODEL], [
-  AC_CACHE_CHECK([for QAbstractItemModel::beginResetModel in <QAbstractItemModel>],
-    [octave_cv_func_qabstractitemmodel_beginresetmodel],
+AC_DEFUN([OCTAVE_CHECK_FUNC_QFONTMETRICS_HORIZONTAL_ADVANCE], [
+  AC_CACHE_CHECK([for QFontMetrics::horizontalAdvance function],
+    [octave_cv_func_qfontmetrics_horizontal_advance],
     [AC_LANG_PUSH(C++)
     ac_octave_save_CPPFLAGS="$CPPFLAGS"
     ac_octave_save_CXXFLAGS="$CXXFLAGS"
     CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
     CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QAbstractItemModel>
-        class item_model : public QAbstractItemModel
-        {
-        public:
-          item_model (QObject *parent = 0) : QAbstractItemModel (parent) {}
-          ~item_model () {}
-          QModelIndex index (int, int, const QModelIndex& m) const { return m; }
-          QModelIndex parent (const QModelIndex& m) const { return m; }
-          int columnCount (const QModelIndex&) const { return 0; }
-          int rowCount (const QModelIndex&) const { return 0; }
-          QVariant data (const QModelIndex&, int) const { return QVariant(); }
-          void update_model ()
-          {
-            this->beginResetModel ();
-            this->endResetModel ();
-          }
-        };
+        #include <QFont>
+        #include <QFontMetrics>
+        #include <QString>
         ]], [[
-        item_model model;
-        model.update_model ();
+        QFont font;
+        QFontMetrics fm (font);
+        fm.horizontalAdvance ('x');
+        fm.horizontalAdvance (QString ("string"));
         ]])],
-      octave_cv_func_qabstractitemmodel_beginresetmodel=yes,
-      octave_cv_func_qabstractitemmodel_beginresetmodel=no)
+      octave_cv_func_qfontmetrics_horizontal_advance=yes,
+      octave_cv_func_qfontmetrics_horizontal_advance=no)
     CPPFLAGS="$ac_octave_save_CPPFLAGS"
     CXXFLAGS="$ac_octave_save_CXXFLAGS"
     AC_LANG_POP(C++)
   ])
-  if test $octave_cv_func_qabstractitemmodel_beginresetmodel = yes; then
-    AC_DEFINE(HAVE_QABSTRACTITEMMODEL_BEGINRESETMODEL, 1,
-      [Define to 1 if you have the `QAbstractItemModel::beginResetModel' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt QComboBox class has the setCurrentText
-dnl function.  This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QCOMBOBOX_SETCURRENTTEXT], [
-  AC_CACHE_CHECK([for QComboBox::setCurrentText],
-    [octave_cv_func_qcombobox_setcurrenttext],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QComboBox>
-        ]], [[
-        QComboBox combo_box (nullptr);
-        combo_box.setCurrentText ("text");
-        ]])],
-      octave_cv_func_qcombobox_setcurrenttext=yes,
-      octave_cv_func_qcombobox_setcurrenttext=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qcombobox_setcurrenttext = yes; then
-    AC_DEFINE(HAVE_QCOMBOBOX_SETCURRENTTEXT, 1,
-      [Define to 1 if you have the `QComboBox::setCurrentText' member function.])
+  if test $octave_cv_func_qfontmetrics_horizontal_advance = yes; then
+    AC_DEFINE(HAVE_QFONTMETRICS_HORIZONTAL_ADVANCE, 1,
+      [Define to 1 if you have the `QFontMetrics::horizontalAdvance' function.])
   fi
 ])
 dnl
@@ -479,96 +509,38 @@
   fi
 ])
 dnl
-dnl Check whether the Qt QHeaderView class has the setSectionResizeMode
-dnl function.  This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
+dnl Check whether the Qt class QHelpEngine has the documentsForIdentifier
+dnl function.  dnl This member function was introduced in Qt 5.15.
 dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONRESIZEMODE], [
-  AC_CACHE_CHECK([for QHeaderView::setSectionResizeMode],
-    [octave_cv_func_qheaderview_setsectionresizemode],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QHeaderView>
-        ]], [[
-        QHeaderView header_view (Qt::Horizontal);
-        header_view.setSectionResizeMode (QHeaderView::Interactive);
-        ]])],
-      octave_cv_func_qheaderview_setsectionresizemode=yes,
-      octave_cv_func_qheaderview_setsectionresizemode=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qheaderview_setsectionresizemode = yes; then
-    AC_DEFINE(HAVE_QHEADERVIEW_SETSECTIONRESIZEMODE, 1,
-      [Define to 1 if you have the `QHeaderView::setSectionResizeMode' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt QHeaderView class has the setSectionsClickable
-dnl function.  This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONSCLICKABLE], [
-  AC_CACHE_CHECK([for QHeaderView::setSectionsClickable],
-    [octave_cv_func_qheaderview_setsectionsclickable],
+AC_DEFUN([OCTAVE_CHECK_FUNC_QHELPENGINE_DOCUMENTSFORIDENTIFIER], [
+  AC_CACHE_CHECK([for QHelpEngine::documentsForIdentifier in <QHelpEngine>],
+    [octave_cv_func_qhelpengine_documentsforidentifier],
     [AC_LANG_PUSH(C++)
     ac_octave_save_CPPFLAGS="$CPPFLAGS"
     ac_octave_save_CXXFLAGS="$CXXFLAGS"
     CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
+    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QHeaderView>
+        #include <QHelpEngine>
+        #include <QHelpLink>
+        #include <QList>
+        #include <QString>
+        #include <QUrl>
         ]], [[
-        QHeaderView header_view (Qt::Horizontal);
-        header_view.setSectionsClickable (true);
+        QString collection_file;
+        QHelpEngine eng (collection_file);
+        QString id;
+        eng.documentsForIdentifier (id);
         ]])],
-      octave_cv_func_qheaderview_setsectionsclickable=yes,
-      octave_cv_func_qheaderview_setsectionsclickable=no)
+      octave_cv_func_qhelpengine_documentsforidentifier=yes,
+      octave_cv_func_qhelpengine_documentsforidentifier=no)
     CPPFLAGS="$ac_octave_save_CPPFLAGS"
     CXXFLAGS="$ac_octave_save_CXXFLAGS"
     AC_LANG_POP(C++)
   ])
-  if test $octave_cv_func_qheaderview_setsectionsclickable = yes; then
-    AC_DEFINE(HAVE_QHEADERVIEW_SETSECTIONSCLICKABLE, 1,
-      [Define to 1 if you have the `QHeaderView::setSectionsClickable' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt QHeaderView class has the setSectionsMovable
-dnl function.  This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONSMOVABLE], [
-  AC_CACHE_CHECK([for QHeaderView::setSectionsMovable],
-    [octave_cv_func_qheaderview_setsectionsmovable],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QHeaderView>
-        ]], [[
-        QHeaderView header_view (Qt::Horizontal);
-        header_view.setSectionsMovable (true);
-        ]])],
-      octave_cv_func_qheaderview_setsectionsmovable=yes,
-      octave_cv_func_qheaderview_setsectionsmovable=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qheaderview_setsectionsmovable = yes; then
-    AC_DEFINE(HAVE_QHEADERVIEW_SETSECTIONSMOVABLE, 1,
-      [Define to 1 if you have the `QHeaderView::setSectionsMovable' member function.])
+  if test $octave_cv_func_qhelpengine_documentsforidentifier = yes; then
+    AC_DEFINE(HAVE_QHELPENGINE_DOCUMENTSFORIDENTIFIER, 1,
+      [Define to 1 if you have the `QHelpEngine::documentsForIdentifier' member function.])
   fi
 ])
 dnl
@@ -604,139 +576,12 @@
   fi
 ])
 dnl
-dnl Check whether new API is used with QHelpIndexWidget.
-dnl Under new API, QHelpIndexWidget emits documentActivates.
-dnl Under old API, QHelpIndexWidget emits linkActivated.
-dnl New structure/signal API was introduced in Qt 5.15.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 5.14 or older.
-dnl
-AC_DEFUN([OCTAVE_CHECK_NEW_QHELPINDEXWIDGET_API], [
-  AC_CACHE_CHECK([for new QHelpIndexWidget API],
-    [octave_cv_new_qhelpindexwidget_api],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QHelpLink>
-        ]], [[
-        QHelpLink link;
-        ]])],
-      octave_cv_new_qhelpindexwidget_api=yes,
-      octave_cv_new_qhelpindexwidget_api=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_new_qhelpindexwidget_api = yes; then
-    AC_DEFINE(HAVE_NEW_QHELPINDEXWIDGET_API, 1,
-      [Define to 1 if using new QHelpIndexWidget API.])
-  fi
-])
-dnl
-dnl Check whether the Qt function qInstallMessageHandler is available.
-dnl This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QINSTALLMESSAGEHANDLER], [
-  AC_CACHE_CHECK([for qInstallMessageHandler],
-    [octave_cv_func_qinstallmessagehandler],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QtGlobal>
-        ]], [[
-        qInstallMessageHandler (nullptr);
-        ]])],
-      octave_cv_func_qinstallmessagehandler=yes,
-      octave_cv_func_qinstallmessagehandler=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qinstallmessagehandler = yes; then
-    AC_DEFINE(HAVE_QINSTALLMESSAGEHANDLER, 1,
-      [Define to 1 if you have the `qInstallMessageHandler' function.])
-  fi
-])
-dnl
-dnl Check whether the Qt class QLineEdit has the setPlaceholderText member
-dnl function.  This member function was introduced in Qt 4.7.
+dnl Check whether the Qt class QList has a constructor that accepts
+dnl a pair of iterators.  This constructor was introduced in Qt 5.14.
 dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.7 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QLINEEDIT_SETPLACEHOLDERTEXT], [
-  AC_CACHE_CHECK([for QLineEdit::setPlaceholderText in <QLinedEdit>],
-    [octave_cv_func_qlineedit_setplaceholdertext],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QLineEdit>
-        ]], [[
-        QLineEdit line_edit;
-        line_edit.setPlaceholderText ("placeholder text");
-        ]])],
-      octave_cv_func_qlineedit_setplaceholdertext=yes,
-      octave_cv_func_qlineedit_setplaceholdertext=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qlineedit_setplaceholdertext = yes; then
-    AC_DEFINE(HAVE_QLINEEDIT_SETPLACEHOLDERTEXT, 1,
-      [Define to 1 if you have the `QLineEdit::setPlaceholderText' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt QMouseEvent class has the localPos function.
-dnl This function was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QMOUSEEVENT_LOCALPOS], [
-  AC_CACHE_CHECK([for QMouseEvent::localPos],
-    [octave_cv_func_qmouseevent_localpos],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QMouseEvent>
-        ]], [[
-        QMouseEvent *event;
-        event->localPos ();
-        ]])],
-      octave_cv_func_qmouseevent_localpos=yes,
-      octave_cv_func_qmouseevent_localpos=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qmouseevent_localpos = yes; then
-    AC_DEFINE(HAVE_QMOUSEEVENT_LOCALPOS, 1,
-      [Define to 1 if you have the `QMouseEvent::localPos' member function.])
-  fi
-])
-dnl
-dnl Check whether QObject::findChildren accepts Qt::FindChildOptions
-dnl argument.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS], [
-  AC_CACHE_CHECK([whether QObject::findChildren accepts Qt::FindChildOptions],
-    [octave_cv_func_qobject_findchildren_accepts_findchildoptions],
+AC_DEFUN([OCTAVE_CHECK_FUNC_QLIST_ITERATOR_CONSTRUCTOR], [
+  AC_CACHE_CHECK([for QList<T>::QList (iterator, iterator) constructor],
+    [octave_cv_func_qlist_iterator_constructor],
     [AC_LANG_PUSH(C++)
     ac_octave_save_CPPFLAGS="$CPPFLAGS"
     ac_octave_save_CXXFLAGS="$CXXFLAGS"
@@ -744,22 +589,19 @@
     CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
         #include <QList>
-        #include <QObject>
-        #include <QWidget>
         ]], [[
-        QObject obj;
-        QList<QWidget *> widgets
-          = obj.findChildren<QWidget *> ("name", Qt::FindDirectChildrenOnly);
+        QList<int> lst_one;
+        QList<int> lst_two (lst_one.begin (), lst_one.end ());
         ]])],
-      octave_cv_func_qobject_findchildren_accepts_findchildoptions=yes,
-      octave_cv_func_qobject_findchildren_accepts_findchildoptions=no)
+      octave_cv_func_qlist_iterator_constructor=yes,
+      octave_cv_func_qlist_iterator_constructor=no)
     CPPFLAGS="$ac_octave_save_CPPFLAGS"
     CXXFLAGS="$ac_octave_save_CXXFLAGS"
     AC_LANG_POP(C++)
   ])
-  if test $octave_cv_func_qobject_findchildren_accepts_findchildoptions = yes; then
-    AC_DEFINE(QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS, 1,
-      [Define to 1 if 'QObject::findChildren' accepts 'Qt::FindChildOptions' argument.])
+  if test $octave_cv_func_qlist_iterator_constructor = yes; then
+    AC_DEFINE(HAVE_QLIST_ITERATOR_CONSTRUCTOR, 1,
+      [Define to 1 if you have the `QList<T>::QList (iterator, iterator)' constructor.])
   fi
 ])
 dnl
@@ -797,6 +639,37 @@
   fi
 ])
 dnl
+dnl Check whether the Qt class QPrinter has the setPageSize member function.
+dnl This member function was introduced in Qt 5.3.
+dnl
+dnl FIXME: remove this test when we drop support for Qt older than 5.3.
+dnl
+AC_DEFUN([OCTAVE_CHECK_FUNC_QPRINTER_SETPAGESIZE], [
+  AC_CACHE_CHECK([for QPrinter::setPageSize in <QPrinter>],
+    [octave_cv_func_qprinter_setpagesizes],
+    [AC_LANG_PUSH(C++)
+    ac_octave_save_CPPFLAGS="$CPPFLAGS"
+    ac_octave_save_CXXFLAGS="$CXXFLAGS"
+    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
+    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+        #include <QPrinter>
+        ]], [[
+        QPrinter printer;
+        printer.setPageSize (QPageSize (QSizeF (8.5, 11.0), QPageSize::Inch));
+        ]])],
+      octave_cv_func_qprinter_setpagesize=yes,
+      octave_cv_func_qprinter_setpagesize=no)
+    CPPFLAGS="$ac_octave_save_CPPFLAGS"
+    CXXFLAGS="$ac_octave_save_CXXFLAGS"
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_func_qprinter_setpagesize = yes; then
+    AC_DEFINE(HAVE_QPRINTER_SETPAGESIZE, 1,
+      [Define to 1 if you have the 'QPrinter::setPageSize' member function.])
+  fi
+])
+dnl
 dnl Check whether the Qt class QScreen has the devicePixelRatio member function.
 dnl This member function was introduced in Qt 5.5.
 dnl
@@ -827,78 +700,6 @@
   fi
 ])
 dnl
-dnl Check whether the Qt class QTabWidget has the setMovable member function.
-dnl This member function was introduced in Qt 4.5.
-dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.5 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QTABWIDGET_SETMOVABLE], [
-  AC_CACHE_CHECK([for QTabWidget::setMovable in <QTabWidget>],
-    [octave_cv_func_qtabwidget_setmovable],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QTabWidget>
-        class tab_widget : public QTabWidget
-        {
-        public:
-          tab_widget (QWidget *parent = 0) : QTabWidget (parent) { this->setMovable (true); }
-          ~tab_widget () {}
-        };
-        ]], [[
-        tab_widget tw;
-        ]])],
-      octave_cv_func_qtabwidget_setmovable=yes,
-      octave_cv_func_qtabwidget_setmovable=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qtabwidget_setmovable = yes; then
-    AC_DEFINE(HAVE_QTABWIDGET_SETMOVABLE, 1,
-      [Define to 1 if you have the `QTabWidget::setMovable' member function.])
-  fi
-])
-dnl
-dnl Check whether the Qt class QHelpEngine has the documentsForIdentifier
-dnl function.  dnl This member function was introduced in Qt 5.15.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QHELPENGINE_DOCUMENTSFORIDENTIFIER], [
-  AC_CACHE_CHECK([for QHelpEngine::documentsForIdentifier in <QHelpEngine>],
-    [octave_cv_func_qhelpengine_documentsforidentifier],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QHelpEngine>
-        #include <QHelpLink>
-        #include <QList>
-        #include <QString>
-        #include <QUrl>
-        ]], [[
-        QString collection_file;
-        QHelpEngine eng (collection_file);
-        QString id;
-        eng.documentsForIdentifier (id);
-        ]])],
-      octave_cv_func_qhelpengine_documentsforidentifier=yes,
-      octave_cv_func_qhelpengine_documentsforidentifier=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qhelpengine_documentsforidentifier = yes; then
-    AC_DEFINE(HAVE_QHELPENGINE_DOCUMENTSFORIDENTIFIER, 1,
-      [Define to 1 if you have the `QHelpEngine::documentsForIdentifier' member function.])
-  fi
-])
-dnl
 dnl Check whether the Qt class QWheelEvent has the angleDelta member function.
 dnl This member function was introduced in Qt 5.
 dnl
@@ -961,198 +762,6 @@
   fi
 ])
 dnl
-dnl Check whether Qt message handler function accepts QMessageLogContext
-dnl argument.  This change was introduced in Qt 5.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT], [
-  AC_CACHE_CHECK([whether Qt message handler accepts QMessageLogContext],
-    [octave_cv_func_qtmessagehandler_accepts_qmessagelogcontext],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QtGlobal>
-        static void
-        msg_handler (QtMsgType, const QMessageLogContext &, const QString &)
-        { }
-        ]], [[
-        QtMessageHandler fptr = msg_handler;
-        ]])],
-      octave_cv_func_qtmessagehandler_accepts_qmessagelogcontext=yes,
-      octave_cv_func_qtmessagehandler_accepts_qmessagelogcontext=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qtmessagehandler_accepts_qmessagelogcontext = yes; then
-    AC_DEFINE(QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT, 1,
-      [Define to 1 if Qt message handler accepts 'QMessageLogContext' argument.])
-  fi
-])
-dnl
-dnl Check whether the Qt class QList has a constructor that accepts
-dnl a pair of iterators.  This constructor was introduced in Qt 5.14.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QLIST_ITERATOR_CONSTRUCTOR], [
-  AC_CACHE_CHECK([for QList<T>::QList (iterator, iterator) constructor],
-    [octave_cv_func_qlist_iterator_constructor],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QList>
-        ]], [[
-        QList<int> lst_one;
-        QList<int> lst_two (lst_one.begin (), lst_one.end ());
-        ]])],
-      octave_cv_func_qlist_iterator_constructor=yes,
-      octave_cv_func_qlist_iterator_constructor=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qlist_iterator_constructor = yes; then
-    AC_DEFINE(HAVE_QLIST_ITERATOR_CONSTRUCTOR, 1,
-      [Define to 1 if you have the `QList<T>::QList (iterator, iterator)' constructor.])
-  fi
-])
-dnl
-dnl Check whether the Qt class QRegion has the iterators and related
-dnl functions introduced in Qt 5.8.
-dnl
-AC_DEFUN([OCTAVE_CHECK_QREGION_ITERATORS], [
-  AC_CACHE_CHECK([for QRegion iterators and related functions],
-    [octave_cv_qregion_iterators],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QRegion>
-        ]], [[
-        QRegion region;
-        QRegion::const_iterator it;
-        it = region.begin ();
-        it = region.end ();
-        it = region.cbegin ();
-        it = region.cend ();
-        QRegion::const_reverse_iterator rit;
-        rit = region.rbegin ();
-        rit = region.rend ();
-        rit = region.crbegin ();
-        rit = region.crend ();
-        ]])],
-      octave_cv_qregion_iterators=yes,
-      octave_cv_qregion_iterators=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_qregion_iterators = yes; then
-    AC_DEFINE(HAVE_QREGION_ITERATORS, 1,
-      [Define to 1 if you have the `QFontMetrics::horizontalAdvance' function.])
-  fi
-])
-dnl
-dnl Check whether the Qt::SplitBehavior enum exists and has
-dnl Qt::KeepEmptyParts and Qt::SkipEmptyParts members.  This enum
-dnl was introduced or modified in Qt 5.14.
-dnl
-AC_DEFUN([OCTAVE_CHECK_QT_SPLITBEHAVIOR_ENUM], [
-  AC_CACHE_CHECK([for Qt::SplitBehavior enum],
-    [octave_cv_qt_splitbehavior_enum],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <Qt>
-        ]], [[
-        Qt::SplitBehavior sb_keep = Qt::KeepEmptyParts;
-        Qt::SplitBehavior sb_skip = Qt::SkipEmptyParts;
-        ]])],
-      octave_cv_qt_splitbehavior_enum=yes,
-      octave_cv_qt_splitbehavior_enum=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_qt_splitbehavior_enum = yes; then
-    AC_DEFINE(HAVE_QT_SPLITBEHAVIOR_ENUM, 1,
-      [Define to 1 if you have the `Qt::SplitBehavior' enum.])
-  fi
-])
-dnl
-dnl Check whether the Qt class QFontDatabase has the systemFont member
-dnl function.  This function was introduced in Qt 5.2.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QFONTDATABASE_SYSTEMFONT], [
-  AC_CACHE_CHECK([for QFontDatabase::systemFont function],
-    [octave_cv_func_qfontdatabase_systemfont],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QFontDatabase>
-        #include <QFont>
-        ]], [[
-        QFont font = QFontDatabase::systemFont (QFontDatabase::FixedFont);
-        ]])],
-      octave_cv_func_qfontdatabase_systemfont=yes,
-      octave_cv_func_qfontdatabase_systemfont=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qfontdatabase_systemfont = yes; then
-    AC_DEFINE(HAVE_QFONTDATABASE_SYSTEMFONT, 1,
-      [Define to 1 if you have the `QFontDatabase::systemFont' function.])
-  fi
-])
-dnl
-dnl Check whether the Qt class QList has a constructor that accepts
-dnl a pair of iterators.  This constructor was introduced in Qt 5.14.
-dnl
-AC_DEFUN([OCTAVE_CHECK_FUNC_QFONTMETRICS_HORIZONTAL_ADVANCE], [
-  AC_CACHE_CHECK([for QFontMetrics::horizontalAdvance function],
-    [octave_cv_func_qfontmetrics_horizontal_advance],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QFont>
-        #include <QFontMetrics>
-        #include <QString>
-        ]], [[
-        QFont font;
-        QFontMetrics fm (font);
-        fm.horizontalAdvance ('x');
-        fm.horizontalAdvance (QString ("string"));
-        ]])],
-      octave_cv_func_qfontmetrics_horizontal_advance=yes,
-      octave_cv_func_qfontmetrics_horizontal_advance=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_func_qfontmetrics_horizontal_advance = yes; then
-    AC_DEFINE(HAVE_QFONTMETRICS_HORIZONTAL_ADVANCE, 1,
-      [Define to 1 if you have the `QFontMetrics::horizontalAdvance' function.])
-  fi
-])
-dnl
 dnl Check whether HDF5 library has version 1.6 API functions.
 dnl
 AC_DEFUN([OCTAVE_CHECK_HDF5_HAS_VER_16_API], [
@@ -1206,7 +815,7 @@
     no)
       ifelse([$#], 10,
         [AC_MSG_ERROR([--without-m4_tolower($1) specified but $2 is required.])],
-        [warn_$1="--without-m4_tolower($1) specified.  Functions or features that depend on $2 will be disabled."
+        [warn_$1=""
          m4_toupper([$1])_LIBS=])
     ;;
     yes | "")
@@ -1790,63 +1399,6 @@
   fi
 ])
 dnl
-dnl Check whether Qhull works (does not crash).
-dnl
-AC_DEFUN([OCTAVE_CHECK_LIB_QHULL_OK], [
-  AC_CACHE_CHECK([whether the qhull library works],
-    [octave_cv_lib_qhull_ok],
-    [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
-        #include <stdio.h>
-        #if defined (HAVE_LIBQHULL_LIBQHULL_H)
-        # include <libqhull/libqhull.h>
-        # include <libqhull/qset.h>
-        # include <libqhull/geom.h>
-        # include <libqhull/poly.h>
-        # include <libqhull/io.h>
-        #elif defined (HAVE_QHULL_LIBQHULL_H) || defined (HAVE_QHULL_QHULL_H)
-        # if defined (HAVE_QHULL_LIBQHULL_H)
-        #  include <qhull/libqhull.h>
-        # else
-        #  include <qhull/qhull.h>
-        # endif
-        # include <qhull/qset.h>
-        # include <qhull/geom.h>
-        # include <qhull/poly.h>
-        # include <qhull/io.h>
-        #elif defined (HAVE_LIBQHULL_H) || defined (HAVE_QHULL_H)
-        # if defined (HAVE_LIBQHULL_H)
-        #  include <libqhull.h>
-        # else
-        #  include <qhull.h>
-        # endif
-        # include <qset.h>
-        # include <geom.h>
-        # include <poly.h>
-        # include <io.h>
-        #endif
-        #if defined (NEED_QHULL_VERSION)
-          char *qh_version = "version";
-        #endif
-        ]], [[
-        int dim = 2;
-        int n = 4;
-        coordT points[8] = { -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5 };
-        boolT ismalloc = 0;
-        return qh_new_qhull (dim, n, points, ismalloc, "qhull ", 0, stderr);
-      ]])],
-      octave_cv_lib_qhull_ok=yes,
-      octave_cv_lib_qhull_ok=no,
-      octave_cv_lib_qhull_ok=yes)
-  ])
-  if test $octave_cv_lib_qhull_ok = yes; then
-    $1
-    :
-  else
-    $2
-    :
-  fi
-])
-dnl
 dnl Check whether PCRE is compiled with --enable-utf.
 dnl
 AC_DEFUN([OCTAVE_CHECK_LIB_PCRE_OK], [
@@ -1881,6 +1433,51 @@
   fi
 ])
 dnl
+dnl Check whether Qhull works (does not crash).
+dnl
+AC_DEFUN([OCTAVE_CHECK_LIB_QHULL_OK], [
+  AC_CACHE_CHECK([whether the qhull_r library works],
+    [octave_cv_lib_qhull_r_ok],
+    [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+        #include <stdio.h>
+        #if defined (HAVE_LIBQHULL_R_LIBQHULL_R_H)
+        # include <libqhull_r/libqhull_r.h>
+        # include <libqhull_r/qset_r.h>
+        # include <libqhull_r/geom_r.h>
+        # include <libqhull_r/poly_r.h>
+        # include <libqhull_r/io_r.h>
+        #elif defined (HAVE_LIBQHULL_R_H)
+        # include <libqhull_r.h>
+        # include <qset_r.h>
+        # include <geom_r.h>
+        # include <poly_r.h>
+        # include <io_r.h>
+        #endif
+        #if defined (NEED_QHULL_R_VERSION)
+          char *qh_version = "version";
+        #endif
+        ]], [[
+        int dim = 2;
+        int n = 4;
+        coordT points[8] = { -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5 };
+        boolT ismalloc = 0;
+        qhT context = { };
+        qhT* qh = &context;
+        return qh_new_qhull (qh, dim, n, points, ismalloc, "qhull ", 0, stderr);
+      ]])],
+      octave_cv_lib_qhull_r_ok=yes,
+      octave_cv_lib_qhull_r_ok=no,
+      octave_cv_lib_qhull_r_ok=yes)
+  ])
+  if test $octave_cv_lib_qhull_r_ok = yes; then
+    $1
+    :
+  else
+    $2
+    :
+  fi
+])
+dnl
 dnl Check whether sndfile library is modern enough to include things like Ogg
 dnl
 AC_DEFUN([OCTAVE_CHECK_LIB_SNDFILE_OK], [
@@ -1934,141 +1531,137 @@
   AC_SUBST(TERM_LIBS)
 ])
 dnl
-dnl Check whether the Qt class QFont has the ForceIntegerMetrics enumerated
-dnl type member.  This property was introduced in Qt 4.7.
+dnl Check whether new API is used with QHelpIndexWidget.
+dnl Under new API, QHelpIndexWidget emits documentActivates.
+dnl Under old API, QHelpIndexWidget emits linkActivated.
+dnl New structure/signal API was introduced in Qt 5.15.
 dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.7 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
+dnl FIXME: Delete this entirely when we drop support for Qt 5.14 or older.
 dnl
-AC_DEFUN([OCTAVE_CHECK_MEMBER_QFONT_FORCE_INTEGER_METRICS], [
-  AC_CACHE_CHECK([for QFont::ForceIntegerMetrics in <QFont>],
-    [octave_cv_decl_qfont_force_integer_metrics],
+AC_DEFUN([OCTAVE_CHECK_NEW_QHELPINDEXWIDGET_API], [
+  AC_CACHE_CHECK([for new QHelpIndexWidget API],
+    [octave_cv_new_qhelpindexwidget_api],
     [AC_LANG_PUSH(C++)
     ac_octave_save_CPPFLAGS="$CPPFLAGS"
     ac_octave_save_CXXFLAGS="$CXXFLAGS"
     CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
+    CXXFLAGS="$CXXPICFLAG $CPPFLAGS"
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QFont>
+        #include <QHelpLink>
         ]], [[
-        QFont::StyleStrategy strategy = QFont::ForceIntegerMetrics;
+        QHelpLink link;
         ]])],
-      octave_cv_decl_qfont_force_integer_metrics=yes,
-      octave_cv_decl_qfont_force_integer_metrics=no)
+      octave_cv_new_qhelpindexwidget_api=yes,
+      octave_cv_new_qhelpindexwidget_api=no)
     CPPFLAGS="$ac_octave_save_CPPFLAGS"
     CXXFLAGS="$ac_octave_save_CXXFLAGS"
     AC_LANG_POP(C++)
   ])
-  if test $octave_cv_decl_qfont_force_integer_metrics = yes; then
-    AC_DEFINE(HAVE_QFONT_FORCE_INTEGER_METRICS, 1,
-      [Define to 1 if `ForceIntegerMetrics' is a member of `QFont'.])
+  if test $octave_cv_new_qhelpindexwidget_api = yes; then
+    AC_DEFINE(HAVE_NEW_QHELPINDEXWIDGET_API, 1,
+      [Define to 1 if using new QHelpIndexWidget API.])
   fi
 ])
 dnl
-dnl Check whether the Qt class QFont has the Monospace enumerated type member.
-dnl This property was introduced in Qt 4.7.
+dnl Check for the Qhull version.
 dnl
-dnl FIXME: Delete this entirely when we can safely assume that Qt 4.7 or later
-dnl is in use everywhere, or when we drop support for Qt 4.
+AC_DEFUN([OCTAVE_CHECK_QHULL_VERSION], [
+  AC_CACHE_CHECK([for qh_version in $QHULL_R_LIBS],
+    [octave_cv_lib_qhull_r_version],
+    [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+        #include <stdio.h>
+        #if defined (HAVE_LIBQHULL_R_LIBQHULL_R_H)
+        # include <libqhull_r/libqhull_r.h>
+        # include <libqhull_r/qset_r.h>
+        # include <libqhull_r/geom_r.h>
+        # include <libqhull_r/poly_r.h>
+        # include <libqhull_r/io_r.h>
+        #elif defined (HAVE_LIBQHULL_R_H)
+        # include <libqhull_r.h>
+        # include <qset_r.h>
+        # include <geom_r.h>
+        # include <poly_r.h>
+        # include <io_r.h>
+        #endif
+        ]], [[
+        const char *tmp = qh_version;
+      ]])],
+      octave_cv_lib_qhull_r_version=yes, octave_cv_lib_qhull_r_version=no)
+  ])
+  if test $octave_cv_lib_qhull_r_version = no; then
+    AC_DEFINE(NEED_QHULL_R_VERSION, 1,
+      [Define to 1 if the Qhull library needs a qh_version variable defined.])
+  fi
+])
 dnl
-AC_DEFUN([OCTAVE_CHECK_MEMBER_QFONT_MONOSPACE], [
-  AC_CACHE_CHECK([for QFont::Monospace in <QFont>],
-    [octave_cv_decl_qfont_monospace],
+dnl Check whether Qt has the QOverload template introduced in Qt 5.7.
+dnl
+AC_DEFUN([OCTAVE_CHECK_QOVERLOAD_TEMPLATE], [
+  AC_CACHE_CHECK([for QOverload template],
+    [octave_cv_qoverload_template],
     [AC_LANG_PUSH(C++)
     ac_octave_save_CPPFLAGS="$CPPFLAGS"
     ac_octave_save_CXXFLAGS="$CXXFLAGS"
     CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
     CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QFont>
+        #include <QtGlobal>
         ]], [[
-        QFont::StyleHint hint = QFont::Monospace;
+        struct Foo
+        {
+            void overloadedFunction (int) const;
+            void overloadedFunction (int, const QString &) const;
+        };
+        QOverload<int>::of (&Foo::overloadedFunction);
+        QOverload<int, const QString &>::of (&Foo::overloadedFunction);
         ]])],
-      octave_cv_decl_qfont_monospace=yes,
-      octave_cv_decl_qfont_monospace=no)
+      octave_cv_qoverload_template=yes,
+      octave_cv_qoverload_template=no)
     CPPFLAGS="$ac_octave_save_CPPFLAGS"
     CXXFLAGS="$ac_octave_save_CXXFLAGS"
     AC_LANG_POP(C++)
   ])
-  if test $octave_cv_decl_qfont_monospace = yes; then
-    AC_DEFINE(HAVE_QFONT_MONOSPACE, 1,
-      [Define to 1 if `Monospace' is a member of `QFont'.])
+  if test $octave_cv_qoverload_template = yes; then
+    AC_DEFINE(HAVE_QOVERLOAD_TEMPLATE, 1,
+      [Define to 1 if you have the `QOverload' template.])
   fi
 ])
 dnl
-dnl Check whether QVariant::canConvert accepts a QMetaType::Type
-dnl enumeration value as an argument.
+dnl Check whether the Qt class QRegion has the iterators and related
+dnl functions introduced in Qt 5.8.
 dnl
-AC_DEFUN([OCTAVE_CHECK_QVARIANT_CANCONVERT_ACCEPTS_QMETATYPE_TYPE], [
-  AC_CACHE_CHECK([whether QVariant::canConvert accepts QMetaType::Type argument],
-    [octave_cv_qvariant_canconvert_accepts_qmetatype_type],
+AC_DEFUN([OCTAVE_CHECK_QREGION_ITERATORS], [
+  AC_CACHE_CHECK([for QRegion iterators and related functions],
+    [octave_cv_qregion_iterators],
     [AC_LANG_PUSH(C++)
     ac_octave_save_CPPFLAGS="$CPPFLAGS"
     ac_octave_save_CXXFLAGS="$CXXFLAGS"
     CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
     CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
     AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QMetaType>
-        #include <QVariant>
+        #include <QRegion>
         ]], [[
-        QVariant var;
-        QMetaType::Type type = QMetaType::QString;
-        var.canConvert (type);
+        QRegion region;
+        QRegion::const_iterator it;
+        it = region.begin ();
+        it = region.end ();
+        it = region.cbegin ();
+        it = region.cend ();
+        QRegion::const_reverse_iterator rit;
+        rit = region.rbegin ();
+        rit = region.rend ();
+        rit = region.crbegin ();
+        rit = region.crend ();
         ]])],
-      octave_cv_qvariant_canconvert_accepts_qmetatype_type=yes,
-      octave_cv_qvariant_canconvert_accepts_qmetatype_type=no)
+      octave_cv_qregion_iterators=yes,
+      octave_cv_qregion_iterators=no)
     CPPFLAGS="$ac_octave_save_CPPFLAGS"
     CXXFLAGS="$ac_octave_save_CXXFLAGS"
     AC_LANG_POP(C++)
   ])
-  if test $octave_cv_qvariant_canconvert_accepts_qmetatype_type = yes; then
-    AC_DEFINE(QVARIANT_CANCONVERT_ACCEPTS_QMETATYPE_TYPE, 1,
-      [Define to 1 if `QVariant::canConvert' accepts `QMetaType::Type' enumeration value as argument.])
-  fi
-])
-dnl
-dnl Check for the Qhull version.
-dnl
-AC_DEFUN([OCTAVE_CHECK_QHULL_VERSION], [
-  AC_CACHE_CHECK([for qh_version in $QHULL_LIBS],
-    [octave_cv_lib_qhull_version],
-    [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-        #include <stdio.h>
-        #if defined (HAVE_LIBQHULL_LIBQHULL_H)
-        # include <libqhull/libqhull.h>
-        # include <libqhull/qset.h>
-        # include <libqhull/geom.h>
-        # include <libqhull/poly.h>
-        # include <libqhull/io.h>
-        #elif defined (HAVE_QHULL_LIBQHULL_H) || defined (HAVE_QHULL_QHULL_H)
-        # if defined (HAVE_QHULL_LIBQHULL_H)
-        #  include <qhull/libqhull.h>
-        # else
-        #  include <qhull/qhull.h>
-        # endif
-        # include <qhull/qset.h>
-        # include <qhull/geom.h>
-        # include <qhull/poly.h>
-        # include <qhull/io.h>
-        #elif defined (HAVE_LIBQHULL_H) || defined (HAVE_QHULL_H)
-        # if defined (HAVE_LIBQHULL_H)
-        #  include <libqhull.h>
-        # else
-        #  include <qhull.h>
-        # endif
-        # include <qset.h>
-        # include <geom.h>
-        # include <poly.h>
-        # include <io.h>
-        #endif
-        ]], [[
-        const char *tmp = qh_version;
-      ]])],
-      octave_cv_lib_qhull_version=yes, octave_cv_lib_qhull_version=no)
-  ])
-  if test $octave_cv_lib_qhull_version = no; then
-    AC_DEFINE(NEED_QHULL_VERSION, 1,
-      [Define to 1 if the Qhull library needs a qh_version variable defined.])
+  if test $octave_cv_qregion_iterators = yes; then
+    AC_DEFINE(HAVE_QREGION_ITERATORS, 1,
+      [Define to 1 if you have the `QFontMetrics::horizontalAdvance' function.])
   fi
 ])
 dnl
@@ -2081,9 +1674,6 @@
 
   ## Check for Qt libraries
   case "$qt_version" in
-    4)
-      octave_qscintilla_libnames="qscintilla2-qt4 qscintilla2_qt4 qt4scintilla2 qscintilla2"
-    ;;
     5)
       octave_qscintilla_libnames="qscintilla2-qt5 qscintilla2_qt5 qt5scintilla2"
     ;;
@@ -2209,11 +1799,6 @@
 
   if test $build_qt_gui = yes; then
     BUILD_QT_SUMMARY_MSG="yes (version: $have_qt_version)"
-    if test x"$have_qt_version" = x4; then
-      AC_DEFINE(HAVE_QT4, 1, [Define to 1 if using Qt version 4.])
-      warn_qt_ver="Use of Qt version 4 is deprecated.  Support will be removed in Octave version 7."
-      OCTAVE_CONFIGURE_WARNING([warn_qt_ver])
-    fi
     if test x"$have_qt_version" = x5; then
       AC_DEFINE(HAVE_QT5, 1, [Define to 1 if using Qt version 5.])
     fi
@@ -2374,6 +1959,36 @@
   fi
 ])
 dnl
+dnl Check whether the Qt::SplitBehavior enum exists and has
+dnl Qt::KeepEmptyParts and Qt::SkipEmptyParts members.  This enum
+dnl was introduced or modified in Qt 5.14.
+dnl
+AC_DEFUN([OCTAVE_CHECK_QT_SPLITBEHAVIOR_ENUM], [
+  AC_CACHE_CHECK([for Qt::SplitBehavior enum],
+    [octave_cv_qt_splitbehavior_enum],
+    [AC_LANG_PUSH(C++)
+    ac_octave_save_CPPFLAGS="$CPPFLAGS"
+    ac_octave_save_CXXFLAGS="$CXXFLAGS"
+    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
+    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+        #include <Qt>
+        ]], [[
+        Qt::SplitBehavior sb_keep = Qt::KeepEmptyParts;
+        Qt::SplitBehavior sb_skip = Qt::SkipEmptyParts;
+        ]])],
+      octave_cv_qt_splitbehavior_enum=yes,
+      octave_cv_qt_splitbehavior_enum=no)
+    CPPFLAGS="$ac_octave_save_CPPFLAGS"
+    CXXFLAGS="$ac_octave_save_CXXFLAGS"
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_qt_splitbehavior_enum = yes; then
+    AC_DEFINE(HAVE_QT_SPLITBEHAVIOR_ENUM, 1,
+      [Define to 1 if you have the `Qt::SplitBehavior' enum.])
+  fi
+])
+dnl
 dnl OCTAVE_CHECK_QT_TOOL(TOOL)
 dnl
 AC_DEFUN([OCTAVE_CHECK_QT_TOOL], [
@@ -2421,13 +2036,9 @@
 
   ## Check for Qt libraries
   case "$qt_version" in
-    4)
-      QT_OPENGL_MODULE="QtOpenGL"
-      QT_MODULES="QtCore QtGui QtNetwork QtHelp QtXml"
-    ;;
     5)
       QT_OPENGL_MODULE="Qt5OpenGL"
-      QT_MODULES="Qt5Core Qt5Gui Qt5Network Qt5PrintSupport Qt5Help Qt5Xml"
+      QT_MODULES="Qt5Core Qt5Gui Qt5Help Qt5Network Qt5PrintSupport Qt5Xml"
     ;;
     *)
       AC_MSG_ERROR([Unrecognized Qt version $qt_version])
@@ -2471,19 +2082,13 @@
           QT_OPENGL_LIBS="`$PKG_CONFIG --libs-only-other $QT_OPENGL_MODULE | tr ' ' '\n' | $GREP -v -e '-F' | uniq | tr '\n' ' '`"
           ## Enabling link_all_deps works around libtool's imperfect handling
           ## of the -F flag
-          AM_CONDITIONAL([AMCOND_LINK_ALL_DEPS],
-                         [test $link_all_deps = yes || test -n "$QT_LDFLAGS"])
+          if test -n "$QT_LDFLAGS"; then
+            link_all_deps=yes
+          fi
+          AM_CONDITIONAL([AMCOND_LINK_ALL_DEPS], [test $link_all_deps = yes])
         fi
       ;;
     esac
-
-    if test $qt_version = 4; then
-      ## Check for Qt4
-      if ! `$PKG_CONFIG --atleast-version=4.0.0 QtCore`; then
-        build_qt_gui=no
-        warn_qt_version="Qt >= 4.0.0 not found; disabling Qt GUI"
-      fi
-    fi
   fi
 
   QT_TOOLS_AVAILABLE=
@@ -2548,18 +2153,6 @@
   fi
 
   if test $build_qt_gui = yes; then
-    OCTAVE_CHECK_FUNC_QABSTRACTITEMMODEL_BEGINRESETMODEL
-
-    if test $octave_cv_func_qabstractitemmodel_beginresetmodel = no; then
-      build_qt_gui=no
-      warn_qt_abstract_item_model="QAbstractItemModel::beginResetModel not found; disabling Qt GUI"
-      ## Invalidate cache so that this test will be done again if we
-      ## perform the test with a different Qt version.
-      $as_unset octave_cv_func_qabstractitemmodel_beginresetmodel
-    fi
-  fi
-
-  if test $build_qt_gui = yes; then
     ## We have what we need to build the Qt GUI.  The remaining
     ## checks below are for optional features related to the Qt GUI.
 
@@ -2577,32 +2170,19 @@
     ## tests if they fail because we have already decided that the Qt
     ## version that we are testing now will be the one used.
 
-    OCTAVE_CHECK_FUNC_QCOMBOBOX_SETCURRENTTEXT
-    OCTAVE_CHECK_FUNC_QFONTDATABASE_SYSTEMFONT
     OCTAVE_CHECK_FUNC_QFONTMETRICS_HORIZONTAL_ADVANCE
     OCTAVE_CHECK_FUNC_QGUIAPPLICATION_SETDESKTOPFILENAME
-    OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONRESIZEMODE
-    OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONSCLICKABLE
-    OCTAVE_CHECK_FUNC_QHEADERVIEW_SETSECTIONSMOVABLE
     OCTAVE_CHECK_FUNC_QHELPSEARCHQUERYWIDGET_SEARCHINPUT
     OCTAVE_CHECK_NEW_QHELPINDEXWIDGET_API
-    OCTAVE_CHECK_FUNC_QINSTALLMESSAGEHANDLER
-    OCTAVE_CHECK_FUNC_QLINEEDIT_SETPLACEHOLDERTEXT
     OCTAVE_CHECK_FUNC_QLIST_ITERATOR_CONSTRUCTOR
-    OCTAVE_CHECK_FUNC_QMOUSEEVENT_LOCALPOS
-    OCTAVE_CHECK_FUNC_QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS
     OCTAVE_CHECK_FUNC_QMAINWINDOW_RESIZEDOCKS
+    OCTAVE_CHECK_FUNC_QPRINTER_SETPAGESIZE
     OCTAVE_CHECK_FUNC_QSCREEN_DEVICEPIXELRATIO
-    OCTAVE_CHECK_FUNC_QTABWIDGET_SETMOVABLE
-    OCTAVE_CHECK_FUNC_QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT
     OCTAVE_CHECK_FUNC_QHELPENGINE_DOCUMENTSFORIDENTIFIER
     OCTAVE_CHECK_FUNC_QWHEELEVENT_ANGLEDELTA
     OCTAVE_CHECK_FUNC_QWHEELEVENT_POSITION
-    OCTAVE_CHECK_MEMBER_QFONT_FORCE_INTEGER_METRICS
-    OCTAVE_CHECK_MEMBER_QFONT_MONOSPACE
-    OCTAVE_CHECK_QVARIANT_CANCONVERT_ACCEPTS_QMETATYPE_TYPE
-    OCTAVE_HAVE_QGUIAPPLICATION
 
+    OCTAVE_CHECK_QOVERLOAD_TEMPLATE
     OCTAVE_CHECK_QREGION_ITERATORS
     OCTAVE_CHECK_QT_SPLITBEHAVIOR_ENUM
 
@@ -2675,7 +2255,7 @@
   ac_octave_save_LIBS=$LIBS
   LIBS="$SUNDIALS_IDA_LIBS $SUNDIALS_NVECSERIAL_LIBS $LIBS"
   dnl Current API functions present in SUNDIALS version 4
-  AC_CHECK_FUNCS([IDASetJacFn IDASetLinearSolver SUNLinSol_Dense])
+  AC_CHECK_FUNCS([IDASetJacFn IDASetLinearSolver SUNLinSol_Dense SUNSparseMatrix_Reallocate])
   dnl FIXME: The purpose of the following tests is to detect the deprecated
   dnl API from SUNDIALS version 3, which should only be used if the current
   dnl API tests above failed. For now, always test for ida_direct.h.
@@ -2726,6 +2306,22 @@
   fi
 ])
 dnl
+dnl Check whether SUNDIALS IDA library has the SUNLINSOL_DENSE linear solver.
+dnl
+AC_DEFUN([OCTAVE_CHECK_SUNDIALS_SUNLINSOL_DENSE], [
+  AC_CHECK_HEADERS([sunlinsol/sunlinsol_dense.h],
+      octave_cv_sundials_sunlinsol_dense=yes,
+      octave_cv_sundials_sunlinsol_dense=no)
+    ])
+  if test $octave_cv_sundials_sunlinsol_dense = yes; then
+    AC_DEFINE(HAVE_SUNDIALS_SUNLINSOL_DENSE, 1,
+      [Define to 1 if SUNDIALS IDA includes the SUNLINSOL_DENSE linear solver.])
+  else
+    warn_sundials_disabled="SUNDIALS IDA library does not include the SUNLINSOL_DENSE linear solver.  The solvers ode15i and ode15s will be disabled."
+    OCTAVE_CONFIGURE_WARNING([warn_sundials_disabled])
+  fi
+])
+dnl
 dnl Check whether SUNDIALS IDA library is configured with SUNLINSOL_KLU
 dnl enabled.
 dnl
@@ -2787,21 +2383,14 @@
   fi
 ])
 dnl
-dnl Check whether SUNDIALS IDA library has the SUNLINSOL_DENSE linear solver.
+dnl Like AC_CONFIG_FILES, but don't touch the output file if it already
+dnl exists and hasn't changed.
 dnl
-AC_DEFUN([OCTAVE_CHECK_SUNDIALS_SUNLINSOL_DENSE], [
-  AC_CHECK_HEADERS([sunlinsol/sunlinsol_dense.h],
-      octave_cv_sundials_sunlinsol_dense=yes,
-      octave_cv_sundials_sunlinsol_dense=no)
-    ])
-  if test $octave_cv_sundials_sunlinsol_dense = yes; then
-    AC_DEFINE(HAVE_SUNDIALS_SUNLINSOL_DENSE, 1,
-      [Define to 1 if SUNDIALS IDA includes the SUNLINSOL_DENSE linear solver.])
-  else
-    warn_sundials_disabled="SUNDIALS IDA library does not include the SUNLINSOL_DENSE linear solver.  The solvers ode15i and ode15s will be disabled."
-    OCTAVE_CONFIGURE_WARNING([warn_sundials_disabled])
-  fi
-])
+AC_DEFUN([OCTAVE_CONFIG_MOVE_IF_CHANGE_FILES], [
+  m4_foreach_w([elt], [$1], [
+    AC_CONFIG_FILES(elt[-tmp:]patsubst(elt, [.sh$], [.in.sh]))
+    AC_CONFIG_COMMANDS(elt,
+    [$SHELL $srcdir/build-aux/move-if-change ]elt[-tmp ]elt)])])
 dnl
 dnl Add warning to final summary.
 dnl
@@ -2820,15 +2409,6 @@
     fi])
 ])
 dnl
-dnl Like AC_CONFIG_FILES, but don't touch the output file if it already
-dnl exists and hasn't changed.
-dnl
-AC_DEFUN([OCTAVE_CONFIG_MOVE_IF_CHANGE_FILES], [
-  m4_foreach_w([elt], [$1], [
-    AC_CONFIG_FILES(elt[-tmp:]patsubst(elt, [.sh$], [.in.sh]))
-    AC_CONFIG_COMMANDS(elt,
-    [$SHELL $srcdir/build-aux/move-if-change ]elt[-tmp ]elt)])])
-dnl
 dnl Check if the C++ library has the bit_and, bit_or, and bit_xor
 dnl templates defined.
 dnl
@@ -2952,6 +2532,208 @@
   fi
 ])
 dnl
+dnl OCTAVE_DEFINE_MKOCTFILE_DYNAMIC_LINK_OPTIONS
+dnl
+dnl Requires the following variables to already be set:
+dnl
+dnl   AR
+dnl   CFLAGS
+dnl   CXX
+dnl   CXXFLAGS
+dnl   EXEEXT
+dnl   GCC
+dnl   GREP
+dnl   GXX
+dnl   LDFLAGS
+dnl   ac_cv_f77_compiler_gnu
+dnl   ac_top_build_prefix
+dnl   canonical_host_type
+dnl   have_msvc
+dnl
+AC_DEFUN_ONCE([OCTAVE_DEFINE_MKOCTFILE_DYNAMIC_LINK_OPTIONS], [
+  ### Set system-dependent options for building shared libraries.
+  ### These are used by mkoctfile to create dynamically loadable
+  ### .oct and .mex files.  It would be great if we could somehow
+  ### use libtool to get this information.
+
+  CPICFLAG=-fPIC
+  CXXPICFLAG=-fPIC
+  FPICFLAG=-fPIC
+  SH_LDFLAGS=-shared
+  DL_LDFLAGS="${SH_LDFLAGS}"
+  MKOCTFILE_DL_LDFLAGS="${DL_LDFLAGS}"
+  NO_OCT_FILE_STRIP=false
+  TEMPLATE_AR="${AR}"
+  TEMPLATE_ARFLAGS="${ARFLAGS}"
+  library_path_var=LD_LIBRARY_PATH
+  ldpreloadsep=" "
+  case $canonical_host_type in
+    *-*-386bsd* | *-*-netbsd*)
+      SH_LDFLAGS=-Bshareable
+    ;;
+    *-*-openbsd*)
+      SH_LDFLAGS="-shared -fPIC"
+    ;;
+    *-*-freebsd*)
+      SH_LDFLAGS="-shared -Wl,-x"
+    ;;
+    alpha*-dec-osf*)
+      CPICFLAG=
+      CXXPICFLAG=
+      FPICFLAG=
+      SH_LDFLAGS="-shared -Wl,-expect_unresolved -Wl,'*'"
+    ;;
+    *-*-darwin*)
+      DL_LDFLAGS="-bundle -undefined dynamic_lookup -bind_at_load -bundle_loader ${ac_top_build_prefix}libinterp/octave ${LDFLAGS}"
+      dnl Contains variables that are defined and undefined at this point, so use
+      dnl appropriate quoting to defer expansion of ${bindir} and ${version}.
+      MKOCTFILE_DL_LDFLAGS='-bundle -undefined dynamic_lookup -bind_at_load -bundle_loader ${bindir}/octave-${version}'"${EXEEXT}"
+      SH_LDFLAGS="-dynamiclib -single_module ${LDFLAGS}"
+      case $canonical_host_type in
+        powerpc-*)
+          CXXPICFLAG=
+          CPICFLAG=
+          FPICFLAG=
+        ;;
+      esac
+      NO_OCT_FILE_STRIP=true
+      library_path_var=DYLD_LIBRARY_PATH
+    ;;
+    *-*-cygwin*)
+      CPICFLAG=
+      CXXPICFLAG=
+      FPICFLAG=
+      DL_LDFLAGS="-shared -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--enable-runtime-pseudo-reloc"
+      SH_LDFLAGS="-shared -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--enable-auto-image-base"
+      ldpreloadsep=":"
+    ;;
+    *-*-mingw*)
+      if test $have_msvc = yes; then
+        DL_LDFLAGS="-shared"
+        CPICFLAG=
+        CXXPICFLAG=
+        FPICFLAG=
+        SH_LDFLAGS="-shared"
+        if test -n "`echo $CFLAGS | $GREP -e '-g'`" || test -n "`echo $CXXFLAGS | $GREP -e '-g'`"; then
+          DL_LDFLAGS="$DL_LDFLAGS -g"
+          SH_LDFLAGS="$SH_LDFLAGS -g"
+        fi
+        NO_OCT_FILE_STRIP=true
+        library_path_var=PATH
+      else
+        CPICFLAG=
+        CXXPICFLAG=
+        FPICFLAG=
+        DL_LDFLAGS="-shared -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--enable-runtime-pseudo-reloc"
+        SH_LDFLAGS="-shared -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--enable-auto-image-base"
+        library_path_var=PATH
+      fi
+    ;;
+    *-*-msdosmsvc)
+      DL_LDFLAGS="-shared"
+      CPICFLAG=
+      CXXPICFLAG=
+      FPICFLAG=
+      SH_LDFLAGS="-shared"
+      if test -n "`echo $CFLAGS | $GREP -e '-g'`" || test -n "`echo $CXXFLAGS | $GREP -e '-g'`"; then
+        DL_LDFLAGS="$DL_LDFLAGS -g"
+        SH_LDFLAGS="$SH_LDFLAGS -g"
+      fi
+      NO_OCT_FILE_STRIP=true
+      library_path_var=PATH
+    ;;
+    *-*-linux* | *-*-gnu*)
+      MKOCTFILE_DL_LDFLAGS="-shared -Wl,-Bsymbolic"
+    ;;
+    i[[3456]]86-*-sco3.2v5*)
+      SH_LDFLAGS=-G
+    ;;
+    rs6000-ibm-aix* | powerpc-ibm-aix*)
+      CPICFLAG=
+      CXXPICFLAG=
+      FPICFLAG=
+      library_path_var=LIBPATH
+    ;;
+    hppa*-hp-hpux*)
+      if test $ac_cv_f77_compiler_gnu = yes; then
+        FPICFLAG=-fPIC
+      else
+        FPICFLAG=+Z
+      fi
+      SH_LDFLAGS="-shared -fPIC"
+      library_path_var=SHLIB_PATH
+    ;;
+    ia64*-hp-hpux*)
+      if test $ac_cv_f77_compiler_gnu = yes; then
+        FPICFLAG=-fPIC
+      else
+        FPICFLAG=+Z
+      fi
+      SH_LDFLAGS="-shared -fPIC"
+    ;;
+    *-sgi-*)
+      CPICFLAG=
+      CXXPICFLAG=
+      FPICFLAG=
+    ;;
+    sparc-sun-sunos4*)
+      if test $ac_cv_f77_compiler_gnu = yes; then
+        FPICFLAG=-fPIC
+      else
+        FPICFLAG=-PIC
+      fi
+      SH_LDFLAGS="-assert nodefinitions"
+    ;;
+    sparc-sun-solaris2* | i386-pc-solaris2*)
+      if test $ac_cv_f77_compiler_gnu = yes; then
+        FPICFLAG=-fPIC
+      else
+        FPICFLAG=-KPIC
+      fi
+      if test "$GCC" = yes; then
+        CPICFLAG=-fPIC
+      else
+        CPICFLAG=-KPIC
+      fi
+      if test "$GXX" = yes; then
+        CXXPICFLAG=-fPIC
+        SH_LDFLAGS=-shared
+      else
+        CXXPICFLAG=-KPIC
+        SH_LDFLAGS=-G
+      fi
+      ## Template closures in archive libraries need a different mechanism.
+      if test "$GXX" != yes; then
+        TEMPLATE_AR="${CXX}"
+        TEMPLATE_ARFLAGS="-xar -o"
+      fi
+    ;;
+  esac
+
+  AC_MSG_NOTICE([defining FPICFLAG to be $FPICFLAG])
+  AC_MSG_NOTICE([defining CPICFLAG to be $CPICFLAG])
+  AC_MSG_NOTICE([defining CXXPICFLAG to be $CXXPICFLAG])
+  AC_MSG_NOTICE([defining SH_LDFLAGS to be $SH_LDFLAGS])
+  AC_MSG_NOTICE([defining DL_LDFLAGS to be $DL_LDFLAGS])
+  AC_MSG_NOTICE([defining MKOCTFILE_DL_LDFLAGS to be $MKOCTFILE_DL_LDFLAGS])
+  AC_MSG_NOTICE([defining NO_OCT_FILE_STRIP to be $NO_OCT_FILE_STRIP])
+  AC_MSG_NOTICE([defining TEMPLATE_AR to be $TEMPLATE_AR])
+  AC_MSG_NOTICE([defining TEMPLATE_ARFLAGS to be $TEMPLATE_ARFLAGS])
+  AC_MSG_NOTICE([defining library_path_var to be $library_path_var])
+  AC_SUBST(FPICFLAG)
+  AC_SUBST(CPICFLAG)
+  AC_SUBST(CXXPICFLAG)
+  AC_SUBST(SH_LDFLAGS)
+  AC_SUBST(DL_LDFLAGS)
+  AC_SUBST(MKOCTFILE_DL_LDFLAGS)
+  AC_SUBST(NO_OCT_FILE_STRIP)
+  AC_SUBST(TEMPLATE_AR)
+  AC_SUBST(TEMPLATE_ARFLAGS)
+  AC_SUBST(library_path_var)
+  AC_SUBST(ldpreloadsep)
+  AM_SUBST_NOTMAKE(ldpreloadsep)
+])
+dnl
 dnl Allow the user disable support for command line editing using GNU
 dnl readline.
 dnl
@@ -3049,36 +2831,6 @@
   fi
 ])
 dnl
-dnl Check whether the Qt class QGuiApplication exists.
-dnl This class  was introduced in Qt 5.0.
-dnl
-dnl FIXME: Delete this entirely when we drop support for Qt 4.
-dnl
-AC_DEFUN([OCTAVE_HAVE_QGUIAPPLICATION], [
-  AC_CACHE_CHECK([for QGuiApplication],
-    [octave_cv_decl_qguiapplication],
-    [AC_LANG_PUSH(C++)
-    ac_octave_save_CPPFLAGS="$CPPFLAGS"
-    ac_octave_save_CXXFLAGS="$CXXFLAGS"
-    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
-    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-        #include <QGuiApplication>
-        ]], [[
-        QScreen *pscreen = QGuiApplication::primaryScreen ();
-        ]])],
-      octave_cv_decl_qguiapplication=yes,
-      octave_cv_decl_qguiapplication=no)
-    CPPFLAGS="$ac_octave_save_CPPFLAGS"
-    CXXFLAGS="$ac_octave_save_CXXFLAGS"
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_decl_qguiapplication = yes; then
-    AC_DEFINE(HAVE_QGUIAPPLICATION, 1,
-      [Define to 1 if `QGuiApplication' class is available.])
-  fi
-])
-dnl
 dnl Check for IEEE 754 data format.
 dnl
 AC_DEFUN([OCTAVE_IEEE754_DATA_FORMAT], [
@@ -3213,6 +2965,95 @@
   fi
 ])
 dnl
+dnl Check for llvm::createAlwaysInlinerPass
+dnl
+AC_DEFUN([OCTAVE_LLVM_HAS_CREATEALWAYSINLINERPASS], [
+  AC_CACHE_CHECK([if llvm::createAlwaysInlinerPass exists],
+    [octave_cv_llvm_has_createalwaysinlinerpass],
+    [AC_LANG_PUSH(C++)
+      AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM([[
+          #include <llvm/Transforms/IPO.h>
+          ]], [[
+          llvm::Pass *p;
+          p = llvm::createAlwaysInlinerPass ();
+        ]])],
+        octave_cv_llvm_has_createalwaysinlinerpass=yes,
+        octave_cv_llvm_has_createalwaysinlinerpass=no)
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_llvm_has_createalwaysinlinerpass = yes; then
+    AC_DEFINE(LLVM_HAS_CREATEALWAYSINLINERPASS, 1,
+      [Define to 1 if llvm::createAlwaysInlinerPass exists.])
+  fi
+])
+dnl
+dnl Check llvm::IRBuilder API
+dnl
+AC_DEFUN([OCTAVE_LLVM_IRBUILDER_API], [
+  AC_CACHE_CHECK([if llvm::IRBuilder has two template arguments],
+    [octave_cv_llvm_irbuilder_has_two_template_args],
+    [AC_LANG_PUSH(C++)
+      AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM([[
+#if defined (HAVE_LLVM_IR_FUNCTION_H)
+          #include <llvm/IR/LLVMContext.h>
+#else
+          #include <llvm/LLVMContext.h>
+#endif
+#if defined (HAVE_LLVM_IR_IRBUILDER_H)
+          #include <llvm/IR/IRBuilder.h>
+#elif defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
+          #include <llvm/Support/IRBuilder.h>
+#else
+          #include <llvm/IRBuilder.h>
+#endif
+          using namespace llvm;
+          ]], [[
+          LLVMContext c;
+          IRBuilder<ConstantFolder,IRBuilderDefaultInserter>  irb (c);
+        ]])],
+        octave_cv_llvm_irbuilder_has_two_template_args=yes,
+        octave_cv_llvm_irbuilder_has_two_template_args=no)
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_llvm_irbuilder_has_two_template_args = yes; then
+    AC_DEFINE(LLVM_IRBUILDER_HAS_TWO_TEMPLATE_ARGS, 1,
+      [Define to 1 if llvm::IRBuilder has two template arguments.])
+  fi
+])
+dnl
+dnl Check llvm::IRBuilder::CreateConstInBoundsGEP1_32 API
+dbl
+AC_DEFUN([OCTAVE_LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_API], [
+  AC_CACHE_CHECK([if llvm::IRBuilder::CreateConstInBoundsGEP1_32 requires a type argument],
+    [octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type],
+    [AC_LANG_PUSH(C++)
+      AC_COMPILE_IFELSE(
+        [AC_LANG_PROGRAM([[
+#if defined (HAVE_LLVM_IR_IRBUILDER_H)
+          #include <llvm/IR/IRBuilder.h>
+#elif defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
+          #include <llvm/Support/IRBuilder.h>
+#else
+          #include <llvm/IRBuilder.h>
+#endif
+          ]], [[
+          llvm::LLVMContext c;
+          llvm::IRBuilder<>  irb (c);
+          llvm::Value *v;
+          v = irb.CreateConstInBoundsGEP1_32 ((llvm::Value *) nullptr, 0);
+        ]])],
+        octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type=no,
+        octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type=yes)
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type = yes; then
+    AC_DEFINE(LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_REQUIRES_TYPE, 1,
+      [Define to 1 if llvm::IRBuilder::CreateConstInBoundsGEP1_32 requires a type argument.])
+  fi
+])
+dnl
 dnl Check for legacy::PassManager API
 dnl
 AC_DEFUN([OCTAVE_LLVM_LEGACY_PASSMANAGER_API], [
@@ -3265,95 +3106,6 @@
   fi
 ])
 dnl
-dnl Check llvm::IRBuilder API
-dnl
-AC_DEFUN([OCTAVE_LLVM_IRBUILDER_API], [
-  AC_CACHE_CHECK([if llvm::IRBuilder has two template arguments],
-    [octave_cv_llvm_irbuilder_has_two_template_args],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-#if defined (HAVE_LLVM_IR_FUNCTION_H)
-          #include <llvm/IR/LLVMContext.h>
-#else
-          #include <llvm/LLVMContext.h>
-#endif
-#if defined (HAVE_LLVM_IR_IRBUILDER_H)
-          #include <llvm/IR/IRBuilder.h>
-#elif defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
-          #include <llvm/Support/IRBuilder.h>
-#else
-          #include <llvm/IRBuilder.h>
-#endif
-          using namespace llvm;
-          ]], [[
-          LLVMContext c;
-          IRBuilder<ConstantFolder,IRBuilderDefaultInserter>  irb (c);
-        ]])],
-        octave_cv_llvm_irbuilder_has_two_template_args=yes,
-        octave_cv_llvm_irbuilder_has_two_template_args=no)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_llvm_irbuilder_has_two_template_args = yes; then
-    AC_DEFINE(LLVM_IRBUILDER_HAS_TWO_TEMPLATE_ARGS, 1,
-      [Define to 1 if llvm::IRBuilder has two template arguments.])
-  fi
-])
-dnl
-dnl Check for llvm::createAlwaysInlinerPass
-dnl
-AC_DEFUN([OCTAVE_LLVM_HAS_CREATEALWAYSINLINERPASS], [
-  AC_CACHE_CHECK([if llvm::createAlwaysInlinerPass exists],
-    [octave_cv_llvm_has_createalwaysinlinerpass],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-          #include <llvm/Transforms/IPO.h>
-          ]], [[
-          llvm::Pass *p;
-          p = llvm::createAlwaysInlinerPass ();
-        ]])],
-        octave_cv_llvm_has_createalwaysinlinerpass=yes,
-        octave_cv_llvm_has_createalwaysinlinerpass=no)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_llvm_has_createalwaysinlinerpass = yes; then
-    AC_DEFINE(LLVM_HAS_CREATEALWAYSINLINERPASS, 1,
-      [Define to 1 if llvm::createAlwaysInlinerPass exists.])
-  fi
-])
-dnl
-dnl Check llvm::IRBuilder::CreateConstInBoundsGEP1_32 API
-dbl
-AC_DEFUN([OCTAVE_LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_API], [
-  AC_CACHE_CHECK([if llvm::IRBuilder::CreateConstInBoundsGEP1_32 requires a type argument],
-    [octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type],
-    [AC_LANG_PUSH(C++)
-      AC_COMPILE_IFELSE(
-        [AC_LANG_PROGRAM([[
-#if defined (HAVE_LLVM_IR_IRBUILDER_H)
-          #include <llvm/IR/IRBuilder.h>
-#elif defined (HAVE_LLVM_SUPPORT_IRBUILDER_H)
-          #include <llvm/Support/IRBuilder.h>
-#else
-          #include <llvm/IRBuilder.h>
-#endif
-          ]], [[
-          llvm::LLVMContext c;
-          llvm::IRBuilder<>  irb (c);
-          llvm::Value *v;
-          v = irb.CreateConstInBoundsGEP1_32 ((llvm::Value *) nullptr, 0);
-        ]])],
-        octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type=no,
-        octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type=yes)
-    AC_LANG_POP(C++)
-  ])
-  if test $octave_cv_llvm_irbuilder_createconstinboundsgep1_32_requires_type = yes; then
-    AC_DEFINE(LLVM_IRBUILDER_CREATECONSTINBOUNDSGEP1_32_REQUIRES_TYPE, 1,
-      [Define to 1 if llvm::IRBuilder::CreateConstInBoundsGEP1_32 requires a type argument.])
-  fi
-])
-dnl
 dnl Check if MIPS processor is target and quiet signalling NaN value is
 dnl opposite of IEEE 754-2008 standard used by all other architectures.
 dnl
@@ -3376,7 +3128,7 @@
           return (0);
         #else
           return (1);
-        #endif  
+        #endif
       ]])],
       octave_cv_mips_nan=yes,
       octave_cv_mips_nan=no,
@@ -3389,311 +3141,6 @@
   fi
 ])
 dnl
-dnl OCTAVE_CHECK_FORTRAN_SYMBOL_AND_CALLING_CONVENTIONS
-dnl
-dnl Set variables related to Fortran symbol names (append underscore,
-dnl use uppercase names, etc.) and calling convention (mostly used for
-dnl determining how character strings are passed).
-dnl
-AC_DEFUN([OCTAVE_CHECK_FORTRAN_SYMBOL_AND_CALLING_CONVENTIONS], [
-  F77_TOLOWER=yes
-  F77_APPEND_UNDERSCORE=yes
-  F77_APPEND_EXTRA_UNDERSCORE=yes
-
-  case $ac_cv_f77_mangling in
-    "upper case") F77_TOLOWER=no ;;
-  esac
-  case $ac_cv_f77_mangling in
-    "no underscore") F77_APPEND_UNDERSCORE=no ;;
-  esac
-  case $ac_cv_f77_mangling in
-    "no extra underscore") F77_APPEND_EXTRA_UNDERSCORE=no ;;
-  esac
-
-  case $canonical_host_type in
-    i[[3456789]]86-*-*)
-      if test $ac_cv_f77_compiler_gnu = yes; then
-        OCTAVE_F77_FLAG([-mieee-fp])
-      fi
-    ;;
-    alpha*-*-*)
-      if test $ac_cv_f77_compiler_gnu = yes; then
-        OCTAVE_F77_FLAG([-mieee])
-      else
-        OCTAVE_F77_FLAG([-ieee])
-        OCTAVE_F77_FLAG([-fpe1])
-      fi
-    ;;
-    powerpc-apple-machten*)
-      FFLAGS=
-    ;;
-  esac
-
-  if test $ac_cv_f77_compiler_gnu = yes; then
-    FORTRAN_CALLING_CONVENTION=gfortran
-  else
-    FORTRAN_CALLING_CONVENTION=unknown
-  fi
-  AC_ARG_ENABLE([fortran-calling-convention],
-    [AS_HELP_STRING([--enable-fortran-calling-convention=OPTION],
-      [Select C++ to Fortran calling convention.  "gfortran" should be detected automatically.  Other options are "cray", "visual-fortran", or "f2c".])],
-    [FORTRAN_CALLING_CONVENTION="$enableval"], [])
-
-  case $FORTRAN_CALLING_CONVENTION in
-    gfortran)
-      AC_DEFINE(F77_USES_GFORTRAN_CALLING_CONVENTION, 1, [Define to 1 if calling Fortran from C++ should use the gfortran calling convention.])
-    ;;
-    cray)
-      AC_DEFINE(F77_USES_CRAY_CALLING_CONVENTION, 1, [Define to 1 if calling Fortran from C++ should use the Cray Fortran calling convention.])
-    ;;
-    visual-fortran)
-      AC_DEFINE(F77_USES_VISUAL_FORTRAN_CALLING_CONVENTION, 1, [Define to 1 if calling Fortran from C++ should use the Visual Fortran calling convention.])
-    ;;
-    f2c)
-      AC_DEFINE(F77_USES_F2C_CALLING_CONVENTION, 1, [Define to 1 if calling Fortran from C++ should use the f2c calling convention.])
-    ;;
-    *)
-      AC_MSG_ERROR([to build Octave, the C++ to Fortran calling convention must be known.])
-    ;;
-  esac
-
-  if test -n "$FFLAGS"; then
-    AC_MSG_NOTICE([defining FFLAGS to be $FFLAGS])
-  fi
-
-  AC_SUBST(F77_TOLOWER)
-  AC_SUBST(F77_APPEND_UNDERSCORE)
-  AC_SUBST(F77_APPEND_EXTRA_UNDERSCORE)
-])
-dnl
-dnl OCTAVE_DEFINE_MKOCTFILE_DYNAMIC_LINK_OPTIONS
-dnl
-dnl Requires the following variables to already be set:
-dnl
-dnl   AR
-dnl   CFLAGS
-dnl   CXX
-dnl   CXXFLAGS
-dnl   EXEEXT
-dnl   GCC
-dnl   GREP
-dnl   GXX
-dnl   LDFLAGS
-dnl   ac_cv_f77_compiler_gnu
-dnl   ac_top_build_prefix
-dnl   canonical_host_type
-dnl   have_msvc
-dnl
-AC_DEFUN_ONCE([OCTAVE_DEFINE_MKOCTFILE_DYNAMIC_LINK_OPTIONS], [
-  ### Set system-dependent options for building shared libraries.
-  ### These are used by mkoctfile to create dynamically loadable
-  ### .oct and .mex files.  It would be great if we could somehow
-  ### use libtool to get this information.
-
-  CPICFLAG=-fPIC
-  CXXPICFLAG=-fPIC
-  FPICFLAG=-fPIC
-  SH_LDFLAGS=-shared
-  DL_LDFLAGS="${SH_LDFLAGS}"
-  MKOCTFILE_DL_LDFLAGS="${DL_LDFLAGS}"
-  NO_OCT_FILE_STRIP=false
-  TEMPLATE_AR="${AR}"
-  TEMPLATE_ARFLAGS="${ARFLAGS}"
-  EXTERNAL_DLL_DEFS=
-  OCTAVE_DLL_DEFS=
-  OCTINTERP_DLL_DEFS=
-  OCTGUI_DLL_DEFS=
-  OCTGRAPHICS_DLL_DEFS=
-  library_path_var=LD_LIBRARY_PATH
-  ldpreloadsep=" "
-  case $canonical_host_type in
-    *-*-386bsd* | *-*-netbsd*)
-      SH_LDFLAGS=-Bshareable
-    ;;
-    *-*-openbsd*)
-      SH_LDFLAGS="-shared -fPIC"
-    ;;
-    *-*-freebsd*)
-      SH_LDFLAGS="-shared -Wl,-x"
-    ;;
-    alpha*-dec-osf*)
-      CPICFLAG=
-      CXXPICFLAG=
-      FPICFLAG=
-      SH_LDFLAGS="-shared -Wl,-expect_unresolved -Wl,'*'"
-    ;;
-    *-*-darwin*)
-      DL_LDFLAGS="-bundle -bundle_loader ${ac_top_build_prefix}libinterp/octave ${LDFLAGS}"
-      dnl Contains variables that are defined and undefined at this point, so use
-      dnl appropriate quoting to defer expansion of ${bindir} and ${version}.
-      MKOCTFILE_DL_LDFLAGS='-bundle -bundle_loader ${bindir}/octave-${version}'"${EXEEXT}"
-      SH_LDFLAGS="-dynamiclib -single_module ${LDFLAGS}"
-      case $canonical_host_type in
-        powerpc-*)
-          CXXPICFLAG=
-          CPICFLAG=
-          FPICFLAG=
-        ;;
-      esac
-      NO_OCT_FILE_STRIP=true
-      library_path_var=DYLD_LIBRARY_PATH
-    ;;
-    *-*-cygwin*)
-      CPICFLAG=
-      CXXPICFLAG=
-      FPICFLAG=
-      DL_LDFLAGS="-shared -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--enable-runtime-pseudo-reloc"
-      SH_LDFLAGS="-shared -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--enable-auto-image-base"
-      ldpreloadsep=":"
-    ;;
-    *-*-mingw*)
-      if test $have_msvc = yes; then
-        DL_LDFLAGS="-shared"
-        CPICFLAG=
-        CXXPICFLAG=
-        FPICFLAG=
-        SH_LDFLAGS="-shared"
-        if test -n "`echo $CFLAGS | $GREP -e '-g'`" || test -n "`echo $CXXFLAGS | $GREP -e '-g'`"; then
-          DL_LDFLAGS="$DL_LDFLAGS -g"
-          SH_LDFLAGS="$SH_LDFLAGS -g"
-        fi
-        NO_OCT_FILE_STRIP=true
-        library_path_var=PATH
-        ## Extra compilation flags.
-        EXTERNAL_DLL_DEFS="-DEXTERNAL_DLL"
-        OCTAVE_DLL_DEFS="-DOCTAVE_DLL"
-        OCTINTERP_DLL_DEFS="-DOCTINTERP_DLL"
-        OCTGUI_DLL_DEFS="-DOCTGUI_DLL"
-        OCTGRAPHICS_DLL_DEFS="-DOCTGRAPHICS_DLL"
-      else
-        CPICFLAG=
-        CXXPICFLAG=
-        FPICFLAG=
-        DL_LDFLAGS="-shared -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--enable-runtime-pseudo-reloc"
-        SH_LDFLAGS="-shared -Wl,--export-all-symbols -Wl,--enable-auto-import -Wl,--enable-auto-image-base"
-        library_path_var=PATH
-      fi
-    ;;
-    *-*-msdosmsvc)
-      DL_LDFLAGS="-shared"
-      CPICFLAG=
-      CXXPICFLAG=
-      FPICFLAG=
-      SH_LDFLAGS="-shared"
-      if test -n "`echo $CFLAGS | $GREP -e '-g'`" || test -n "`echo $CXXFLAGS | $GREP -e '-g'`"; then
-        DL_LDFLAGS="$DL_LDFLAGS -g"
-        SH_LDFLAGS="$SH_LDFLAGS -g"
-      fi
-      NO_OCT_FILE_STRIP=true
-      library_path_var=PATH
-      ## Extra compilation flags.
-      EXTERNAL_DLL_DEFS="-DEXTERNAL_DLL"
-      OCTAVE_DLL_DEFS="-DOCTAVE_DLL"
-      OCTGUI_DLL_DEFS="-DOCTGUI_DLL"
-      OCTGRAPHICS_DLL_DEFS="-DOCTGRAPHICS_DLL"
-    ;;
-    *-*-linux* | *-*-gnu*)
-      MKOCTFILE_DL_LDFLAGS="-shared -Wl,-Bsymbolic"
-    ;;
-    i[[3456]]86-*-sco3.2v5*)
-      SH_LDFLAGS=-G
-    ;;
-    rs6000-ibm-aix* | powerpc-ibm-aix*)
-      CPICFLAG=
-      CXXPICFLAG=
-      FPICFLAG=
-      library_path_var=LIBPATH
-    ;;
-    hppa*-hp-hpux*)
-      if test $ac_cv_f77_compiler_gnu = yes; then
-        FPICFLAG=-fPIC
-      else
-        FPICFLAG=+Z
-      fi
-      SH_LDFLAGS="-shared -fPIC"
-      library_path_var=SHLIB_PATH
-    ;;
-    ia64*-hp-hpux*)
-      if test $ac_cv_f77_compiler_gnu = yes; then
-        FPICFLAG=-fPIC
-      else
-        FPICFLAG=+Z
-      fi
-      SH_LDFLAGS="-shared -fPIC"
-    ;;
-    *-sgi-*)
-      CPICFLAG=
-      CXXPICFLAG=
-      FPICFLAG=
-    ;;
-    sparc-sun-sunos4*)
-      if test $ac_cv_f77_compiler_gnu = yes; then
-        FPICFLAG=-fPIC
-      else
-        FPICFLAG=-PIC
-      fi
-      SH_LDFLAGS="-assert nodefinitions"
-    ;;
-    sparc-sun-solaris2* | i386-pc-solaris2*)
-      if test $ac_cv_f77_compiler_gnu = yes; then
-        FPICFLAG=-fPIC
-      else
-        FPICFLAG=-KPIC
-      fi
-      if test "$GCC" = yes; then
-        CPICFLAG=-fPIC
-      else
-        CPICFLAG=-KPIC
-      fi
-      if test "$GXX" = yes; then
-        CXXPICFLAG=-fPIC
-        SH_LDFLAGS=-shared
-      else
-        CXXPICFLAG=-KPIC
-        SH_LDFLAGS=-G
-      fi
-      ## Template closures in archive libraries need a different mechanism.
-      if test "$GXX" != yes; then
-        TEMPLATE_AR="${CXX}"
-        TEMPLATE_ARFLAGS="-xar -o"
-      fi
-    ;;
-  esac
-
-  AC_MSG_NOTICE([defining FPICFLAG to be $FPICFLAG])
-  AC_MSG_NOTICE([defining CPICFLAG to be $CPICFLAG])
-  AC_MSG_NOTICE([defining CXXPICFLAG to be $CXXPICFLAG])
-  AC_MSG_NOTICE([defining SH_LDFLAGS to be $SH_LDFLAGS])
-  AC_MSG_NOTICE([defining DL_LDFLAGS to be $DL_LDFLAGS])
-  AC_MSG_NOTICE([defining MKOCTFILE_DL_LDFLAGS to be $MKOCTFILE_DL_LDFLAGS])
-  AC_MSG_NOTICE([defining NO_OCT_FILE_STRIP to be $NO_OCT_FILE_STRIP])
-  AC_MSG_NOTICE([defining TEMPLATE_AR to be $TEMPLATE_AR])
-  AC_MSG_NOTICE([defining TEMPLATE_ARFLAGS to be $TEMPLATE_ARFLAGS])
-  AC_MSG_NOTICE([defining EXTERNAL_DLL_DEFS to be $EXTERNAL_DLL_DEFS])
-  AC_MSG_NOTICE([defining OCTAVE_DLL_DEFS to be $OCTAVE_DLL_DEFS])
-  AC_MSG_NOTICE([defining OCTINTERP_DLL_DEFS to be $OCTINTERP_DLL_DEFS])
-  AC_MSG_NOTICE([defining OCTGUI_DLL_DEFS to be $OCTGUI_DLL_DEFS])
-  AC_MSG_NOTICE([defining OCTGRAPHICS_DLL_DEFS to be $OCTGRAPHICS_DLL_DEFS])
-  AC_MSG_NOTICE([defining library_path_var to be $library_path_var])
-  AC_SUBST(FPICFLAG)
-  AC_SUBST(CPICFLAG)
-  AC_SUBST(CXXPICFLAG)
-  AC_SUBST(SH_LDFLAGS)
-  AC_SUBST(DL_LDFLAGS)
-  AC_SUBST(MKOCTFILE_DL_LDFLAGS)
-  AC_SUBST(NO_OCT_FILE_STRIP)
-  AC_SUBST(TEMPLATE_AR)
-  AC_SUBST(TEMPLATE_ARFLAGS)
-  AC_SUBST(EXTERNAL_DLL_DEFS)
-  AC_SUBST(OCTAVE_DLL_DEFS)
-  AC_SUBST(OCTINTERP_DLL_DEFS)
-  AC_SUBST(OCTGUI_DLL_DEFS)
-  AC_SUBST(OCTGRAPHICS_DLL_DEFS)
-  AC_SUBST(library_path_var)
-  AC_SUBST(ldpreloadsep)
-  AM_SUBST_NOTMAKE(ldpreloadsep)
-])
-dnl
 dnl Check for ar.
 dnl
 AC_DEFUN([OCTAVE_PROG_AR], [
@@ -3820,7 +3267,9 @@
   ##
   ## Also make sure that we generate an interactive scanner if we are
   ## using flex.
-  AC_PROG_LEX
+dnl We declare %noyywrap in the lexer files so we use the noyywrap
+dnl option here to skip the search for that function.
+  AC_PROG_LEX([noyywrap])
   case "`$LEX --version`" in
     *flex*)
       LFLAGS="-I"
--- a/oct-conf-post.in.h	Sun May 16 09:43:43 2021 +0200
+++ b/oct-conf-post.in.h	Sun May 16 09:44:35 2021 +0200
@@ -170,14 +170,23 @@
 
 /* oct-dlldefs.h */
 
-/* FIXME: GCC supports visibility attributes as well, even using the
-   same __declspec declaration if desired.  The build system should be
-   extended to support GCC and visibility attributes.  */
-#if defined (_MSC_VER)
-#  define OCTAVE_EXPORT __declspec(dllexport)
-#  define OCTAVE_IMPORT __declspec(dllimport)
+#if defined (OCTAVE_ENABLE_LIB_VISIBILITY_FLAGS)
+#  if defined (_WIN32) || defined (__CYGWIN__)
+#    if defined (__GNUC__)
+       /* GCC */
+#      define OCTAVE_EXPORT __attribute__ ((dllexport))
+#      define OCTAVE_IMPORT __attribute__ ((dllimport))
+#    else
+       /* MSVC */
+#      define OCTAVE_EXPORT __declspec(dllexport)
+#      define OCTAVE_IMPORT __declspec(dllimport)
+#    endif
+#  else
+     /* All other platforms. */
+#    define OCTAVE_EXPORT __attribute__ ((visibility ("default")))
+#    define OCTAVE_IMPORT
+#  endif
 #else
-   /* All other compilers, at least for now. */
 #  define OCTAVE_EXPORT
 #  define OCTAVE_IMPORT
 #endif
@@ -189,13 +198,20 @@
 #  define OCTAVE_API OCTAVE_IMPORT
 #endif
 
-/* API macro for libinterp */
+/* API macro for liboctinterp */
 #if defined (OCTINTERP_DLL)
 #  define OCTINTERP_API OCTAVE_EXPORT
 #else
 #  define OCTINTERP_API OCTAVE_IMPORT
 #endif
 
+/* API macro for the Array class in liboctave and liboctinterp */
+#if (defined (OCTAVE_DLL) || defined (OCTINTERP_DLL))
+#  define OCTARRAY_API OCTAVE_EXPORT
+#else
+#  define OCTARRAY_API OCTAVE_IMPORT
+#endif
+
 /* API macro for libinterp/graphics */
 #if defined (OCTGRAPHICS_DLL)
 #  define OCTGRAPHICS_API OCTAVE_EXPORT
@@ -242,6 +258,12 @@
 
 typedef OCTAVE_F77_INT_TYPE octave_f77_int_type;
 
+#if OCTAVE_SIZEOF_F77_INT_TYPE == 8
+#  define OCTAVE_F77_INT_TYPE_FORMAT PRId64
+#else
+#  define OCTAVE_F77_INT_TYPE_FORMAT PRId32
+#endif
+
 #define OCTAVE_HAVE_F77_INT_TYPE 1
 
 #if defined (__cplusplus) && ! defined (OCTAVE_THREAD_LOCAL)
--- a/run-octave.in	Sun May 16 09:43:43 2021 +0200
+++ b/run-octave.in	Sun May 16 09:44:35 2021 +0200
@@ -111,7 +111,6 @@
 
 OCTAVE_ARCHLIBDIR="$builddir/src"; export OCTAVE_ARCHLIBDIR
 OCTAVE_BINDIR="$builddir/src"; export OCTAVE_BINDIR
-OCTAVE_DEFAULT_QT_SETTINGS="$builddir/libgui/default-qt-settings"; export OCTAVE_DEFAULT_QT_SETTINGS
 OCTAVE_FONTS_DIR="$top_srcdir/etc/fonts"; export OCTAVE_FONTS_DIR
 OCTAVE_JAVA_DIR="$builddir/scripts/java"; export OCTAVE_JAVA_DIR
 OCTAVE_LOCALE_DIR="$builddir/libgui/languages"; export OCTAVE_LOCALE_DIR
--- a/scripts/+containers/Map.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/+containers/Map.m	Sun May 16 09:44:35 2021 +0200
@@ -379,7 +379,13 @@
             case "keys"
               sref = keys (this);
             case "values"
-              sref = values (this);
+              if (numel (s) > 1
+                  && strcmp (s(2).type, "()") && ! isempty (s(2).subs))
+                sref = values (this, s(2).subs{1});
+                s(1) = [];
+              else
+                sref = values (this);
+              end
             case "size"
               sref = size (this);
             case "length"
@@ -397,7 +403,7 @@
                 error ("containers.Map: input argument 'KeySet' is missing");
               endif
               sref = feval (s(1).subs, this, s(2).subs{1});
-              s = s(3:end);
+              s(1) = [];
             otherwise
               error ("containers.Map: unknown property '%s'", s(1).subs);
           endswitch
@@ -821,6 +827,24 @@
 %! m3 = [m2, m1];
 %! assert (m3.KeyType, "single");
 
+## Test subsref calls
+%!test <*59607>
+%! months = {'Jan', 'Feb', 'Mar', 'Apr'};
+%! vals = [10, 11, 12, 13];
+%! M = containers.Map (months, vals);
+%! keys = {'Jan', 'Feb'};
+%! assert (M.values, values (M));
+%! assert (M.values (), values (M));
+%! assert (M.values (keys), {10, 11});
+%! assert (M.values (keys)(2), {11});
+%! assert (M.values (keys){2}, 11);
+%!test
+%! months = {'Jan', 'Feb', 'Mar', 'Apr'};
+%! vals = [10, 11, 12, 13];
+%! M = containers.Map (months, vals);
+%! keys = {'Jan', 'FooBar', 'Feb'};
+%! assert (M.isKey (keys)(2:end), logical ([0, 1]));
+
 ## Test input validation
 %!error containers.Map (1,2,3)
 %!error containers.Map (1,2,3,4,5)
--- a/scripts/+matlab/+lang/makeUniqueStrings.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/+matlab/+lang/makeUniqueStrings.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
 
 function [uniqstr, ismodified] = makeUniqueStrings (str, ex = {}, maxlength = Inf)
 
-  if (nargin == 0 || nargout > 3)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -228,8 +228,7 @@
 %! assert (uniqstr, {"a_1","a_2","a_4","a_6","a_5"});
 
 ## Test input validation
-%!error matlab.lang.makeUniqueStrings ()
-%!error [a, b, c] = matlab.lang.makeUniqueStrings ("a");
+%!error <Invalid call> matlab.lang.makeUniqueStrings ()
 %!error <STR must be a string or cellstr> matlab.lang.makeUniqueStrings (1)
 %!error <STR and EX logical array must have the same length>
 %! matlab.lang.makeUniqueStrings ("a", [true false]);
--- a/scripts/+matlab/+lang/makeValidName.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/+matlab/+lang/makeValidName.m	Sun May 16 09:44:35 2021 +0200
@@ -65,102 +65,9 @@
 ## @seealso{iskeyword, isvarname, matlab.lang.makeUniqueStrings}
 ## @end deftypefn
 
-function [varname, ismodified] = makeValidName (str, varargin)
-
-  if (nargin == 0 || nargout > 2)
-    print_usage ();
-  endif
-
-  if (! ischar (str) && ! iscellstr (str))
-    error ("makeValidName: STR must be a string or cellstr");
-  endif
-
-  if (mod (nargin - 1, 2) != 0)
-    error ("makeValidName: property/value options must occur in pairs");
-  endif
-
-  varname = cellstr (str);
-  ismodified = false (size (varname));
-  convert2char = ischar (str);
-  opts = struct ("replacementstyle", "underscore", "prefix", "x");
-
-  for i = 1:2:numel (varargin)
-    if (! ischar (varargin{i}))
-      error ("makeValidName: option argument must be a string");
-    endif
-    parameter = tolower (varargin{i});
-    value = varargin{i+1};
-    switch (parameter)
-      case "replacementstyle"
-        if (! ischar (value))
-          error ('makeValidName: "ReplacementStyle" value must be a string');
-        endif
-        value = tolower (value);
-        if (! any (strcmp (value, {"underscore", "delete", "hex"})))
-          error ('makeValidName: invalid "ReplacementStyle" value "%s"', value);
-        endif
-        opts.replacementstyle = value;
-
-      case "prefix"
-        if (! isvarname (value))
-          error ('makeValidName: invalid "Prefix" value "%s"', value);
-        endif
-        opts.prefix = value;
-
-      otherwise
-        error ('makeValidName: unknown property "%s"', parameter);
-    endswitch
-  endfor
+function [varname, ismodified] = makeValidName (varargin)
 
-  for i = 1:numel (varname)
-    if (! isvarname (varname{i}))
-      ismodified(i) = true;
-
-      ## Remove leading and trailing whitespace
-      varname{i} = strtrim (varname{i});
-      if (isempty (varname{i}))
-        varname{i} = opts.prefix;
-      endif
-
-      ## Add prefix if input is a reserved keyword
-      if (iskeyword (varname{i}))
-        varname{i} = [opts.prefix, toupper(varname{i}(1)), varname{i}(2:end)];
-      endif
-
-      ## Change whitespace followed by lowercase letter to uppercase
-      idx = regexp (varname{i}, '\s[a-z]');
-      varname{i}(idx+1) = toupper (varname{i}(idx+1));
-
-      ## Remove any whitespace character
-      varname{i}(isspace (varname{i})) = "";
-
-      ## Add prefix if first character is not a letter or underscore
-      char1 = varname{i}(1);
-      if (! isalpha (char1) && char1 != "_")
-        varname{i} = [opts.prefix varname{i}];
-      endif
-
-      ## Replace non alphanumerics or underscores
-      idx = regexp (varname{i}, '[^0-9a-zA-Z_]');
-      switch (opts.replacementstyle)
-        case "underscore"
-          varname{i}(idx) = "_";
-
-        case "delete"
-          varname{i}(idx) = "";
-
-        case "hex"
-          for j = numel (idx):-1:1
-            varname{i} = strrep (varname{i}, varname{i}(idx(j)),
-                                 sprintf ("0x%02X",varname{i}(idx(j))));
-          endfor
-      endswitch
-    endif
-  endfor
-
-  if (convert2char)
-    varname = char (varname);
-  endif
+  [varname, ismodified] = __make_valid_name__ (varargin{:});
 
 endfunction
 
@@ -218,16 +125,16 @@
 %!error matlab.lang.makeValidName ("for", "Prefix", "for")
 
 ## Test input validation
-%!error matlab.lang.makeValidName ()
+%!error <Invalid call> matlab.lang.makeValidName ()
 %!error <STR must be a string or cellstr> matlab.lang.makeValidName (42)
 %!error <options must occur in pairs> matlab.lang.makeValidName ("a", "opt1")
 %!error <option argument must be a string>
 %! matlab.lang.makeValidName ("a", 1, 2)
-%!error <"ReplacementStyle" value must be a string>
+%!error <'ReplacementStyle' value must be a string>
 %! matlab.lang.makeValidName ("a", "ReplacementStyle", 1);
-%!error <invalid "ReplacementStyle" value "foobar">
+%!error <invalid 'ReplacementStyle' value 'foobar'>
 %! matlab.lang.makeValidName ("a", "ReplacementStyle", "foobar");
-%!error <invalid "Prefix" value "1_">
+%!error <invalid 'Prefix' value '1_'>
 %! matlab.lang.makeValidName ("a", "Prefix", "1_");
-%!error <unknown property "foobar">
+%!error <unknown property 'foobar'>
 %! matlab.lang.makeValidName ("a", "foobar", 1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+net/base64decode.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,64 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{out_vec} =} matlab.net.base64decode (@var{b64_str})
+##
+## Convert base64 encoded @var{b64_str} to uint8 vector @var{out_vec}.
+##
+## The input @var{b64_str} must be a string vector.
+## The output @var{out_vec} will be a uint8 vector that is decoded
+## according to RFC 4648.
+##
+## @seealso{matlab.net.base64encode, base64_decode, base64_encode, native2unicode}
+## @end deftypefn
+
+function out_vec = base64decode (b64_str)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (! isvector (b64_str) || ! ischar (b64_str))
+    error ("base64decode: B64_STR must be a base64 encoded character vector");
+  endif
+
+  out_vec = uint8 (__base64_decode_bytes__ (b64_str));
+
+endfunction
+
+
+## Test char vector input
+%!assert (matlab.net.base64decode ("AQ=="), uint8 (1));
+%!assert (matlab.net.base64decode ("/w=="), uint8 (255));
+%!assert (matlab.net.base64decode ("AQID"), uint8 (1:3));
+%!assert (matlab.net.base64decode ("YQ=="), uint8 ("a"));
+%!assert (matlab.net.base64decode ("YWJjZGVmZw=="), uint8 ("abcdefg"));
+
+## Test input validation
+%!error <Invalid call> matlab.net.base64decode ()
+%!error <character vector> matlab.net.base64decode (pi)
+%!error <character vector> matlab.net.base64decode ({1,2})
+%!error <character vector> matlab.net.base64decode ([1,2;3,4])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+net/base64encode.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,67 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{b64_str} =} matlab.net.base64encode (@var{in})
+##
+## Convert @var{in} to a base64 encoded string @var{b64_str}.
+##
+## The input @var{in} can be a string or numeric vector.
+## The output @var{b64_str} will be encoded according to RFC 4648.
+##
+## @seealso{matlab.net.base64decode, base64_decode, base64_encode, unicode2native}
+## @end deftypefn
+
+function b64_str = base64encode (in)
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  if (! isvector (in) || ! (isnumeric (in) || ischar (in)))
+    error ("base64encode: IN must be a numeric or character vector");
+  endif
+
+  if (any (in != round (in)))
+    error ("base64encode: IN must consist of integers");
+  endif
+
+  b64_str = base64_encode (uint8 (in));
+
+endfunction
+
+
+## Test char vector input
+%!assert (matlab.net.base64encode (1), "AQ==");
+%!assert (matlab.net.base64encode (255), "/w==");
+%!assert (matlab.net.base64encode (1:3), "AQID");
+%!assert (matlab.net.base64encode ("a"), "YQ==");
+%!assert (matlab.net.base64encode ("abcdefg"), "YWJjZGVmZw==");
+
+## Test input validation
+%!error <Invalid call> matlab.net.base64encode ()
+%!error <numeric or character vector> matlab.net.base64encode ({1,2})
+%!error <numeric or character vector> matlab.net.base64encode ([1,2;3,4])
+%!error <consist of integers> matlab.net.base64encode (pi)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/+matlab/+net/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,15 @@
+FCN_FILE_DIRS += %reldir%
+
+%canon_reldir%_FCN_FILES = \
+  %reldir%/base64decode.m \
+  %reldir%/base64encode.m
+
+%canon_reldir%dir = $(fcnfiledir)/+matlab/+net
+
+%canon_reldir%_DATA = $(%canon_reldir%_FCN_FILES)
+
+FCN_FILES += $(%canon_reldir%_FCN_FILES)
+
+PKG_ADD_FILES += %reldir%/PKG_ADD
+
+DIRSTAMP_FILES += %reldir%/$(octave_dirstamp)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/@ftp/cd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/@ftp/cd.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function path = cd (f, path)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/@ftp/disp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/@ftp/disp.m	Sun May 16 09:44:35 2021 +0200
@@ -25,7 +25,7 @@
 
 function disp (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/audio/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/audio/@audioplayer/__get_properties__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audioplayer/__get_properties__.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function props = __get_properties__ (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/disp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audioplayer/disp.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function disp (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/isplaying.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audioplayer/isplaying.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function result = isplaying (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/pause.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audioplayer/pause.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function pause (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/resume.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audioplayer/resume.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function resume (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audioplayer/stop.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audioplayer/stop.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function stop (player)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/__get_properties__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audiorecorder/__get_properties__.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function props = __get_properties__ (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/audiorecorder.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audiorecorder/audiorecorder.m	Sun May 16 09:44:35 2021 +0200
@@ -88,14 +88,14 @@
 %! assert (size (data)(2), 2);
 
 %!testif HAVE_PORTAUDIO; audiodevinfo (1) > 0
-%! recorder = audiorecorder;
+%! recorder = audiorecorder ();
 %! set (recorder, {"SampleRate", "Tag", "UserData"}, {8000, "tag", [1, 2; 3, 4]});
 %! assert (recorder.SampleRate, 8000);
 %! assert (recorder.Tag, "tag");
 %! assert (recorder.UserData, [1, 2; 3, 4]);
 
 %!testif HAVE_PORTAUDIO; audiodevinfo (1) > 0
-%! recorder = audiorecorder;
+%! recorder = audiorecorder ();
 %! settable = set (recorder);
 %! settable.SampleRate = 8000;
 %! settable.Tag = "tag";
@@ -106,7 +106,7 @@
 %! assert (recorder.UserData, [1, 2; 3, 4]);
 
 %!testif HAVE_PORTAUDIO; audiodevinfo (1) > 0
-%! recorder = audiorecorder;
+%! recorder = audiorecorder ();
 %! recorder.SampleRate = 8000;
 %! recorder.Tag = "tag";
 %! recorder.UserData = [1, 2; 3, 4];
--- a/scripts/audio/@audiorecorder/disp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audiorecorder/disp.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function disp (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/isrecording.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audiorecorder/isrecording.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function result = isrecording (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/pause.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audiorecorder/pause.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function pause (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/resume.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audiorecorder/resume.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function resume (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/@audiorecorder/stop.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/@audiorecorder/stop.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function stop (recorder)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/audio/lin2mu.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/lin2mu.m	Sun May 16 09:44:35 2021 +0200
@@ -39,6 +39,10 @@
 
 function y = lin2mu (x, n)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   if (nargin == 1)
     range = max (abs (x (:)));
     if (range <= 1)
@@ -49,12 +53,10 @@
     else
       n = 16;
     endif
-  elseif (nargin == 2)
+  else
     if (n != 0 && n != 8 && n != 16)
       error ("lin2mu: N must be either 0, 8 or 16");
     endif
-  else
-    print_usage ();
   endif
 
   ## Transform real and n-bit format to 16-bit.
--- a/scripts/audio/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -4,6 +4,7 @@
   %reldir%/@audiorecorder
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/lin2mu.m \
   %reldir%/mu2lin.m \
   %reldir%/record.m \
--- a/scripts/audio/mu2lin.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/mu2lin.m	Sun May 16 09:44:35 2021 +0200
@@ -37,14 +37,14 @@
 
 function y = mu2lin (x, n = 0)
 
-  if (nargin == 2)
-    if (n != 0 && n != 8 && n != 16)
-      error ("mu2lin: N must be either 0, 8, or 16");
-    endif
-  elseif (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
+  if (n != 0 && n != 8 && n != 16)
+    error ("mu2lin: N must be either 0, 8, or 16");
+  endif
+
   ulaw = [32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, ...
           23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, ...
           15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, ...
--- a/scripts/audio/record.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/record.m	Sun May 16 09:44:35 2021 +0200
@@ -36,19 +36,17 @@
 ## @seealso{sound, soundsc}
 ## @end deftypefn
 
-function x = record (sec, fs)
+function x = record (sec, fs = 8000)
 
-  if (nargin == 1)
-    fs = 8000;
-  elseif (nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  if (! (isscalar (sec) && (sec >= 0)))
+  if (! (isscalar (sec) && sec >= 0))
     error ("record: recording duration SEC must be a non-negative number");
   endif
 
-  if (! (isscalar (fs) && (fs > 0)))
+  if (! (isscalar (fs) && fs > 0))
     error ("record: sample rate FS must be a positive number");
   endif
 
@@ -68,11 +66,10 @@
 
 
 ## Tests of record must not actually record anything.
-
 %!assert (isempty (record (0)))
 
 ## Test input validation
-%!error record ()
-%!error record (1,2,3)
-%!error record (-1)
-%!error record (1, -1)
+%!error <SEC must be a non-negative number> record (ones (2,2))
+%!error <SEC must be a non-negative number> record (-1)
+%!error <FS must be a positive number> record (1, ones (2,2))
+%!error <FS must be a positive number> record (1, -1)
--- a/scripts/audio/sound.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/sound.m	Sun May 16 09:44:35 2021 +0200
@@ -45,13 +45,13 @@
 
 function sound (y, fs, nbits)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
   if (nargin < 2 || isempty (fs))
     fs = 8000;
-  elseif (! (isscalar (fs) && (fs > 0)))
+  elseif (! (isscalar (fs) && fs > 0))
     error ("sound: sample rate FS must be a positive number");
   endif
 
@@ -71,7 +71,7 @@
 ## Tests of sound must not actually play anything.
 
 ## Test input validation
-%!error sound ()
-%!error sound (1,2,3,4)
-%!error sound (1, -1)
-%!error sound (1, [], 2)
+%!error <Invalid call> sound ()
+%!error <FS must be a positive number> sound (1, ones (2,2))
+%!error <FS must be a positive number> sound (1, -1)
+%!error <NBITS must be 8, 16, or 24> sound (1, [], 2)
--- a/scripts/audio/soundsc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/audio/soundsc.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 
 function soundsc (y, fs, nbits, yrange)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -64,7 +64,7 @@
   elseif (nargin == 2 && numel (fs) > 1)
     yrange = fs;
     fs = 8000;
-  elseif (! (isscalar (fs) && (fs > 0)))
+  elseif (! (isscalar (fs) && fs > 0))
     error ("soundsc: sample rate FS must be a positive number");
   endif
 
@@ -102,15 +102,14 @@
 
 
 ## Tests of soundsc must not actually play anything.
-
 ## Test input validation
-%!error soundsc ()
-%!error soundsc (1,2,3,4,5)
-%!error soundsc (1, -1)
-%!error soundsc (1, [], 2)
-%!error soundsc (1, [2 1])
-%!error soundsc (1, [1 2 3])
-%!error soundsc (1, 8000, [2 1])
-%!error soundsc (1, 8000, [1 2 3])
-%!error soundsc (1, 8000, 8, [2 1])
-%!error soundsc (1, 8000, 8, [1 2 3])
+%!error <Invalid call> soundsc ()
+%!error <FS must be a positive number> soundsc (1, ones (2,2), 8)
+%!error <FS must be a positive number> soundsc (1, -1)
+%!error <NBITS must be 8, 16, or 24> soundsc (1, [], 2)
+%!error <range must be a 2-element .* vector> soundsc (1, [2 1])
+%!error <range must be a 2-element .* vector> soundsc (1, [1 2 3])
+%!error <range must be a 2-element .* vector> soundsc (1, 8000, [2 1])
+%!error <range must be a 2-element .* vector> soundsc (1, 8000, [1 2 3])
+%!error <range must be a 2-element .* vector> soundsc (1, 8000, 8, [2 1])
+%!error <range must be a 2-element .* vector> soundsc (1, 8000, 8, [1 2 3])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/deprecated/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/deprecated/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/deprecated/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,7 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
-  %reldir%/output_max_field_width.m \
+  %reldir%/.oct-config \
   %reldir%/runtests.m
 
 %canon_reldir%dir = $(fcnfiledir)/deprecated
--- a/scripts/deprecated/output_max_field_width.m	Sun May 16 09:43:43 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2018-2021 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## This file is part of Octave.
-##
-## Octave is free software: you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-## -*- texinfo -*-
-## @deftypefn  {} {@var{val} =} output_max_field_width ()
-## @deftypefnx {} {@var{old_val} =} output_max_field_width (@var{new_val})
-## @deftypefnx {} {} output_max_field_width (@var{new_val}, "local")
-##
-## @code{output_max_field_width} is deprecated and will be removed in Octave
-## version 7.  Use @code{output_precision} instead.
-##
-## Query or set the internal variable that specifies the maximum width
-## of a numeric output field.
-##
-## When called from inside a function with the @qcode{"local"} option, the
-## variable is changed locally for the function and any subroutines it calls.
-## The original variable value is restored when exiting the function.
-## @seealso{format, fixed_point_format, output_precision}
-## @end deftypefn
-
-## FIXME: DEPRECATED: Remove in version 7.
-
-function retval = output_max_field_width (varargin)
-
-  persistent warned = false;
-  if (! warned)
-    warned = true;
-    warning ("Octave:deprecated-function",
-             "output_max_field_width is obsolete and will be removed from a future version of Octave, please use output_precision instead\n");
-  endif
-
-  retval = 20;
-
-endfunction
--- a/scripts/deprecated/runtests.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/deprecated/runtests.m	Sun May 16 09:44:35 2021 +0200
@@ -53,4 +53,5 @@
   endif
 
   oruntests (varargin{:});
+
 endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/elfun/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/elfun/acosd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/acosd.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = acosd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (acosd (0:0.1:1), 180/pi * acos (0:0.1:1), -10*eps)
 
-%!error acosd ()
-%!error acosd (1, 2)
+%!error <Invalid call> acosd ()
--- a/scripts/elfun/acot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/acot.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = acot (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! v = [pi/6, pi/4, pi/3, pi/2, -pi/3, -pi/4, -pi/6];
 %! assert (acot (x), v, sqrt (eps));
 
-%!error acot ()
-%!error acot (1, 2)
+%!error <Invalid call> acot ()
--- a/scripts/elfun/acotd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/acotd.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = acotd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (acotd (0:10:90), 180/pi * acot (0:10:90), -10*eps)
 
-%!error acotd ()
-%!error acotd (1, 2)
+%!error <Invalid call> acotd ()
--- a/scripts/elfun/acoth.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/acoth.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = acoth (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! x = i*[rt3, 1, rt3/3, -rt3/3, -1, -rt3];
 %! assert (acoth (x), v, sqrt (eps));
 
-%!error acoth ()
-%!error acoth (1, 2)
+%!error <Invalid call> acoth ()
--- a/scripts/elfun/acsc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/acsc.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = acsc (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! x = [2, rt2, 2*rt3/3, 1, 2*rt3/3, rt2, 2];
 %! assert (acsc (x), v, sqrt (eps));
 
-%!error acsc ()
-%!error acsc (1, 2)
+%!error <Invalid call> acsc ()
--- a/scripts/elfun/acscd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/acscd.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = acscd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (acscd (0:10:90), 180/pi * acsc (0:10:90), -10*eps)
 
-%!error acscd ()
-%!error acscd (1, 2)
+%!error <Invalid call> acscd ()
--- a/scripts/elfun/acsch.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/acsch.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = acsch (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,5 +45,4 @@
 %! x = [-i, i];
 %! assert (acsch (x), v, sqrt (eps));
 
-%!error acsch ()
-%!error acsch (1, 2)
+%!error <Invalid call> acsch ()
--- a/scripts/elfun/asec.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/asec.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = asec (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! x = [1, 2*rt3/3, rt2, 2, -2, -rt2, -2*rt3/3, -1];
 %! assert (asec (x), v, sqrt (eps));
 
-%!error asec ()
-%!error asec (1, 2)
+%!error <Invalid call> asec ()
--- a/scripts/elfun/asecd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/asecd.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = asecd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (asecd (0:10:90), 180/pi * asec (0:10:90), -10*eps)
 
-%!error asecd ()
-%!error asecd (1, 2)
+%!error <Invalid call> asecd ()
--- a/scripts/elfun/asech.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/asech.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = asech (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,7 +45,7 @@
 %! x = [1, -1];
 %! assert (asech (x), v, sqrt (eps));
 
-%!xtest <*52627>
+%!test <*52627>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! ## Mac trig/hyperbolic functions have huge tolerances.
 %! if (! ismac ()), return; endif
@@ -53,5 +53,4 @@
 %! x = [1, -1];
 %! assert (asech (x), v, sqrt (eps));
 
-%!error asech ()
-%!error asech (1, 2)
+%!error <Invalid call> asech ()
--- a/scripts/elfun/asind.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/asind.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = asind (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (asind (0:0.1:1), 180/pi * asin (0:0.1:1), -10*eps)
 
-%!error asind ()
-%!error asind (1, 2)
+%!error <Invalid call> asind ()
--- a/scripts/elfun/atan2d.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/atan2d.m	Sun May 16 09:44:35 2021 +0200
@@ -43,5 +43,5 @@
 
 %!assert (atan2d (-1:.1:1, 1:-.1:-1), 180/pi * atan2 (-1:.1:1, 1:-.1:-1), -10*eps)
 
-%!error atan2d ()
-%!error atan2d (1)
+%!error <Invalid call> atan2d ()
+%!error <Invalid call> atan2d (1)
--- a/scripts/elfun/atand.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/atand.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = atand (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -42,5 +42,4 @@
 
 %!assert (atand (0:10:90), 180/pi * atan (0:10:90), -10*eps)
 
-%!error atand ()
-%!error atand (1, 2)
+%!error <Invalid call> atand ()
--- a/scripts/elfun/cosd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/cosd.m	Sun May 16 09:44:35 2021 +0200
@@ -27,27 +27,37 @@
 ## @deftypefn {} {} cosd (@var{x})
 ## Compute the cosine for each element of @var{x} in degrees.
 ##
-## Returns zero for elements where @code{(@var{x}-90)/180} is an integer.
+## The function is more accurate than @code{cos} for large values of @var{x}
+## and for multiples of 90 degrees (@code{@var{x} = 90 + 180*n} with n an
+## integer) where @code{cosd} returns 0 rather than a small value on the order
+## of eps.
 ## @seealso{acosd, cos}
 ## @end deftypefn
 
 function y = cosd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  I = x / 180;
-  y = cos (I .* pi);
-  I += 0.5;
-  y(I == fix (I) & isfinite (I)) = 0;
+  if (! isnumeric (x))
+    error ("cosd: X must be numeric");
+  endif
+
+  ## Advance phase by 90 degrees to transform sin to cos and use sind().
+  y = sind (x + 90);
 
 endfunction
 
 
-%!assert (cosd (0:10:80), cos (pi*[0:10:80]/180), -10*eps)
-%!assert (cosd ([0, 180, 360]) != 0)
-%!assert (cosd ([90, 270]) == 0)
+%!assert (cosd (10:20:360), cos ([10:20:360] * pi/180), 5*eps)
+%!assert (cosd ([-270, -90, 90, 270]) == 0)
+%!assert (cosd ([-360, -180, 0, 180, 360]), [1, -1, 1, -1, 1])
+%!assert (cosd ([-Inf, NaN, +Inf, 0]), [NaN, NaN, NaN, 1])
+%!assert (cosd (+23) == cosd (-23))
+%!assert (cosd (1e6), 0.17364817766693033, 5*eps)
+%!assert (cosd (90 + 180i), -i*sinh (pi))
+%!assert (cosd (1e6 + 180i), 2.01292156189451577 + 11.3732880565446539i, -eps)
 
-%!error cosd ()
-%!error cosd (1, 2)
+%!error <Invalid call> cosd ()
+%!error <X must be numeric> cosd ("abc")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/elfun/cospi.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,76 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 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{y} =} cospi (@var{x})
+## Compute cosine (@var{x} * pi) for each element of @var{x} accurately.
+##
+## The ordinary @code{cos} function uses IEEE floating point numbers and may
+## produce results that are very close (within a few eps) of the correct
+## value, but which are not exact.  The @code{cospi} function is more accurate
+## and returns 0 exactly for half-integer values of @var{x} (e.g., @dots{},
+## -3/2, -1/2, 1/2, 3/2, @dots{}), and +1/-1 for integer values.
+##
+## Example @*
+## comparison of @code{cos} and @code{cospi} for half-integer values of @var{x}
+##
+## @example
+## @group
+## cos ([-3/2, -1/2, 1/2, 3/2] * pi)
+## @result{}
+##      -1.8370e-16   6.1232e-17   6.1232e-17  -1.8370e-16
+##
+## cospi ([-3/2, -1/2, 1/2, 3/2])
+## @result{}
+##        0   0   0   0
+## @end group
+## @end example
+##
+## @seealso{sinpi, cos}
+## @end deftypefn
+
+function y = cospi (x)
+
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  ## Advance phase by pi/2 so that algorithm from sinpi can be used.
+  ## Wrap integer multiples so that new domain is [-1, 1).
+  x = mod (x - 0.5, 2) - 1;
+
+  ## Integer multiples of pi must be exactly zero.
+  x(x == -1) = 0;
+
+  y = sin (x * pi);
+
+endfunction
+
+
+%!assert (cospi ([-3/2, -1/2, 1/2, 3/2]) == 0)
+%!assert (cospi ([-2, -1, 0, 1, 2]), [1, -1, 1, -1, 1])
+%!assert (cospi (100 + [0.1:0.1:0.9]), cos ([0.1:0.1:0.9]*pi), 2*eps (100))
+
+%!error <Invalid call> cospi ()
--- a/scripts/elfun/cot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/cot.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = cot (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! v = [rt3, 1, rt3/3, 0, -rt3/3, -1, -rt3];
 %! assert (cot (x), v, sqrt (eps));
 
-%!error cot ()
-%!error cot (1, 2)
+%!error <Invalid call> cot ()
--- a/scripts/elfun/cotd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/cotd.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = cotd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -44,5 +44,4 @@
 %!assert (cotd ([0, 180, 360]) == Inf)
 %!assert (cotd ([90, 270]) == 0)
 
-%!error cotd ()
-%!error cotd (1, 2)
+%!error <Invalid call> cotd ()
--- a/scripts/elfun/coth.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/coth.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = coth (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,5 +45,4 @@
 %! v = [0, 0];
 %! assert (coth (x), v, sqrt (eps));
 
-%!error coth ()
-%!error coth (1, 2)
+%!error <Invalid call> coth ()
--- a/scripts/elfun/csc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/csc.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = csc (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! v = [2, rt2, 2*rt3/3, 1, 2*rt3/3, rt2, 2];
 %! assert (csc (x), v, sqrt (eps));
 
-%!error csc ()
-%!error csc (1, 2)
+%!error <Invalid call> csc ()
--- a/scripts/elfun/cscd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/cscd.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = cscd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -44,5 +44,4 @@
 %!assert (cscd ([0, 180, 360]) == Inf)
 %!assert (cscd ([90, 270]) != Inf)
 
-%!error cscd ()
-%!error cscd (1, 2)
+%!error <Invalid call> cscd ()
--- a/scripts/elfun/csch.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/csch.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = csch (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,5 +45,4 @@
 %! v = [-i, i];
 %! assert (csch (x), v, sqrt (eps));
 
-%!error csch ()
-%!error csch (1, 2)
+%!error <Invalid call> csch ()
--- a/scripts/elfun/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/acosd.m \
   %reldir%/acot.m \
   %reldir%/acotd.m \
@@ -15,6 +16,7 @@
   %reldir%/atan2d.m \
   %reldir%/atand.m \
   %reldir%/cosd.m \
+  %reldir%/cospi.m \
   %reldir%/cot.m \
   %reldir%/cotd.m \
   %reldir%/coth.m \
@@ -25,6 +27,7 @@
   %reldir%/secd.m \
   %reldir%/sech.m \
   %reldir%/sind.m \
+  %reldir%/sinpi.m \
   %reldir%/tand.m
 
 %canon_reldir%dir = $(fcnfiledir)/elfun
--- a/scripts/elfun/sec.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/sec.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = sec (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -47,5 +47,4 @@
 %! v = [1, 2*rt3/3, rt2, 2, -2, -rt2, -2*rt3/3, -1];
 %! assert (sec (x), v, sqrt (eps));
 
-%!error sec ()
-%!error sec (1, 2)
+%!error <Invalid call> sec ()
--- a/scripts/elfun/secd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/secd.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = secd (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -44,5 +44,4 @@
 %!assert (secd ([0, 180, 360]) != Inf)
 %!assert (secd ([90, 270]) == Inf)
 
-%!error secd ()
-%!error secd (1, 2)
+%!error <Invalid call> secd ()
--- a/scripts/elfun/sech.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/sech.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function y = sech (x)
 
-if (nargin != 1)
+if (nargin < 1)
     print_usage ();
   endif
 
@@ -45,5 +45,4 @@
 %! v = [1, -1];
 %! assert (sech (x), v, sqrt (eps));
 
-%!error sech ()
-%!error sech (1, 2)
+%!error <Invalid call> sech ()
--- a/scripts/elfun/sind.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/sind.m	Sun May 16 09:44:35 2021 +0200
@@ -27,26 +27,52 @@
 ## @deftypefn {} {} sind (@var{x})
 ## Compute the sine for each element of @var{x} in degrees.
 ##
-## Returns zero for elements where @code{@var{x}/180} is an integer.
+## The function is more accurate than @code{sin} for large values of @var{x}
+## and for multiples of 180 degrees (@code{@var{x}/180} is an integer) where
+## @code{sind} returns 0 rather than a small value on the order of eps.
 ## @seealso{asind, sin}
 ## @end deftypefn
 
 function y = sind (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  I = x / 180;
-  y = sin (I .* pi);
-  y(I == fix (I) & isfinite (I)) = 0;
+  if (! isnumeric (x))
+    error ("sind: X must be numeric");
+  endif
+
+  x_iscomplex = iscomplex (x);
+  if (x_iscomplex)
+    xi = imag (x);
+  endif
+  x = real (x);
+
+  ## Wrap multiples so that new domain is [-180, 180)
+  x = mod (x-180, 360) - 180;
+
+  if (x_iscomplex)
+    y = sin (complex (x, xi) / 180 * pi);
+    ## Integer multiples of pi must be exactly zero
+    y(x == -180) = complex (0, imag (y(x == -180)));
+  else
+    y = sin (x / 180 * pi);
+    ## Integer multiples of pi must be exactly zero
+    y(x == -180) = 0;
+  endif
 
 endfunction
 
 
-%!assert (sind (10:10:90), sin (pi*[10:10:90]/180), -10*eps)
-%!assert (sind ([0, 180, 360]) == 0)
-%!assert (sind ([90, 270]) != 0)
+%!assert (sind (10:20:360), sin ([10:20:360] * pi/180), 5*eps)
+%!assert (sind ([-360, -180, 0, 180, 360]) == 0)
+%!assert (sind ([-270, -90, 90, 270]), [1, -1, 1, -1])
+%!assert (sind ([-Inf, NaN, +Inf, 0]), [NaN, NaN, NaN, 0])
+%!assert (sind (+23) == -sind (-23))
+%!assert (sind (1e6), -0.984807753012208, 5*eps)
+%!assert (sind (180 + 180i), -i*sinh (pi))
+%!assert (sind (1e6 + 180i), -11.415845458288851 + 2.0054175437381652i, 5*eps)
 
-%!error sind ()
-%!error sind (1, 2)
+%!error <Invalid call> sind ()
+%!error <X must be numeric> sind ("abc")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/elfun/sinpi.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,75 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 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{y} =} sinpi (@var{x})
+## Compute sine (@var{x} * pi) for each element of @var{x} accurately.
+##
+## The ordinary @code{sin} function uses IEEE floating point numbers and may
+## produce results that are very close (within a few eps) of the correct
+## value, but which are not exact.  The @code{sinpi} function is more accurate
+## and returns 0 exactly for integer values of @var{x} and +1/-1 for
+## half-integer values (e.g., @dots{}, -3/2, -1/2, 1/2, 3/2, @dots{}).
+##
+## Example @*
+## comparison of @code{sin} and @code{sinpi} for integer values of @var{x}
+##
+## @example
+## @group
+## sin ([0, 1, 2, 3] * pi)
+## @result{}
+##      0   1.2246e-16  -2.4493e-16   3.6739e-16
+##
+## sinpi ([0, 1, 2, 3])
+## @result{}
+##        0   0   0   0
+## @end group
+## @end example
+##
+## @seealso{cospi, sin}
+## @end deftypefn
+
+function y = sinpi (x)
+
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  ## Wrap integer multiples so that new domain is [-1, 1)
+  x = mod (x-1, 2) - 1;
+
+  ## Integer multiples of pi must be exactly zero
+  x(x == -1) = 0;
+
+  y = sin (x * pi);
+
+endfunction
+
+
+%!assert (sinpi ([-1, -2, 0, 1, 2]) == 0)
+%!assert (sinpi ([-3/2, -1/2, 1/2, 3/2]), [1, -1, 1, -1])
+%!assert (sinpi (100 + [0.1:0.1:0.9]), sin ([0.1:0.1:0.9]*pi), 2*eps (100))
+
+%!error <Invalid call> sinpi ()
--- a/scripts/elfun/tand.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/elfun/tand.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function y = tand (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -51,5 +51,4 @@
 %!assert (tand ([0, 180, 360]) == 0)
 %!assert (tand ([90, 270]) == Inf)
 
-%!error tand ()
-%!error tand (1, 2)
+%!error <Invalid call> tand ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/general/accumarray.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/accumarray.m	Sun May 16 09:44:35 2021 +0200
@@ -68,7 +68,7 @@
 ## that in the first column counts how many occurrences each number in
 ## the second column has, taken from the vector @var{x}.  Note the usage
 ## of @code{unique}  for assigning to all repeated elements of @var{x}
-## the same index (@pxref{XREFunique,,unique}).
+## the same index (@pxref{XREFunique,,@code{unique}}).
 ##
 ## @example
 ## @group
@@ -99,7 +99,7 @@
 ## @end example
 ##
 ## The sparse option can be used as an alternative to the @code{sparse}
-## constructor (@pxref{XREFsparse,,sparse}).  Thus
+## constructor (@pxref{XREFsparse,,@code{sparse}}).  Thus
 ##
 ## @example
 ## sparse (@var{i}, @var{j}, @var{sv})
@@ -134,7 +134,7 @@
 
 function A = accumarray (subs, vals, sz = [], func = [], fillval = [], issparse = [])
 
-  if (nargin < 2 || nargin > 6)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -442,8 +442,8 @@
 %! assert (accumarray (subsc, vals, [], @max),
 %!         accumarray (subs, vals, [], @max));
 
-%!error (accumarray (1:5))
-%!error (accumarray ([1,2,3],1:2))
+%!error accumarray (1:5)
+%!error accumarray ([1,2,3],1:2)
 
 ## Handle empty arrays
 %!test <*47287>
--- a/scripts/general/accumdim.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/accumdim.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 
 function A = accumdim (subs, vals, dim, n = 0, func = [], fillval = 0)
 
-  if (nargin < 2 || nargin > 6)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -172,8 +172,8 @@
 %!assert (accumdim ([1;3;1;3;3], a, 1, 4, [], pi)([2 4],:,:), pi (2,5,5))
 
 ## Test input validation
-%!error accumdim (1)
-%!error accumdim (1,2,3,4,5,6,7)
+%!error <Invalid call> accumdim ()
+%!error <Invalid call> accumdim (1)
 %!error <SUBS must be a subscript vector> accumdim (ones (2,2), ones (2,2))
 %!error <indices must be positive integers> accumdim ([-1 1], ones (2,2))
 %!error <N index out of range> accumdim ([1 2], ones (2,2), 1, 1)
--- a/scripts/general/bincoeff.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/bincoeff.m	Sun May 16 09:44:35 2021 +0200
@@ -118,7 +118,7 @@
 %!assert (bincoeff ([4 NaN 4], [-1, 2, 2.5]), NaN (1, 3))
 
 ## Test input validation
-%!error bincoeff ()
-%!error bincoeff (1, 2, 3)
-%!error bincoeff (ones (3),ones (2))
-%!error bincoeff (ones (2),ones (3))
+%!error <Invalid call> bincoeff ()
+%!error <Invalid call> bincoeff (1)
+%!error bincoeff (ones (3), ones (2))
+%!error bincoeff (ones (2), ones (3))
--- a/scripts/general/bitcmp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/bitcmp.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 
 function C = bitcmp (A, k)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/general/bitget.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/bitget.m	Sun May 16 09:44:35 2021 +0200
@@ -103,23 +103,19 @@
 %!   endfor
 %! endfor
 
-%!error bitget (0, 0)
-%!error bitget (0, 55)
-
-%!error bitget (single (0), 0)
-%!error bitget (single (0), 26)
-
-%!error bitget (int8 (0), 9)
-%!error bitget (uint8 (0), 9)
-
-%!error bitget (int16 (0), 17)
-%!error bitget (uint16 (0), 17)
-
-%!error bitget (int32 (0), 33)
-%!error bitget (uint32 (0), 33)
-
-%!error bitget (int64 (0), 65)
-%!error bitget (uint64 (0), 65)
-
-%!error bitget (1)
-%!error bitget (1, 2, 3)
+## Test input validation
+%!error <Invalid call> bitget ()
+%!error <Invalid call> bitget (1)
+%!error <invalid class> bitget ("char", 1)
+%!error <N must be in the range \[1,53\]> bitget (0, 0)
+%!error <N must be in the range \[1,53\]> bitget (0, 55)
+%!error <N must be in the range \[1,24\]> bitget (single (0), 0)
+%!error <N must be in the range \[1,24\]> bitget (single (0), 26)
+%!error <N must be in the range \[1,8\]> bitget (int8 (0), 9)
+%!error <N must be in the range \[1,8\]> bitget (uint8 (0), 9)
+%!error <N must be in the range \[1,16\]> bitget (int16 (0), 17)
+%!error <N must be in the range \[1,16\]> bitget (uint16 (0), 17)
+%!error <N must be in the range \[1,32\]> bitget (int32 (0), 33)
+%!error <N must be in the range \[1,32\]> bitget (uint32 (0), 33)
+%!error <N must be in the range \[1,64\]> bitget (int64 (0), 65)
+%!error <N must be in the range \[1,64\]> bitget (uint64 (0), 65)
--- a/scripts/general/bitset.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/bitset.m	Sun May 16 09:44:35 2021 +0200
@@ -64,7 +64,7 @@
 
 function C = bitset (A, n, val = true)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -141,8 +141,9 @@
 %!assert <*54110> (bitset (1:5, 1, 1), [1, 3, 3, 5, 5])
 %!assert (bitset (1:5, 1, [1, 1, 1, 1, 0]), [1, 3, 3, 5, 4])
 
-%!error bitset (1)
-%!error bitset (1, 2, 3, 4)
+## Test input validation
+%!error <Invalid call> bitset ()
+%!error <Invalid call> bitset (1)
 %!error <A must be .= 0> bitset (-1, 2)
 %!error <must be the same size or scalar> bitset (1, [1 2], [1 2 3])
 %!error <must be the same size or scalar> bitset ([1 2], [1 2 3])
--- a/scripts/general/cart2pol.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/cart2pol.m	Sun May 16 09:44:35 2021 +0200
@@ -28,69 +28,105 @@
 ## @deftypefnx {} {[@var{theta}, @var{r}, @var{z}] =} cart2pol (@var{x}, @var{y}, @var{z})
 ## @deftypefnx {} {[@var{theta}, @var{r}] =} cart2pol (@var{C})
 ## @deftypefnx {} {[@var{theta}, @var{r}, @var{z}] =} cart2pol (@var{C})
-## @deftypefnx {} {@var{P} =} cart2pol (@dots{})
 ##
 ## Transform Cartesian coordinates to polar or cylindrical coordinates.
 ##
 ## The inputs @var{x}, @var{y} (, and @var{z}) must be the same shape, or
 ## scalar.  If called with a single matrix argument then each row of @var{C}
-## represents the Cartesian coordinate (@var{x}, @var{y} (, @var{z})).
+## represents the Cartesian coordinate pair (@var{x}, @var{y}) or triplet
+## (@var{x}, @var{y}, @var{z}).
 ##
-## @var{theta} describes the angle relative to the positive x-axis.
+## The outputs @var{theta}, @var{r} (, and @var{z}) match the shape of the
+## inputs.  For a matrix input @var{C} the outputs will be column vectors with
+## rows corresponding to the rows of the input matrix.
+##
+## @var{theta} describes the angle relative to the positive x-axis measured in
+## the xy-plane.
 ##
 ## @var{r} is the distance to the z-axis @w{(0, 0, z)}.
 ##
-## If only a single return argument is requested then return a matrix @var{P}
-## where each row represents one polar/(cylindrical) coordinate
-## (@var{theta}, @var{phi} (, @var{z})).
+## @var{z}, if present, is unchanged by the transformation.
+##
+## The coordinate transformation is computed using:
+##
+## @tex
+## $$ \theta = \arctan \left ( {y \over x} \right ) $$
+## $$ r = \sqrt{x^2 + y^2} $$
+## $$ z = z $$
+## @end tex
+## @ifnottex
+##
+## @example
+## @group
+## @var{theta} = arctan (@var{y} / @var{x})
+## @var{r} = sqrt (@var{x}^2 + @var{y}^2)
+## @var{z} = @var{z}
+## @end group
+## @end example
+##
+## @end ifnottex
+##
+## @c FIXME: Remove this note in Octave 9.1 (two releases after 7.1).
+## Note: For @sc{matlab} compatibility, this function no longer returns a full
+## coordinate matrix when called with a single return argument.
 ## @seealso{pol2cart, cart2sph, sph2cart}
 ## @end deftypefn
 
 function [theta, r, z] = cart2pol (x, y, z = [])
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
   if (nargin == 1)
-    if (! (isnumeric (x) && ismatrix (x)
-           && (columns (x) == 2 || columns (x) == 3)))
-      error ("cart2pol: matrix input must have 2 or 3 columns [X, Y (, Z)]");
+    if (! (isnumeric (x) && ismatrix (x)))
+      error ("cart2pol: matrix input must be 2-D numeric array");
     endif
-    if (columns (x) == 3)
-      z = x(:,3);
+    if (isvector (x))
+      n = numel (x);
+      if (n != 2 && n != 3)
+        error ("cart2pol: matrix input must be a 2- or 3-element vector or a 2- or 3-column array");
+      endif
+      if (n == 3)
+        z = x(3);
+      endif
+      y = x(2);
+      x = x(1);
+    else
+      ncols = columns (x);
+      if (ncols != 2 && ncols != 3)
+        error ("cart2pol: matrix input must be a 2- or 3-element vector or a 2- or 3-column array");
+      endif
+
+      if (ncols == 3)
+        z = x(:,3);
+      endif
+      y = x(:,2);
+      x = x(:,1);
     endif
-    y = x(:,2);
-    x = x(:,1);
+
   elseif (nargin == 2)
-    if (! isnumeric (x) || ! isnumeric (y))
-      error ("cart2pol: X, Y must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (x) && isnumeric (y)))
+      error ("cart2pol: X, Y must be numeric arrays or scalars");
     endif
     [err, x, y] = common_size (x, y);
     if (err)
-      error ("cart2pol: X, Y must be numeric arrays of the same size, or scalar");
+      error ("cart2pol: X, Y must be the same size or scalars");
     endif
+
   elseif (nargin == 3)
-    if (! isnumeric (x) || ! isnumeric (y) || ! isnumeric (z))
-      error ("cart2pol: X, Y, Z must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (x) && isnumeric (y) && isnumeric (z)))
+      error ("cart2pol: X, Y, Z must be numeric arrays or scalars");
     endif
     [err, x, y, z] = common_size (x, y, z);
     if (err)
-      error ("cart2pol: X, Y, Z must be numeric arrays of the same size, or scalar");
+      error ("cart2pol: X, Y, Z must be the same size or scalars");
     endif
   endif
 
   theta = atan2 (y, x);
   r = sqrt (x .^ 2 + y .^ 2);
 
-  if (nargout <= 1)
-    if (isempty (z))
-      theta = [theta(:), r(:)];
-    else
-      theta = [theta(:), r(:), z(:)];
-    endif
-  endif
-
 endfunction
 
 
@@ -104,9 +140,16 @@
 %!test
 %! x = [0, 1, 2];
 %! y = [0, 1, 2];
-%! P = cart2pol (x, y);
-%! assert (P(:,1), [0; pi/4; pi/4], sqrt (eps));
-%! assert (P(:,2), sqrt (2)*[0; 1; 2], sqrt (eps));
+%! [t, r] = cart2pol (x, y);
+%! assert (t, [0, pi/4, pi/4], eps);
+%! assert (r, sqrt (2)*[0, 1, 2], eps);
+
+%!test
+%! x = [0, 1, 2]';
+%! y = [0, 1, 2]';
+%! [t, r] = cart2pol (x, y);
+%! assert (t, [0; pi/4; pi/4], eps);
+%! assert (r, sqrt (2)*[0; 1; 2], eps);
 
 %!test
 %! x = [0, 1, 2];
@@ -146,13 +189,23 @@
 
 %!test
 %! C = [0, 0; 1, 1; 2, 2];
-%! P = [0, 0; pi/4, sqrt(2); pi/4, 2*sqrt(2)];
-%! assert (cart2pol (C), P, sqrt (eps));
+%! [t, r] = cart2pol (C);
+%! assert (t, [0; 1; 1]*pi/4, eps);
+%! assert (r, [0; 1; 2]*sqrt(2), eps);
 
 %!test
 %! C = [0, 0, 0; 1, 1, 1; 2, 2, 2];
-%! P = [0, 0, 0; pi/4, sqrt(2), 1; pi/4, 2*sqrt(2), 2];
-%! assert (cart2pol (C), P, sqrt (eps));
+%! [t, r, z] = cart2pol (C);
+%! assert (t, [0; 1; 1]*pi/4, eps);
+%! assert (r, [0; 1; 2]*sqrt(2), eps);
+%! assert (z, [0; 1; 2]);
+
+%!test
+%! C = [0, 0, 0; 1, 1, 1; 2, 2, 2;1, 1, 1];
+%! [t, r, z] = cart2pol (C);
+%! assert (t, [0; 1; 1; 1]*pi/4, eps);
+%! assert (r, [0; 1; 2; 1]*sqrt(2), eps);
+%! assert (z, [0; 1; 2; 1]);
 
 %!test
 %! x = zeros (1, 1, 1, 2);
@@ -177,17 +230,19 @@
 %! assert (z, Z);
 
 ## Test input validation
-%!error cart2pol ()
+%!error <Invalid call> cart2pol ()
 %!error cart2pol (1,2,3,4)
-%!error <matrix input must have 2 or 3 columns> cart2pol ({1,2,3})
-%!error <matrix input must have 2 or 3 columns> cart2pol (ones (3,3,2))
-%!error <matrix input must have 2 or 3 columns> cart2pol ([1])
-%!error <matrix input must have 2 or 3 columns> cart2pol ([1,2,3,4])
-%!error <numeric arrays of the same size> cart2pol ({1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> cart2pol ([1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), ones (3,2,3))
-%!error <numeric arrays of the same size> cart2pol ({1,2,3}, [1,2,3], [1,2,3])
-%!error <numeric arrays of the same size> cart2pol ([1,2,3], {1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> cart2pol ([1,2,3], [1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), 1, ones (3,2,3))
-%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), ones (3,2,3), 1)
+%!error <matrix input must be 2-D numeric array> cart2pol ({1,2,3})
+%!error <matrix input must be 2-D numeric array> cart2pol (ones (3,3,2))
+%!error <matrix input must be a 2- or 3-element> cart2pol ([1])
+%!error <matrix input must be a 2- or 3-element> cart2pol ([1,2,3,4])
+%!error <must be numeric arrays or scalars> cart2pol ({1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> cart2pol ([1,2,3], {1,2,3})
+%!error <must be the same size or scalars> cart2pol (ones (3,3,3), ones (3,2,3))
+%!error <must be the same size or scalars> cart2pol ([1; 1], [2, 2])
+%!error <must be the same size or scalars> cart2pol ([1; 1], [2, 2], [3, 3])
+%!error <must be numeric arrays or scalars> cart2pol ({1,2,3}, [1,2,3], [1,2,3])
+%!error <must be numeric arrays or scalars> cart2pol ([1,2,3], {1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> cart2pol ([1,2,3], [1,2,3], {1,2,3})
+%!error <must be the same size or scalars> cart2pol (ones (3,3,3), 1, ones (3,2,3))
+%!error <must be the same size or scalars> cart2pol (ones (3,3,3), ones (3,2,3), 1)
--- a/scripts/general/cart2sph.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/cart2sph.m	Sun May 16 09:44:35 2021 +0200
@@ -26,22 +26,45 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {[@var{theta}, @var{phi}, @var{r}] =} cart2sph (@var{x}, @var{y}, @var{z})
 ## @deftypefnx {} {[@var{theta}, @var{phi}, @var{r}] =} cart2sph (@var{C})
-## @deftypefnx {} {@var{S} =} cart2sph (@dots{})
 ## Transform Cartesian coordinates to spherical coordinates.
 ##
 ## The inputs @var{x}, @var{y}, and @var{z} must be the same shape, or scalar.
-## If called with a single matrix argument then each row of @var{C} represents
-## the Cartesian coordinate (@var{x}, @var{y}, @var{z}).
+## If called with a single matrix argument then each row of @var{C} must
+## represent a Cartesian coordinate triplet (@var{x}, @var{y}, @var{z}).
 ##
-## @var{theta} describes the angle relative to the positive x-axis.
+## The outputs @var{theta}, @var{phi}, @var{r} match the shape of the inputs.
+## For a matrix input @var{C} the outputs will be column vectors with rows
+## corresponding to the rows of the input matrix.
 ##
-## @var{phi} is the angle relative to the xy-plane.
+## @var{theta} describes the azimuth angle relative to the positive x-axis
+## measured in the xy-plane.
+##
+## @var{phi} is the elevation angle measured relative to the xy-plane.
 ##
 ## @var{r} is the distance to the origin @w{(0, 0, 0)}.
 ##
-## If only a single return argument is requested then return a matrix @var{S}
-## where each row represents one spherical coordinate
-## (@var{theta}, @var{phi}, @var{r}).
+## The coordinate transformation is computed using:
+##
+## @tex
+## $$ \theta = \arctan \left ({y \over x} \right ) $$
+## $$ \phi = \arctan \left ( {z \over {\sqrt{x^2+y^2}}} \right ) $$
+## $$ r = \sqrt{x^2 + y^2 + z^2} $$
+## @end tex
+## @ifnottex
+##
+## @example
+## @group
+## @var{theta} = arctan (@var{y} / @var{x})
+## @var{phi} = arctan (@var{z} / sqrt (@var{x}^2 + @var{y}^2))
+## @var{r} = sqrt (@var{x}^2 + @var{y}^2 + @var{z}^2)
+## @end group
+## @end example
+##
+## @end ifnottex
+##
+## @c FIXME: Remove this note in Octave 9.1 (two releases after 7.1).
+## Note: For @sc{matlab} compatibility, this function no longer returns a full
+## coordinate matrix when called with a single return argument.
 ## @seealso{sph2cart, cart2pol, pol2cart}
 ## @end deftypefn
 
@@ -52,19 +75,29 @@
   endif
 
   if (nargin == 1)
-    if (! (isnumeric (x) && ismatrix (x) && columns (x) == 3))
-      error ("cart2sph: matrix input must have 3 columns [X, Y, Z]");
+    if (! (isnumeric (x) && ismatrix (x)))
+      error ("cart2sph: matrix input C must be a 2-D numeric array");
+    elseif (columns (x) != 3 && numel (x) != 3)
+      error ("cart2sph: matrix input C must be a 3-element vector or 3-column array");
     endif
-    z = x(:,3);
-    y = x(:,2);
-    x = x(:,1);
+
+    if (numel (x) == 3)
+      z = x(3);
+      y = x(2);
+      x = x(1);
+    else
+      z = x(:,3);
+      y = x(:,2);
+      x = x(:,1);
+    endif
+
   else
-    if (! isnumeric (x) || ! isnumeric (y) || ! isnumeric (z))
-      error ("cart2sph: X, Y, Z must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (x) && isnumeric (y) && isnumeric (z)))
+      error ("cart2sph: X, Y, Z must be numeric arrays or scalars");
     endif
     [err, x, y, z] = common_size (x, y, z);
     if (err)
-      error ("cart2sph: X, Y, Z must be numeric arrays of the same size, or scalar");
+      error ("cart2sph: X, Y, Z must be the same size or scalars");
     endif
   endif
 
@@ -72,10 +105,6 @@
   phi = atan2 (z, sqrt (x .^ 2 + y .^ 2));
   r = sqrt (x .^ 2 + y .^ 2 + z .^ 2);
 
-  if (nargout <= 1)
-    theta = [theta(:), phi(:), r(:)];
-  endif
-
 endfunction
 
 
@@ -89,13 +118,22 @@
 %! assert (r, [0, 1, 2]*sqrt (3), eps);
 
 %!test
+%! x = [0; 1; 2];
+%! y = [0; 1; 2];
+%! z = [0; 1; 2];
+%! [t, p, r] = cart2sph (x, y, z);
+%! assert (t, [0; pi/4; pi/4], eps);
+%! assert (p, [0; 1; 1] * atan (sqrt (0.5)), eps);
+%! assert (r, [0; 1; 2] * sqrt (3), eps);
+
+%!test
 %! x = 0;
 %! y = [0, 1, 2];
 %! z = [0, 1, 2];
-%! S = cart2sph (x, y, z);
-%! assert (S(:,1), [0; 1; 1] * pi/2, eps);
-%! assert (S(:,2), [0; 1; 1] * pi/4, eps);
-%! assert (S(:,3), [0; 1; 2] * sqrt (2), eps);
+%! [t, p, r] = cart2sph (x, y, z);
+%! assert (t, [0, 1, 1] * pi/2, eps);
+%! assert (p, [0, 1, 1] * pi/4, eps);
+%! assert (r, [0, 1, 2] * sqrt (2), eps);
 
 %!test
 %! x = [0, 1, 2];
@@ -103,17 +141,17 @@
 %! z = [0, 1, 2];
 %! [t, p, r] = cart2sph (x, y, z);
 %! assert (t, [0, 0, 0]);
-%! assert (p, [0, 1, 1] * pi/4);
-%! assert (r, [0, 1, 2] * sqrt (2));
+%! assert (p, [0, 1, 1] * pi/4, eps);
+%! assert (r, [0, 1, 2] * sqrt (2), eps);
 
 %!test
 %! x = [0, 1, 2];
 %! y = [0, 1, 2];
 %! z = 0;
 %! [t, p, r] = cart2sph (x, y, z);
-%! assert (t, [0, 1, 1] * pi/4);
+%! assert (t, [0, 1, 1] * pi/4, eps);
 %! assert (p, [0, 0, 0]);
-%! assert (r, [0, 1, 2] * sqrt (2));
+%! assert (r, [0, 1, 2] * sqrt (2), eps);
 
 %!test
 %! x = 0;
@@ -121,13 +159,22 @@
 %! z = [0, 1, 2];
 %! [t, p, r] = cart2sph (x, y, z);
 %! assert (t, [0, 0, 0]);
-%! assert (p, [0, 1, 1] * pi/2);
+%! assert (p, [0, 1, 1] * pi/2, eps);
 %! assert (r, [0, 1, 2]);
 
 %!test
 %! C = [0, 0, 0; 1, 0, 1; 2, 0, 2];
-%! S = [0, 0, 0; 0, pi/4, sqrt(2); 0, pi/4, 2*sqrt(2)];
-%! assert (cart2sph (C), S, eps);
+%! [t, p, r] = cart2sph (C);
+%! assert (t, [0; 0; 0]);
+%! assert (p, [0; 1; 1] * pi/4, eps);
+%! assert (r, [0; 1; 2] * sqrt (2), eps);
+
+%!test
+%! C = [0, 0, 0; 1, 0, 1; 2, 0, 2; 1, 0, 1];
+%! [t, p, r] = cart2sph (C);
+%! assert (t, [0; 0; 0; 0]);
+%! assert (p, [0; 1; 1; 1] * pi/4, eps);
+%! assert (r, [0; 1; 2; 1] * sqrt (2), eps);
 
 %!test
 %! [x, y, z] = meshgrid ([0, 1], [0, 1], [0, 1]);
@@ -142,14 +189,15 @@
 %! assert (r, R, eps);
 
 ## Test input validation
-%!error cart2sph ()
-%!error cart2sph (1,2)
-%!error cart2sph (1,2,3,4)
-%!error <matrix input must have 3 columns> cart2sph ({1,2,3})
-%!error <matrix input must have 3 columns> cart2sph (ones (3,3,2))
-%!error <matrix input must have 3 columns> cart2sph ([1,2,3,4])
-%!error <numeric arrays of the same size> cart2sph ({1,2,3}, [1,2,3], [1,2,3])
-%!error <numeric arrays of the same size> cart2sph ([1,2,3], {1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> cart2sph ([1,2,3], [1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> cart2sph (ones (3,3,3), 1, ones (3,2,3))
-%!error <numeric arrays of the same size> cart2sph (ones (3,3,3), ones (3,2,3), 1)
+%!error <Invalid call> cart2sph ()
+%!error <Invalid call> cart2sph (1,2)
+%!error <matrix input C must be a 2-D numeric array> cart2sph ({1,2,3})
+%!error <matrix input C must be a 2-D numeric array> cart2sph (ones (3,3,2))
+%!error <matrix input C must be a 3-element> cart2sph ([1,2,3,4])
+%!error <matrix input C must be a 3-element> cart2sph ([1,2,3,4; 1,2,3,4; 1,2,3,4])
+%!error <must be numeric arrays or scalars> cart2sph ({1,2,3}, [1,2,3], [1,2,3])
+%!error <must be numeric arrays or scalars> cart2sph ([1,2,3], {1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> cart2sph ([1,2,3], [1,2,3], {1,2,3})
+%!error <must be the same size or scalars> cart2sph ([1,2,3], [1,2,3], [1,2,3]')
+%!error <must be the same size or scalars> cart2sph (ones (3,3,3), 1, ones (3,2,3))
+%!error <must be the same size or scalars> cart2sph (ones (3,3,3), ones (3,2,3), 1)
--- a/scripts/general/cell2mat.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/cell2mat.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function m = cell2mat (c)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -130,8 +130,7 @@
 %!assert (cell2mat ({"foo", "lol"; "bar", "qux"}),
 %!        reshape ("fboaorlqoulx", [2 6]))
 
-%!error cell2mat ()
-%!error cell2mat (1,2)
+%!error <Invalid call> cell2mat ()
 %!error <C must be a cell array> cell2mat ([1,2])
 %!error <mixed cells, structs, and matrices> cell2mat ({[1], struct()})
 %!error <mixed cells, structs, and matrices> cell2mat ({[1], {1}})
--- a/scripts/general/celldisp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/celldisp.m	Sun May 16 09:44:35 2021 +0200
@@ -55,7 +55,7 @@
 
 function celldisp (c, name)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -98,6 +98,6 @@
 %! celldisp (c, "b")
 
 ## Test input validation
-%!error celldisp ()
+%!error <Invalid call> celldisp ()
 %!error celldisp ({}, "name", 1)
 %!error <C must be a cell array> celldisp (1)
--- a/scripts/general/circshift.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/circshift.m	Sun May 16 09:44:35 2021 +0200
@@ -74,7 +74,7 @@
 
 function y = circshift (x, n, dim)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -141,9 +141,8 @@
 %!test <*53178> assert (circshift (1:4, 1, 1), 1:4)
 
 ## Test input validation
-%!error circshift ()
-%!error circshift (1)
-%!error circshift (1,2,3)
+%!error <Invalid call> circshift ()
+%!error <Invalid call> circshift (1)
 %!error <N must be a scalar> circshift (1, [2 3], 4)
 %!error <N must be a vector> circshift (1, ones (2,2))
 %!error <no longer than the number of dimensions in X> circshift (1, [1 2 3])
--- a/scripts/general/common_size.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/common_size.m	Sun May 16 09:44:35 2021 +0200
@@ -99,5 +99,6 @@
 %! assert (b, []);
 %! assert (c, 5);
 
-%!error common_size ()
-%!error common_size (1)
+## Test input validation
+%!error <only makes sense if nargin .= 2> common_size ()
+%!error <only makes sense if nargin .= 2> common_size (1)
--- a/scripts/general/cplxpair.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/cplxpair.m	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
 
 function y = cplxpair (z, tol, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -153,9 +153,9 @@
 
 %!shared z,y
 %! z = exp (2i*pi*[4; 3; 5; 2; 6; 1; 0]/7);
-%! z(2) = conj(z(1));
-%! z(4) = conj(z(3));
-%! z(6) = conj(z(5));
+%! z(2) = conj (z(1));
+%! z(4) = conj (z(3));
+%! z(6) = conj (z(5));
 %!assert (cplxpair (z(randperm (7))), z)
 %!assert (cplxpair (z(randperm (7))), z)
 %!assert (cplxpair (z(randperm (7))), z)
@@ -175,8 +175,7 @@
 %! cplxpair ([2e6 + j; 2e6 - j; 1e-9 * (1 + j); 1e-9 * (1 - 2j)]);
 
 ## Test input validation
-%!error cplxpair ()
-%!error cplxpair (1,2,3,4)
+%!error <Invalid call> cplxpair ()
 %!error <cplxpair: TOL must be .* scalar number> cplxpair (1, ones (2,2))
 %!error <cplxpair: TOL must be .* in the range 0 <= TOL < 1> cplxpair (1, -1)
 %!error <cplxpair: TOL must be .* in the range 0 <= TOL < 1> cplxpair (1, -1)
--- a/scripts/general/cumtrapz.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/cumtrapz.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 
 function z = cumtrapz (x, y, dim)
 
-  if (nargin < 1) || (nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -158,8 +158,7 @@
 %!assert (cumtrapz (x2,y,3), reshape ([0,3,8;0,9,20],[1 2 3]))
 
 ## Test input validation
-%!error cumtrapz ()
-%!error cumtrapz (1,2,3,4)
+%!error <Invalid call> cumtrapz ()
 %!error <DIM must be an integer> cumtrapz (1, 2, [1 2])
 %!error <DIM must be an integer> cumtrapz (1, 2, 1.5)
 %!error <DIM must be .* a valid dimension> cumtrapz (1, 2, 0)
--- a/scripts/general/deal.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/deal.m	Sun May 16 09:44:35 2021 +0200
@@ -84,7 +84,7 @@
 ## @seealso{cell2struct, struct2cell, repmat}
 ## @end deftypefn
 
-function [varargout] = deal (varargin)
+function varargout = deal (varargin)
 
   if (nargin == 0)
     print_usage ();
@@ -106,5 +106,6 @@
 %! assert (a, 1);
 %! assert (b, 1);
 
-%!error deal ()
+## Test input validation
+%!error <Invalid call> deal ()
 %!error <nargin . 1 and nargin != nargout> y = deal (1, 2)
--- a/scripts/general/deg2rad.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/deg2rad.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
 
 function rad = deg2rad (deg)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -67,7 +67,6 @@
 %!assert (deg2rad ([0, 90, 180, 270, 360]), pi*[0, 1/2, 1, 3/2, 2])
 
 ## Test input validation
-%!error deg2rad ()
-%!error deg2rad (1, 2)
+%!error <Invalid call> deg2rad ()
 %!error <DEG must be a floating point class> deg2rad (uint8 (1))
 %!error <DEG must be a floating point class> deg2rad ("A")
--- a/scripts/general/del2.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/del2.m	Sun May 16 09:44:35 2021 +0200
@@ -334,8 +334,8 @@
 %! L = 4*del2 (U, x);
 
 ## Test input validation
-%!error del2 ()
-%!error del2 (1, 1, 2, 3)
+%!error <Invalid call> del2 ()
+%!error <Invalid call> del2 (1, 1, 2, 3)
 %!error <in spacing vector 1> del2 (1, 2, [1 1])
 %!error <in spacing vector 2> del2 (1, [1 1], 2)
 %!error <must be a scalar or vector> del2 (1, ones (2,2), 2)
--- a/scripts/general/flip.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/flip.m	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
 
 function y = flip (x, dim)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -107,6 +107,5 @@
 %! assert (flip (a, 4), b);
 %! assert (flip (a, 5), a);
 
-%!error flip ()
-%!error flip (1, 2, 3)
+%!error <Invalid call> flip ()
 %!error <DIM must be a positive integer> flip (magic (3), -1)
--- a/scripts/general/fliplr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/fliplr.m	Sun May 16 09:44:35 2021 +0200
@@ -43,9 +43,10 @@
 
 function y = fliplr (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
+
   y = flip (x, 2);
 
 endfunction
@@ -78,5 +79,5 @@
 %! a(:,1,:,2) = [ 5  6  7  8];
 %! assert (fliplr (a), a);
 
-%!error fliplr()
-%!error fliplr (1, 2)
+## Test input validation
+%!error <Invalid call> fliplr ()
--- a/scripts/general/flipud.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/flipud.m	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,7 @@
 
 function y = flipud (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
   y = flip (x, 1);
@@ -78,5 +78,4 @@
 %! a(1,:,:,2) = [ 5  6  7  8];
 %! assert (flipud (a), a);
 
-%!error flipud ()
-%!error flipud (1, 2)
+%!error <Invalid call> flipud ()
--- a/scripts/general/gradient.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/gradient.m	Sun May 16 09:44:35 2021 +0200
@@ -125,7 +125,7 @@
     endif
   else
     ## have spacing value for each dimension
-    if (length(varargin) != nd)
+    if (length (varargin) != nd)
       error ("gradient: dimensions and number of spacing values do not match");
     endif
     for i = 1:nd
--- a/scripts/general/idivide.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/idivide.m	Sun May 16 09:44:35 2021 +0200
@@ -74,7 +74,7 @@
 
 function z = idivide (x, y, op)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/general/int2str.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/int2str.m	Sun May 16 09:44:35 2021 +0200
@@ -60,7 +60,7 @@
 
 function retval = int2str (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isnumeric (n) || islogical (n) || ischar (n)))
     error ("int2str: N must be a numeric, logical, or character array");
@@ -108,6 +108,5 @@
 %!assert (int2str ([1, 2, 3; 4, 5, 6]), ["1  2  3";"4  5  6"])
 %!assert (int2str ([]), "")
 
-%!error int2str ()
-%!error int2str (1, 2)
+%!error <Invalid call> int2str ()
 %!error <N must be a numeric> int2str ({1})
--- a/scripts/general/integral.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/integral.m	Sun May 16 09:44:35 2021 +0200
@@ -30,11 +30,12 @@
 ## Numerically evaluate the integral of @var{f} from @var{a} to @var{b} using
 ## adaptive quadrature.
 ##
-## @code{integral} is a wrapper for @code{quadcc} (general scalar integrands),
-## @code{quadgk} (integrals with specified integration paths), and @code{quadv}
-## (array-valued integrands) that is intended to provide @sc{matlab}
-## compatibility.  More control of the numerical integration may be achievable
-## by calling the various quadrature functions directly.
+## @code{integral} is a wrapper for @code{quadcc} (general real-valued, scalar
+## integrands and limits), @code{quadgk} (integrals with specified integration
+## paths), and @code{quadv} (array-valued integrands) that is intended to
+## provide @sc{matlab} compatibility.  More control of the numerical
+## integration may be achievable by calling the various quadrature functions
+## directly.
 ##
 ## @var{f} is a function handle, inline function, or string containing the name
 ## of the function to evaluate.  The function @var{f} must be vectorized and
@@ -54,14 +55,14 @@
 ## Specifies points to be used in defining subintervals of the quadrature
 ## algorithm, or if @var{a}, @var{b}, or @var{waypoints} are complex then
 ## the quadrature is calculated as a contour integral along a piecewise
-## continuous path.  For more detail see @code{quadgk}.
+## continuous path.  For more detail, @pxref{XREFquadgk,,@code{quadgk}}.
 ##
 ## @item ArrayValued
 ## @code{integral} expects @var{f} to return a scalar value unless
 ## @var{arrayvalued} is specified as true.  This option will cause
 ## @code{integral} to perform the integration over the entire array and return
 ## @var{q} with the same dimensions as returned by @var{f}.  For more detail
-## see @code{quadv}.
+## @pxref{XREFquadv,,@code{quadv}}.
 ##
 ## @item AbsTol
 ## Define the absolute error tolerance for the quadrature.  The default
@@ -115,10 +116,35 @@
     print_usage ();
   endif
 
+  ## quadcc can't handle complex limits or integrands, but quadgk & quadv can.
+  ## Check for simple cases of complex limits and integrand.
+  f_is_complex = false;
+  if (iscomplex (a) || iscomplex (b))
+    f_is_complex = true;
+  elseif (iscomplex (feval (f, a)) || iscomplex (feval (f, b)))
+    f_is_complex = true;
+  endif
+
   if (nargin == 3)
     ## Pass the simplest case directly to general integrator.
     ## Let quadcc function handle input checks on function and limits.
-    q = quadcc (f, a, b);
+    if (! f_is_complex)
+      try
+        q = quadcc (f, a, b);
+      catch quaderror
+        if (strcmp (quaderror.message,
+                    "quadcc: integrand F must return a single, real-valued vector"))
+          q = quadgk (f, a, b);
+        else
+          error (quaderror.message);
+        endif
+      end_try_catch
+
+    else
+      ## Complex-valued integral
+      q = quadgk (f, a, b);
+    endif
+
   else
     ## Parse options to determine how to call integrator.
     abstol = [];
@@ -155,13 +181,13 @@
 
       ## FIXME: Replace warning when have array compatible call with waypoints
       if (! isempty (waypoints))
-        warning(["integral: array-valued quadrature routine currently ", ...
+        warning (["integral: array-valued quadrature routine currently ", ...
                  "unable to handle WayPoints.  WayPoints are ignored."]);
       endif
 
       ## FIXME: Remove warning once we have reltol compatible arrayval'd quadfn
       if (! isempty (reltol))
-        warning(["integral: array-valued quadrature only accepts AbsTol.", ...
+        warning (["integral: array-valued quadrature only accepts AbsTol.", ...
                  "  RelTol ignored."]);
       endif
       if (isempty (abstol))
@@ -182,7 +208,21 @@
         q = quadgk (f, a, b, "AbsTol", abstol, "RelTol", reltol,
                              "WayPoints", waypoints);
       else
-        q = quadcc (f, a, b, [abstol, reltol]);
+        if (! f_is_complex)
+          try
+            q = quadcc (f, a, b, [abstol, reltol]);
+          catch quaderror
+            if (strcmp (quaderror.message,
+                        "quadcc: integrand F must return a single, real-valued vector"))
+              q = quadgk (f, a, b, "AbsTol", abstol, "RelTol", reltol);
+            else
+              error (quaderror.message);
+            endif
+          end_try_catch
+        else
+          ## Complex-valued integral
+          q = quadgk (f, a, b, "AbsTol", abstol, "RelTol", reltol);
+        endif
       endif
     endif
   endif
@@ -203,7 +243,7 @@
 %! assert (integral (@(x) f(x,5), 0, 2), -0.4605015338467329, 1e-10);
 
 %!test  # with tolerances
-%! f = @(x) log(x);
+%! f = @(x) log (x);
 %! assert (integral (@(x) f(x), 0, 1, "AbsTol", 1e-6), -1, 1e-6);
 
 %!test  # waypoints
@@ -216,15 +256,22 @@
 %!         1e-10);
 
 %!test  # test single input/output
-%! assert (integral (@sin, 0, 1), cos(0)-cos(1), 1e-10);
+%! assert (integral (@sin, 0, 1), cos (0)-cos (1), 1e-10);
 %! assert (class (integral (@sin, single (0), 1)), "single");
 %! assert (class (integral (@sin, 0, single (1))), "single");
 %! assert (class (integral (@sin, single (0), single (1))), "single");
-%! assert (integral (@sin, 0, 1, "Waypoints", 0.5), cos(0)-cos(1), 1e-10);
+%! assert (integral (@sin, 0, 1, "Waypoints", 0.5), cos (0)-cos (1), 1e-10);
 %! assert (class (integral (@sin, 0, 1, "Waypoints", single (0.5))), "single");
 %! assert (class (integral (@sin, single (0), 1, "Waypoints", 0.5)), "single");
 %! assert (class (integral (@sin, 0, single (1), "Waypoints", 0.5)), "single");
 
+%!test  # test complex argument handling
+%! f = @(x) round (exp (i*x));
+%! assert (integral (f, 0, pi), quadgk (f, 0, pi), eps);
+%! assert (integral (f, -1, 1), 2, 5*eps);
+%! assert (integral (@sin, -i, i), 0, eps);
+%! assert (1.5 * integral (@sqrt, -1, 0), i, eps);
+
 %!test
 %! f = @(x) x.^5 .* exp (-x) .* sin (x);
 %! assert (integral (f, 0, inf, "RelTol", 1e-8, "AbsTol", 1e-12), -15, -1e-8);
--- a/scripts/general/integral2.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/integral2.m	Sun May 16 09:44:35 2021 +0200
@@ -303,12 +303,12 @@
 %!assert (integral2 (@plus, 1, 2, 3, 4, "method", "iterated"), 5, 1e-10)
 
 ## Test input validation
-%!error integral2 ()
-%!error integral2 (@plus)
-%!error integral2 (@plus, 1)
-%!error integral2 (@plus, 1, 2)
-%!error integral2 (@plus, 1, 2, 3)
-%!error integral2 (@plus, 1, 2, 3, 4, "foo")
+%!error <Invalid call> integral2 ()
+%!error <Invalid call> integral2 (@plus)
+%!error <Invalid call> integral2 (@plus, 1)
+%!error <Invalid call> integral2 (@plus, 1, 2)
+%!error <Invalid call> integral2 (@plus, 1, 2, 3)
+%!error <Invalid call> integral2 (@plus, 1, 2, 3, 4, "foo")
 %!error integral2 (0, 1, 2, 3, 4)          # f must be function handle
 %!error integral2 (@plus, 1i, 2, 3, 4)     # real limits
 %!error integral2 (@plus, 1, 2i, 3, 4)     # real limits
--- a/scripts/general/integral3.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/integral3.m	Sun May 16 09:44:35 2021 +0200
@@ -241,11 +241,11 @@
     if (! (isreal (za) && isscalar (za)))
       error ("integral3: ZA must be a real scalar or a function");
     endif
-    za = @(x, y) za * ones (size(y));
+    za = @(x, y) za * ones (size (y));
   endif
   if (! is_function_handle (zb))
     if (! (isreal (zb) && isscalar (zb)))
-      error ("integral3: ZB must be a real scalar or a function")
+      error ("integral3: ZB must be a real scalar or a function");
     endif
     zb = @(x, y) zb * ones (size (y));
   endif
@@ -286,10 +286,10 @@
 %!shared f
 %! f = @(x, y, z) x .* y .* z;
 
-%!assert (integral3 (f, 0, 1, 0, 1, 0, 1), 0.125, 1e-10);
-%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "tiled"), 0.125, 1e-10);
-%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "iterated"), 0.125, 1e-10);
-%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "auto"), 0.125, 1e-10);
+%!assert (integral3 (f, 0, 1, 0, 1, 0, 1), 0.125, 1e-10)
+%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "tiled"), 0.125, 1e-10)
+%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "iterated"), 0.125, 1e-10)
+%!assert (integral3 (f, 0, 1, 0, 1, 0, 1, "method", "auto"), 0.125, 1e-10)
 
 ## vectorized = false test
 %!test
--- a/scripts/general/interp1.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/interp1.m	Sun May 16 09:44:35 2021 +0200
@@ -778,8 +778,9 @@
 %!assert (interp1 ([1,2,2,3,4],[0,1,4,2,1],[-1,1.5,2,2.5,3.5], "linear", "extrap", "left"), [-2,0.5,1,3,1.5])
 
 ## Test input validation
-%!error interp1 ()
-%!error interp1 (1,2,3,4,5,6,7)
+%!error <Invalid call> interp1 ()
+%!error <Invalid call> interp1 (1)
+%!error <Invalid call> interp1 (1,2,3,4,5,6,7)
 %!error <minimum of 2 points required> interp1 (1,1,1, "linear")
 %!error <minimum of 2 points required> interp1 (1,1,1, "*nearest")
 %!error <minimum of 2 points required> interp1 (1,1,1, "*linear")
--- a/scripts/general/interp2.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/interp2.m	Sun May 16 09:44:35 2021 +0200
@@ -568,14 +568,14 @@
 %!error <X, Y must be numeric matrices> interp2 (1, {1}, ones (2), 1, 1)
 %!error <XI, YI must be numeric> interp2 (1, 1, ones (2), {1}, 1)
 %!error <XI, YI must be numeric> interp2 (1, 1, ones (2), 1, {1})
-%!error <X and Y must be matrices of equal size> interp2 (ones(2,2), 1, ones (2), 1, 1)
-%!error <X and Y must be matrices of equal size> interp2 (ones(2,2), ones(2,3), ones (2), 1, 1)
+%!error <X and Y must be matrices of equal size> interp2 (ones (2,2), 1, ones (2), 1, 1)
+%!error <X and Y must be matrices of equal size> interp2 (ones (2,2), ones (2,3), ones (2), 1, 1)
 %!error <X and Y size must match the dimensions of Z> interp2 (1:3, 1:3, ones (3,2), 1, 1)
 %!error <X and Y size must match the dimensions of Z> interp2 (1:2, 1:2, ones (3,2), 1, 1)
 %!error <X must be strictly monotonic> interp2 ([1 0 2], 1:3, ones (3,3), 1, 1)
 %!error <Y must be strictly monotonic> interp2 (1:3, [1 0 2], ones (3,3), 1, 1)
-%!error <XI and YI must be matrices of equal size> interp2 (1:2, 1:2, ones (2), ones(2,2), 1)
-%!error <XI and YI must be matrices of equal size> interp2 (1:2, 1:2, ones (2), 1, ones(2,2))
+%!error <XI and YI must be matrices of equal size> interp2 (1:2, 1:2, ones (2), ones (2,2), 1)
+%!error <XI and YI must be matrices of equal size> interp2 (1:2, 1:2, ones (2), 1, ones (2,2))
 %!error <XI, YI must have uniform spacing> interp2 (1:2, 1:2, ones (2), [1 2 4], [1 2 3], "spline")
 %!error <XI, YI must have uniform spacing> interp2 (1:2, 1:2, ones (2), [1 2 3], [1 2 4], "spline")
 %!error interp2 (1, 1, 1, 1, 1, "foobar")
--- a/scripts/general/interp3.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/interp3.m	Sun May 16 09:44:35 2021 +0200
@@ -255,7 +255,7 @@
 %! assert (vi, vi2);
 
 %!test  # extrapolation
-%! X=[0,0.5,1]; Y=X; Z=X;
+%! X = [0,0.5,1];  Y=X;  Z=X;
 %! V = zeros (3,3,3);
 %! V(:,:,1) = [1 3 5; 3 5 7; 5 7 9];
 %! V(:,:,2) = V(:,:,1) + 2;
--- a/scripts/general/interpft.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/interpft.m	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,7 @@
 
 function z = interpft (x, n, dim)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -111,18 +111,18 @@
 %! ti = t(1) + [0 : k-1]*dt*n/k;
 %! y = sin (4*t + 0.3) .* cos (3*t - 0.1);
 %! yp = sin (4*ti + 0.3) .* cos (3*ti - 0.1);
-%! plot (ti, yp, 'g', ti, interp1(t, y, ti, "spline"), 'b', ...
+%! plot (ti, yp, 'g', ti, interp1 (t, y, ti, "spline"), 'b', ...
 %!       ti, interpft (y, k), 'c', t, y, "r+");
-%! legend ("sin(4t+0.3)cos(3t-0.1)", "spline", "interpft", "data");
+%! legend ("sin (4t+0.3)cos (3t-0.1)", "spline", "interpft", "data");
 
 %!shared n,y
 %! x = [0:10]';  y = sin(x);  n = length (x);
 %!testif HAVE_FFTW
-%! assert (interpft (y, n), y, 20*eps)
+%! assert (interpft (y, n), y, 20*eps);
 %!testif HAVE_FFTW
-%! assert (interpft (y', n), y', 20*eps)
+%! assert (interpft (y', n), y', 20*eps);
 %!testif HAVE_FFTW
-%! assert (interpft ([y,y],n), [y,y], 20*eps)
+%! assert (interpft ([y,y],n), [y,y], 20*eps);
 
 ## Test case with complex input
 %!testif HAVE_FFTW <*39566>
@@ -132,18 +132,17 @@
 
 ## Test for correct spectral symmetry with even/odd lengths
 %!testif HAVE_FFTW
-%! assert (max (abs (imag (interpft ([1:8], 20)))), 0, 20*eps)
+%! assert (max (abs (imag (interpft ([1:8], 20)))), 0, 20*eps);
 %!testif HAVE_FFTW
-%! assert (max (abs (imag (interpft ([1:8], 21)))), 0, 21*eps)
+%! assert (max (abs (imag (interpft ([1:8], 21)))), 0, 21*eps);
 %!testif HAVE_FFTW
-%! assert (max (abs (imag (interpft ([1:9], 20)))), 0, 20*eps)
+%! assert (max (abs (imag (interpft ([1:9], 20)))), 0, 20*eps);
 %!testif HAVE_FFTW
-%! assert (max (abs (imag (interpft ([1:9], 21)))), 0, 21*eps)
+%! assert (max (abs (imag (interpft ([1:9], 21)))), 0, 21*eps);
 
 ## Test input validation
-%!error interpft ()
-%!error interpft (1)
-%!error interpft (1,2,3)
+%!error <Invalid call> interpft ()
+%!error <Invalid call> interpft (1)
 %!error <N must be a scalar integer> interpft (1,[2,2])
 %!error <N must be a scalar integer> interpft (1,2.1)
 %!error <invalid dimension DIM> interpft (1,2,0)
--- a/scripts/general/interpn.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/interpn.m	Sun May 16 09:44:35 2021 +0200
@@ -80,20 +80,21 @@
 ## must be specified as well.  If @var{extrapval} is omitted and the
 ## @var{method} is @qcode{"spline"}, then the extrapolated values of the
 ## @qcode{"spline"} are used.  Otherwise the default @var{extrapval} value for
-## any other @var{method} is @qcode{"NA"}.
+## any other @var{method} is @code{NA}.
 ## @seealso{interp1, interp2, interp3, spline, ndgrid}
 ## @end deftypefn
 
 function vi = interpn (varargin)
 
+  if (nargin < 1 || ! isnumeric (varargin{1}))
+    print_usage ();
+  endif
+
   method = "linear";
   extrapval = [];
   nargs = nargin;
 
-  if (nargin < 1 || ! isnumeric (varargin{1}))
-    print_usage ();
-  endif
-
+  ## Find and validate EXTRAPVAL and/or METHOD inputs
   if (nargs > 1 && ischar (varargin{end-1}))
     if (! isnumeric (varargin{end}) || ! isscalar (varargin{end}))
       error ("interpn: EXTRAPVAL must be a numeric scalar");
@@ -110,18 +111,17 @@
     warning ("interpn: ignoring unsupported '*' flag to METHOD");
     method(1) = [];
   endif
-  method = validatestring (method, ...
-    {"nearest", "linear", "pchip", "cubic", "spline"});
+  method = validatestring (method,
+                           {"nearest", "linear", "pchip", "cubic", "spline"},
+                           "interpn");
 
-  if (nargs < 3)
+  if (nargs <= 2)
+    ## Calling form interpn (V, ...)
     v = varargin{1};
     m = 1;
     if (nargs == 2)
-      if (ischar (varargin{2}))
-        method = varargin{2};
-      elseif (isnumeric (m) && isscalar (m) && fix (m) == m)
-        m = varargin{2};
-      else
+      m = varargin{2};
+      if (! (isnumeric (m) && isscalar (m) && m == fix (m)))
         print_usage ();
       endif
     endif
@@ -136,6 +136,7 @@
     y{1} = y{1}.';
     [y{:}] = ndgrid (y{:});
   elseif (! isvector (varargin{1}) && nargs == (ndims (varargin{1}) + 1))
+    ## Calling form interpn (V, Y1, Y2, ...)
     v = varargin{1};
     sz = size (v);
     nd = ndims (v);
@@ -146,6 +147,7 @@
     endfor
   elseif (rem (nargs, 2) == 1
           && nargs == (2 * ndims (varargin{ceil (nargs / 2)})) + 1)
+    ## Calling form interpn (X1, X2, ..., V, Y1, Y2, ...)
     nv = ceil (nargs / 2);
     v = varargin{nv};
     sz = size (v);
@@ -157,26 +159,20 @@
   endif
 
   if (any (! cellfun ("isvector", x)))
-    for i = 2 : nd
-      if (! size_equal (x{1}, x{i}) || ! size_equal (x{i}, v))
-        error ("interpn: dimensional mismatch");
+    for i = 1 : nd
+      if (! size_equal (x{i}, v))
+        error ("interpn: incorrect dimensions for input X%d", i);
       endif
       idx(1 : nd) = {1};
       idx(i) = ":";
       x{i} = x{i}(idx{:})(:);
     endfor
-    idx(1 : nd) = {1};
-    idx(1) = ":";
-    x{1} = x{1}(idx{:})(:);
   endif
 
-  method = tolower (method);
-
   all_vectors = all (cellfun ("isvector", y));
   same_size = size_equal (y{:});
   if (all_vectors && ! same_size)
-    [foobar(1:numel(y)).y] = ndgrid (y{:});
-    y = {foobar.y};
+    [y{:}] = ndgrid (y{:});
   endif
 
   if (strcmp (method, "linear"))
@@ -186,19 +182,25 @@
     endif
     vi(isna (vi)) = extrapval;
   elseif (strcmp (method, "nearest"))
+    ## FIXME: This seems overly complicated.  Is there a way to simplify
+    ## all the code after the call to lookup (which should be fast)?
+    ## Could Qhull be used for quick nearest neighbor calculation?
     yshape = size (y{1});
     yidx = cell (1, nd);
+    ## Find rough nearest index using lookup function [O(log2 (N)].
     for i = 1 : nd
       y{i} = y{i}(:);
       yidx{i} = lookup (x{i}, y{i}, "lr");
     endfor
+    ## Single comparison to next largest index to see which is closer.
     idx = cell (1,nd);
     for i = 1 : nd
       idx{i} = yidx{i} ...
                + (y{i} - x{i}(yidx{i})(:) >= x{i}(yidx{i} + 1)(:) - y{i});
     endfor
     vi = v(sub2ind (sz, idx{:}));
-    idx = zeros (prod (yshape), 1);
+    ## Apply EXTRAPVAL to points outside original volume.
+    idx = false (prod (yshape), 1);
     for i = 1 : nd
       idx |= y{i} < min (x{i}(:)) | y{i} > max (x{i}(:));
     endfor
@@ -209,17 +211,15 @@
     vi = reshape (vi, yshape);
   elseif (strcmp (method, "spline"))
     if (any (! cellfun ("isvector", y)))
-      for i = 2 : nd
-        if (! size_equal (y{1}, y{i}))
-          error ("interpn: dimensional mismatch");
+      ysz = size (y{1});
+      for i = 1 : nd
+        if (any (size (y{i}) != ysz))
+          error ("interpn: incorrect dimensions for input Y%d", i);
         endif
         idx(1 : nd) = {1};
         idx(i) = ":";
         y{i} = y{i}(idx{:});
       endfor
-      idx(1 : nd) = {1};
-      idx(1) = ":";
-      y{1} = y{1}(idx{:});
     endif
 
     vi = __splinen__ (x, v, y, extrapval, "interpn");
@@ -235,10 +235,10 @@
       vi = vi(cellfun (@(x) sub2ind (size (vi), x{:}), idx));
       vi = reshape (vi, size (y{1}));
     endif
+  elseif (strcmp (method, "pchip"))
+    error ("interpn: pchip interpolation not yet implemented");
   elseif (strcmp (method, "cubic"))
     error ("interpn: cubic interpolation not yet implemented");
-  else
-    error ("interpn: unrecognized interpolation METHOD");
   endif
 
 endfunction
@@ -353,4 +353,20 @@
 %! assert (interpn (z, "spline"), zout, tol);
 
 ## Test input validation
+%!error <Invalid call> interpn ()
+%!error <Invalid call> interpn ("foobar")
+%!error <EXTRAPVAL must be a numeric scalar> interpn (1, "linear", {1})
+%!error <EXTRAPVAL must be a numeric scalar> interpn (1, "linear", [1, 2])
 %!warning <ignoring unsupported '\*' flag> interpn (rand (3,3), 1, "*linear");
+%!error <'foobar' does not match any of> interpn (1, "foobar")
+%!error <wrong number or incorrectly formatted input arguments>
+%! interpn (1, 2, 3, 4);
+%!error <incorrect dimensions for input X1>
+%! interpn ([1,2], ones (2,2), magic (3), [1,2], [1,2])
+%!error <incorrect dimensions for input X2>
+%! interpn (ones (3,3), ones (2,2), magic (3), [1,2], [1,2])
+%!error <incorrect dimensions for input Y2>
+%! interpn ([1,2], [1,2], magic (3), [1,2], ones (2,2), "spline")
+%!error <pchip interpolation not yet implemented> interpn ([1,2], "pchip")
+%!error <cubic interpolation not yet implemented> interpn ([1,2], "cubic")
+
--- a/scripts/general/isequal.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/isequal.m	Sun May 16 09:44:35 2021 +0200
@@ -176,7 +176,7 @@
 
       endif
 
-    else  ## More than two args.  This is going to be slower in general.
+    else  # More than two args.  This is going to be slower in general.
 
       if (ischar (x) && all (cellfun ("isclass", varargin, "char")))
         ## char type.  Optimization, strcmp is ~35% faster than '==' operator.
@@ -545,5 +545,5 @@
 %!assert (isequal (sparse (1), sparse (1)), sparse (1), true)
 
 ## test input validation
-%!error isequal ()
-%!error isequal (1)
+%!error <Invalid call> isequal ()
+%!error <Invalid call> isequal (1)
--- a/scripts/general/isequaln.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/isequaln.m	Sun May 16 09:44:35 2021 +0200
@@ -174,7 +174,7 @@
 
       endif
 
-    else  ## More than two args.  This is going to be slower in general.
+    else  # More than two args.  This is going to be slower in general.
 
       if (ischar (x) && all (cellfun ("isclass", varargin, "char")))
         ## char type.  Optimization, strcmp is ~35% faster than '==' operator.
@@ -318,5 +318,5 @@
 %!assert (isequaln (st, st, st), true)
 
 ## Input validation
-%!error isequaln ()
-%!error isequaln (1)
+%!error <Invalid call> isequaln ()
+%!error <Invalid call> isequaln (1)
--- a/scripts/general/logspace.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/logspace.m	Sun May 16 09:44:35 2021 +0200
@@ -74,7 +74,7 @@
 
 function retval = logspace (a, b, n = 50)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -106,8 +106,14 @@
 ## Edge cases
 %!assert (logspace (Inf, Inf, 3), [Inf, Inf, Inf])
 %!assert (logspace (-Inf, Inf, 3), [0, 1, Inf])
-%!assert (logspace (Inf + 1i, Inf + 1i, 3), repmat (complex (-Inf,Inf), [1, 3]))
-%!assert (logspace (-Inf + 1i, Inf + 1i, 3), [0, NaN + NaN * 1i, complex(-Inf, Inf)])
+%!testif ; ! ismac ()
+%! assert (logspace (Inf + 1i, Inf + 1i, 3), repmat (complex (-Inf,Inf), [1, 3]))
+%!testif ; ismac () <55538>
+%! assert (logspace (Inf + 1i, Inf + 1i, 3), repmat (complex (-Inf,Inf), [1, 3]))
+%!testif ; ! ismac ()
+%! assert (logspace (-Inf + 1i, Inf + 1i, 3), [0, NaN + NaN * 1i, complex(-Inf, Inf)])
+%!testif ; ismac () <55538>
+%! assert (logspace (-Inf + 1i, Inf + 1i, 3), [0, NaN + NaN * 1i, complex(-Inf, Inf)])
 %!assert (logspace (0, Inf, 3), [1, Inf, Inf])
 %!assert (logspace (0, -Inf, 3), [1, 0, 0])
 %!assert (logspace (Inf, -Inf, 3), [Inf, 1, 0])
@@ -119,8 +125,7 @@
 ##%!assert (logspace (Inf, 0, 3), [Inf, NaN, 1])
 
 ## Test input validation
-%!error logspace ()
-%!error logspace (1, 2, 3, 4)
+%!error <Invalid call> logspace ()
 %!error logspace ([1, 2; 3, 4], 5, 6)
 %!error logspace (1, [1, 2; 3, 4], 6)
 %!error logspace (1, 2, [1, 2; 3, 4])
--- a/scripts/general/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -6,6 +6,7 @@
   %reldir%/private/__splinen__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/accumarray.m \
   %reldir%/accumdim.m \
   %reldir%/bincoeff.m \
@@ -60,6 +61,7 @@
   %reldir%/repelem.m \
   %reldir%/repmat.m \
   %reldir%/rescale.m \
+  %reldir%/rng.m \
   %reldir%/rot90.m \
   %reldir%/rotdim.m \
   %reldir%/shift.m \
--- a/scripts/general/nextpow2.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/nextpow2.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function n = nextpow2 (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,6 +73,5 @@
 %!assert (nextpow2 ([1, Inf, 3, -Inf, 9, NaN]), [0, Inf, 2, Inf, 4, NaN])
 
 ## Test input validation
-%!error nexpow2 ()
-%!error nexpow2 (1, 2)
+%!error <Invalid call> nextpow2 ()
 %!error <X must be numeric> nextpow2 ("t")
--- a/scripts/general/num2str.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/num2str.m	Sun May 16 09:44:35 2021 +0200
@@ -80,7 +80,7 @@
 
 function retval = num2str (x, arg)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isnumeric (x) || islogical (x) || ischar (x)))
     error ("num2str: X must be a numeric, logical, or character array");
@@ -130,7 +130,8 @@
     nd = ndims (x);
     nc = columns (x) * (nd - 1);    # ND-arrays are expanded in columns
     x  = permute (x, [2, 3:nd, 1]);
-    if (! (sum (fmt == "%") > 1 || any (strcmp (fmt, {"%s", "%c"}))))
+    if (! (sum (strrep (fmt, "%%", "") == "%") > 1
+           || any (strcmp (fmt, {"%s", "%c"}))))
       fmt = [deblank(repmat (fmt, 1, nc)), "\n"];
     endif
     strtmp = sprintf (fmt, x);
@@ -211,8 +212,8 @@
 %!assert (num2str ([inf -inf]), "Inf -Inf")
 %!assert (num2str ([inf NaN -inf]), "Inf  NaN -Inf")
 %!assert (num2str ([complex(Inf,0), complex(0,-Inf)]), "Inf+0i   0-Infi")
-%!assert (num2str (complex(Inf,1)), "Inf+1i")
-%!assert (num2str (complex(1,Inf)), "1+Infi")
+%!assert (num2str (complex (Inf,1)), "Inf+1i")
+%!assert (num2str (complex (1,Inf)), "1+Infi")
 %!assert (num2str (nan), "NaN")
 %!assert (num2str (complex (NaN, 1)), "NaN+1i")
 %!assert (num2str (complex (1, NaN)), "1+NaNi")
@@ -249,7 +250,7 @@
 %!assert <*36133> (num2str (1e15), "1000000000000000")
 %!assert <*36133> (num2str (1e16), "1e+16")
 ## Even exact integers in IEEE notation should use exponential notation
-%!assert <*36133> (num2str(2^512), "1.34078079299426e+154")
+%!assert <*36133> (num2str (2^512), "1.34078079299426e+154")
 ## Mixed integer/floating point arrays
 %!assert <*36133> (num2str ([2.1, 1e23, pi]),
 %!                 "2.1  9.999999999999999e+22      3.141592653589793")
@@ -265,8 +266,7 @@
 %!assert <*45174> (num2str ([65 66 67], "%s"), "ABC")
 
 ## Test input validation
-%!error num2str ()
-%!error num2str (1, 2, 3)
+%!error <Invalid call> num2str ()
 %!error <X must be a numeric> num2str ({1})
 %!error <PRECISION must be a scalar integer .= 0> num2str (1, {1})
 %!error <PRECISION must be a scalar integer .= 0> num2str (1, ones (2))
--- a/scripts/general/pol2cart.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/pol2cart.m	Sun May 16 09:44:35 2021 +0200
@@ -28,69 +28,104 @@
 ## @deftypefnx {} {[@var{x}, @var{y}, @var{z}] =} pol2cart (@var{theta}, @var{r}, @var{z})
 ## @deftypefnx {} {[@var{x}, @var{y}] =} pol2cart (@var{P})
 ## @deftypefnx {} {[@var{x}, @var{y}, @var{z}] =} pol2cart (@var{P})
-## @deftypefnx {} {@var{C} =} pol2cart (@dots{})
 ## Transform polar or cylindrical coordinates to Cartesian coordinates.
 ##
 ## The inputs @var{theta}, @var{r}, (and @var{z}) must be the same shape, or
 ## scalar.  If called with a single matrix argument then each row of @var{P}
-## represents the polar/(cylindrical) coordinate (@var{theta}, @var{r}
-## (, @var{z})).
+## represents the polar coordinate pair (@var{theta}, @var{r}) or the
+## cylindrical triplet (@var{theta}, @var{r}, @var{z}).
+##
+## The outputs @var{x}, @var{y} (, and @var{z}) match the shape of the inputs.
+## For a matrix input @var{P} the outputs will be column vectors with rows
+## corresponding to the rows of the input matrix.
 ##
-## @var{theta} describes the angle relative to the positive x-axis.
+## @var{theta} describes the angle relative to the positive x-axis measured in
+## the xy-plane.
+##
+## @var{r} is the distance to the z-axis @w{(0, 0, z)}.
+##
+## @var{z}, if present, is unchanged by the transformation.
+##
+## The coordinate transformation is computed using:
 ##
-## @var{r} is the distance to the z-axis (0, 0, z).
+## @tex
+## $$ x = r \cos \theta $$
+## $$ y = r \sin \theta $$
+## $$ z = z $$
+## @end tex
+## @ifnottex
 ##
-## If only a single return argument is requested then return a matrix @var{C}
-## where each row represents one Cartesian coordinate
-## (@var{x}, @var{y} (, @var{z})).
+## @example
+## @group
+## @var{x} = @var{r} * cos (@var{theta})
+## @var{y} = @var{r} * sin (@var{theta})
+## @var{z} = @var{z}
+## @end group
+## @end example
+##
+## @end ifnottex
+## @c FIXME: Remove this note in Octave 9.1 (two releases after 7.1).
+## Note: For @sc{matlab} compatibility, this function no longer returns a full
+## coordinate matrix when called with a single return argument.
 ## @seealso{cart2pol, sph2cart, cart2sph}
 ## @end deftypefn
 
 function [x, y, z] = pol2cart (theta, r, z = [])
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
   if (nargin == 1)
-    if (! (isnumeric (theta) && ismatrix (theta)
-           && (columns (theta) == 2 || columns (theta) == 3)))
-      error ("pol2cart: matrix input must have 2 or 3 columns [THETA, R (, Z)]");
+    if (! (isnumeric (theta) && ismatrix (theta)))
+      error ("cart2pol: matrix input P must be 2-D numeric array");
     endif
-    if (columns (theta) == 3)
-      z = theta(:,3);
+    if (isvector (theta))
+      n = numel (theta);
+      if (n != 2 && n != 3)
+        error ("cart2pol: matrix input must be a 2- or 3-element vector or a 2- or 3-column array");
+      endif
+      if (n == 3)
+        z = theta(3);
+      endif
+      r = theta(2);
+      theta = theta(1);
+
+    else
+      ncols = columns (theta);
+      if (ncols != 2 && ncols != 3)
+        error ("cart2pol: matrix input must be a 2- or 3-element vector or a 2- or 3-column array");
+      endif
+
+      if (ncols == 3)
+        z = theta(:,3);
+      endif
+      r = theta(:,2);
+      theta = theta(:,1);
     endif
-    r = theta(:,2);
-    theta = theta(:,1);
+
   elseif (nargin == 2)
-    if (! isnumeric (theta) || ! isnumeric (r))
-      error ("pol2cart: THETA, R must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (theta) && isnumeric (r)))
+      error ("pol2cart: THETA, R must be numeric arrays or scalars");
     endif
     [err, theta, r] = common_size (theta, r);
     if (err)
-      error ("pol2cart: THETA, R must be numeric arrays of the same size, or scalar");
+      error ("pol2cart: THETA, R must be the same size or scalars");
     endif
+
   elseif (nargin == 3)
-    if (! isnumeric (theta) || ! isnumeric (r) || ! isnumeric (z))
-      error ("pol2cart: THETA, R, Z must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (theta) && isnumeric (r) && isnumeric (z)))
+      error ("pol2cart: THETA, R, Z must be numeric arrays or scalars");
     endif
     [err, theta, r, z] = common_size (theta, r, z);
     if (err)
-      error ("pol2cart: THETA, R, Z must be numeric arrays of the same size, or scalar");
+      error ("pol2cart: THETA, R, Z must be the same size or scalars");
     endif
   endif
 
   x = r .* cos (theta);
   y = r .* sin (theta);
 
-  if (nargout <= 1)
-    if (isempty (z))
-      x = [x(:), y(:)];
-    else
-      x = [x(:), y(:), z(:)];
-    endif
-  endif
-
 endfunction
 
 
@@ -98,32 +133,42 @@
 %! t = [0, 0.5, 1] * pi;
 %! r = 1;
 %! [x, y] = pol2cart (t, r);
-%! assert (x, [1, 0, -1], sqrt (eps));
-%! assert (y, [0, 1,  0], sqrt (eps));
+%! assert (x, [1, 0, -1], eps);
+%! assert (y, [0, 1,  0], eps);
 
 %!test
 %! t = [0, 1, 1] * pi/4;
 %! r = sqrt (2) * [0, 1, 2];
-%! C = pol2cart (t, r);
-%! assert (C(:,1), [0; 1; 2], sqrt (eps));
-%! assert (C(:,2), [0; 1; 2], sqrt (eps));
+%! [x, y] = pol2cart (t, r);
+%! assert (x, [0, 1, 2], 2*eps);
+%! assert (y, [0, 1, 2], 2*eps);
 
 %!test
 %! t = [0, 1, 1] * pi/4;
 %! r = sqrt (2) * [0, 1, 2];
 %! z = [0, 1, 2];
 %! [x, y, z2] = pol2cart (t, r, z);
-%! assert (x, [0, 1, 2], sqrt (eps));
-%! assert (y, [0, 1, 2], sqrt (eps));
+%! assert (x, [0, 1, 2], 2*eps);
+%! assert (y, [0, 1, 2], 2*eps);
 %! assert (z2, z);
 
 %!test
+%! t = [0; 1; 1] * pi/4;
+%! r = sqrt (2) * [0; 1; 2];
+%! z = [0; 1; 2];
+%! [x, y, z2] = pol2cart (t, r, z);
+%! assert (x, [0; 1; 2], 2*eps);
+%! assert (y, [0; 1; 2], 2*eps);
+%! assert (z2, z);
+
+
+%!test
 %! t = 0;
 %! r = [0, 1, 2];
 %! z = [0, 1, 2];
 %! [x, y, z2] = pol2cart (t, r, z);
-%! assert (x, [0, 1, 2], sqrt (eps));
-%! assert (y, [0, 0, 0], sqrt (eps));
+%! assert (x, [0, 1, 2], eps);
+%! assert (y, [0, 0, 0], eps);
 %! assert (z2, z);
 
 %!test
@@ -146,13 +191,23 @@
 
 %!test
 %! P = [0, 0; pi/4, sqrt(2); pi/4, 2*sqrt(2)];
-%! C = [0, 0; 1, 1; 2, 2];
-%! assert (pol2cart (P), C, sqrt (eps));
+%! [x, y] = pol2cart(P);
+%! assert (x, [0; 1; 2], 2*eps);
+%! assert (y, [0; 1; 2], 2*eps);
 
 %!test
 %! P = [0, 0, 0; pi/4, sqrt(2), 1; pi/4, 2*sqrt(2), 2];
-%! C = [0, 0, 0; 1, 1, 1; 2, 2, 2];
-%! assert (pol2cart (P), C, sqrt (eps));
+%! [x, y, z] = pol2cart(P);
+%! assert (x, [0; 1; 2], 2*eps);
+%! assert (y, [0; 1; 2], 2*eps);
+%! assert (z, P(:,3), 2*eps);
+
+%!test
+%! P = [0, 0, 0; pi/4, sqrt(2), 1; pi/4, 2*sqrt(2), 2; 0, 0, 0];
+%! [x, y, z] = pol2cart(P);
+%! assert (x, [0; 1; 2; 0], 2*eps);
+%! assert (y, [0; 1; 2; 0], 2*eps);
+%! assert (z, P(:,3), 2*eps);
 
 %!test
 %! r = ones (1, 1, 1, 2);
@@ -169,10 +224,10 @@
 %!test
 %! [t, r, Z] = meshgrid ([0, pi/2], [1, 2], [0, 1]);
 %! [x, y, z] = pol2cart (t, r, Z);
-%! X = zeros(2, 2, 2);
+%! X = zeros (2, 2, 2);
 %! X(:, 1, 1) = [1; 2];
 %! X(:, 1, 2) = [1; 2];
-%! Y = zeros(2, 2, 2);
+%! Y = zeros (2, 2, 2);
 %! Y(:, 2, 1) = [1; 2];
 %! Y(:, 2, 2) = [1; 2];
 %! assert (x, X, eps);
@@ -180,17 +235,18 @@
 %! assert (z, Z);
 
 ## Test input validation
-%!error pol2cart ()
-%!error pol2cart (1,2,3,4)
-%!error <matrix input must have 2 or 3 columns> pol2cart ({1,2,3})
-%!error <matrix input must have 2 or 3 columns> pol2cart (ones (3,3,2))
-%!error <matrix input must have 2 or 3 columns> pol2cart ([1])
-%!error <matrix input must have 2 or 3 columns> pol2cart ([1,2,3,4])
-%!error <numeric arrays of the same size> pol2cart ({1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> pol2cart ([1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> pol2cart (ones (3,3,3), ones (3,2,3))
-%!error <numeric arrays of the same size> pol2cart ({1,2,3}, [1,2,3], [1,2,3])
-%!error <numeric arrays of the same size> pol2cart ([1,2,3], {1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> pol2cart ([1,2,3], [1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> pol2cart (ones (3,3,3), 1, ones (3,2,3))
-%!error <numeric arrays of the same size> pol2cart (ones (3,3,3), ones (3,2,3), 1)
+%!error <Invalid call> pol2cart ()
+%!error <matrix input P must be 2-D numeric array> pol2cart ({1,2,3})
+%!error <matrix input P must be 2-D numeric array> pol2cart (ones (3,3,2))
+%!error <matrix input must be a 2- or 3-element> pol2cart ([1])
+%!error <matrix input must be a 2- or 3-element> pol2cart ([1,2,3,4])
+%!error <must be numeric arrays or scalars> pol2cart ({1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> pol2cart ([1,2,3], {1,2,3})
+%!error <must be the same size or scalars> pol2cart (ones (3,3,3), ones (3,2,3))
+%!error <must be the same size or scalars> pol2cart ([1; 1], [2, 2])
+%!error <must be the same size or scalars> pol2cart ([1; 1], [2, 2], [3, 3])
+%!error <must be numeric arrays or scalars> pol2cart ({1,2,3}, [1,2,3], [1,2,3])
+%!error <must be numeric arrays or scalars> pol2cart ([1,2,3], {1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> pol2cart ([1,2,3], [1,2,3], {1,2,3})
+%!error <must be the same size or scalars> pol2cart (ones (3,3,3), 1, ones (3,2,3))
+%!error <must be the same size or scalars> pol2cart (ones (3,3,3), ones (3,2,3), 1)
--- a/scripts/general/polyarea.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/polyarea.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
 
 function a = polyarea (x, y, dim)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   elseif (! size_equal (x, y))
     error ("polyarea: X and Y must have the same shape");
--- a/scripts/general/postpad.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/postpad.m	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
 
 function y = postpad (x, l, c, dim)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -113,6 +113,5 @@
 %!assert <*44162> (postpad ("Octave", 16, "x"), "Octavexxxxxxxxxx")
 %!assert (postpad ("Octave", 4), "Octa")
 
-%!error postpad ()
-%!error postpad (1)
-%!error postpad (1,2,3,4,5)
+%!error <Invalid call> postpad ()
+%!error <Invalid call> postpad (1)
--- a/scripts/general/prepad.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/prepad.m	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
 
 function y = prepad (x, l, c, dim)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -118,9 +118,8 @@
 
 ## FIXME: We need tests for multidimensional arrays.
 
-%!error prepad ()
-%!error prepad (1)
-%!error prepad (1,2,3,4,5)
+%!error <Invalid call> prepad ()
+%!error <Invalid call> prepad (1)
 %!error <C must be empty or a scalar> prepad ([1,2], 2, ones (2))
 %!error <DIM must be an integer> prepad ([1,2], 2, 2, ones (3))
 %!error <DIM must be an integer> prepad ([1,2], 2, 2, 1.1)
--- a/scripts/general/private/__splinen__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/private/__splinen__.m	Sun May 16 09:44:35 2021 +0200
@@ -23,32 +23,30 @@
 ##
 ########################################################################
 
-## Undocumented internal function.
-
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{yi} =} __splinen__ (@var{x}, @var{y}, @var{xi}, @var{extrapval}, @var{f})
 ## Undocumented internal function.
 ## @end deftypefn
 
-## FIXME: Allow arbitrary grids..
+## FIXME: Allow arbitrary grids.
 
 function yi = __splinen__ (x, y, xi, extrapval, f)
 
-  ## ND isvector function.
-  isvec = @(x) numel (x) == length (x);
-  if (! iscell (x) || length (x) < ndims (y) || any (! cellfun (isvec, x))
-      || ! iscell (xi) || length (xi) < ndims (y)
-      || any (! cellfun (isvec, xi)))
+  ## ND function to check whether any object in cell array is *not* a vector.
+  isnotvec = @(x) cellfun ("numel", x) != cellfun ("length", x);
+  if (! iscell (x) || length (x) < ndims (y) || any (isnotvec (x))
+      || ! iscell (xi) || length (xi) < ndims (y) || any (isnotvec (xi)))
     error ("__splinen__: %s: non-gridded data or dimensions inconsistent", f);
   endif
+
   yi = y;
   for i = length (x):-1:1
     yi = permute (spline (x{i}, yi, xi{i}(:)), [length(x),1:length(x)-1]);
   endfor
 
-  [xi{:}] = ndgrid (cellfun (@(x) x(:), xi, "uniformoutput", false){:});
   if (! isempty (extrapval))
-    idx = zeros (size (xi{1}));
+    [xi{:}] = ndgrid (cellfun (@(x) x(:), xi, "uniformoutput", false){:});
+    idx = false (size (xi{1}));
     for i = 1 : length (x)
       idx |= xi{i} < min (x{i}(:)) | xi{i} > max (x{i}(:));
     endfor
--- a/scripts/general/quad2d.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/quad2d.m	Sun May 16 09:44:35 2021 +0200
@@ -233,13 +233,13 @@
     if (! (isreal (ya) && isscalar (ya)))
       error ("quad2d: YA must be a real scalar or a function");
     endif
-    ya = @(x) ya * ones(rows (x), columns (x));
+    ya = @(x) ya * ones (rows (x), columns (x));
   endif
   if (! is_function_handle (yb))
     if (! (isreal (yb) && isscalar (yb)))
       error ("quad2d: YB must be a real scalar or a function");
     endif
-    yb = @(x) yb * ones(rows (x), columns (x));
+    yb = @(x) yb * ones (rows (x), columns (x));
   endif
 
   iter = 0;
@@ -262,7 +262,7 @@
 
     xtrans = @(tx) ((xa - xb) .* cos (tx) + (xa + xb)) ./ 2;
     ytrans = @(ty) (1 - cos (ty)) ./ 2;
-    ztrans = @(tx, ty) (xb - xa) .* sin(tx) .* sin(ty) ./ 4;
+    ztrans = @(tx, ty) (xb - xa) .* sin (tx) .* sin (ty) ./ 4;
     area = pi ^ 2;
 
     ## Initialize tile list
@@ -408,6 +408,7 @@
   z = yhalfwidth .* f (x, y) .* ztrans(tx, ty) .* xhalfwidth;
   q = weights15 * (weights15 * z)';
   qerr = abs (weights7 * (weights7 * z)' - q);
+
 endfunction
 
 
@@ -437,12 +438,12 @@
 %!assert (quad2d (@plus, 1, 2, 3, 4), 5, 1e-10)
 
 ## Test input validation
-%!error quad2d ()
-%!error quad2d (@plus)
-%!error quad2d (@plus, 1)
-%!error quad2d (@plus, 1, 2)
-%!error quad2d (@plus, 1, 2, 3)
-%!error quad2d (@plus, 1, 2, 3, 4, "foo")
+%!error <Invalid call> quad2d ()
+%!error <Invalid call> quad2d (@plus)
+%!error <Invalid call> quad2d (@plus, 1)
+%!error <Invalid call> quad2d (@plus, 1, 2)
+%!error <Invalid call> quad2d (@plus, 1, 2, 3)
+%!error <Invalid call> quad2d (@plus, 1, 2, 3, 4, "foo")
 %!error quad2d (0, 1, 2, 3, 4)          # f must be function handle
 %!error quad2d (@plus, 1i, 2, 3, 4)     # real limits
 %!error quad2d (@plus, 1, 2i, 3, 4)     # real limits
--- a/scripts/general/quadgk.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/quadgk.m	Sun May 16 09:44:35 2021 +0200
@@ -463,7 +463,7 @@
 function t = __quadgk_finite_waypoint__ (x, a, b)
   c = (-4 .* x + 2.* (b + a)) ./ (b - a);
   k = ((sqrt (c .^ 2 - 4) + c) ./ 2) .^ (1/3);
-  t = real ((sqrt(3) .* 1i * (1 - k .^ 2) - (1 + k .^ 2)) ./ 2 ./ k);
+  t = real ((sqrt (3) .* 1i * (1 - k .^ 2) - (1 + k .^ 2)) ./ 2 ./ k);
 endfunction
 
 
@@ -480,10 +480,10 @@
 %!assert (quadgk (@(x) 1./sqrt (x),0,1), 2, 1e-10)
 %!assert (quadgk (@(x) abs (1 - x.^2),0,2, "Waypoints", 1), 2, 1e-10)
 %!assert (quadgk (@(x) 1./(sqrt (x) .* (x+1)),0,Inf), pi, 1e-10)
-%!assert <*57614> (quadgk (@(z) exp(z)./z, 1, 1,
+%!assert <*57614> (quadgk (@(z) exp (z)./z, 1, 1,
 %!                        "Waypoints", [1+i, -1+i, -1-i, 1-i]),
 %!                 complex (0, 2*pi), 1e-10)
-%!assert <*57614> (quadgk (@(z) exp(z)./z, 1, 1,
+%!assert <*57614> (quadgk (@(z) exp (z)./z, 1, 1,
 %!                        "Waypoints", [1-i, -1-i, -1+i, 1+i]),
 %!                 complex (0, -2*pi), 1e-10)
 %!assert (quadgk (@(z) log (z),1+1i,1+1i, "WayPoints", [1-1i, -1,-1i, -1+1i]),
--- a/scripts/general/quadl.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/quadl.m	Sun May 16 09:44:35 2021 +0200
@@ -184,14 +184,14 @@
 
 ## extra parameters
 %!assert (quadl (@(x,a,b) sin (a + b*x), 0, 1, [], [], 2, 3),
-%!        cos(2)/3 - cos(5)/3, 1e-6)
+%!        cos (2)/3 - cos (5)/3, 1e-6)
 
 ## test different tolerances.
 %!test
 %! [q, nfun1] = quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.5, []);
-%! assert (q, (60 + sin(4) - sin(64))/12, 0.5);
+%! assert (q, (60 + sin (4) - sin (64))/12, 0.5);
 %! [q, nfun2] = quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.1, []);
-%! assert (q, (60 + sin(4) - sin(64))/12, 0.1);
+%! assert (q, (60 + sin (4) - sin (64))/12, 0.1);
 %! assert (nfun2 > nfun1);
 
 %!test  # test single input/output
@@ -200,8 +200,8 @@
 %! assert (class (quadl (@sin, 0, single (1))), "single");
 
 ## Test input validation
-%!error quadl ()
-%!error quadl (@sin)
-%!error quadl (@sin,1)
+%!error <Invalid call> quadl ()
+%!error <Invalid call> quadl (@sin)
+%!error <Invalid call> quadl (@sin,1)
 %!error <TOL must be a scalar> quadl (@sin,0,1, ones (2,2))
 %!error <TOL must be .* .=0> quadl (@sin,0,1, -1)
--- a/scripts/general/quadv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/quadv.m	Sun May 16 09:44:35 2021 +0200
@@ -210,7 +210,7 @@
 %!assert (quadv (@sin, 0, pi), 2, 1e-6)
 
 ## Test weak singularities at the edge
-%!assert (quadv (@(x) 1 ./ sqrt (x), 0, 1), 2, 15*1e-6);
+%!assert (quadv (@(x) 1 ./ sqrt (x), 0, 1), 2, 15*1e-6)
 
 ## Test vector-valued functions
 %!assert (quadv (@(x) [(sin (x)), (sin (2 * x))], 0, pi), [2, 0], 1e-6)
@@ -223,8 +223,8 @@
 %!assert <*57603> (quadv (@(t) sin (t) .^ 2, 0, 8*pi), 4*pi, 1e-6)
 
 ## Test input validation
-%!error quadv ()
-%!error quadv (@sin)
-%!error quadv (@sin,1)
+%!error <Invalid call> quadv ()
+%!error <Invalid call> quadv (@sin)
+%!error <Invalid call> quadv (@sin,1)
 %!error <TOL must be a scalar> quadv (@sin,0,1, ones (2,2))
 %!error <TOL must be .* .=0> quadv (@sin,0,1, -1)
--- a/scripts/general/rad2deg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/rad2deg.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
 
 function deg = rad2deg (rad)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -67,7 +67,6 @@
 %!assert (rad2deg (pi*[0, 1/2, 1, 3/2, 2]), [0, 90, 180, 270, 360])
 
 ## Test input validation
-%!error rad2deg ()
-%!error rad2deg (1, 2)
+%!error <Invalid call> rad2deg ()
 %!error <RAD must be a floating point class> rad2deg (uint8 (1))
 %!error <RAD must be a floating point class> rad2deg ("A")
--- a/scripts/general/randi.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/randi.m	Sun May 16 09:44:35 2021 +0200
@@ -189,13 +189,9 @@
 
 ## Test that no warning thrown if IMAX is exactly on the limits of the range
 %!function test_no_warning (func, varargin)
-%!  state = warning ("query");
-%!  unwind_protect
-%!    warning ("error", "all");
-%!    func (varargin{:});
-%!  unwind_protect_cleanup
-%!    warning (state);
-%!  end_unwind_protect
+%!  lastwarn ("");
+%!  func (varargin{:});
+%!  assert (lastwarn (), "");
 %!endfunction
 %!test test_no_warning (@randi, max_int8, "int8");
 %!test test_no_warning (@randi, max_uint8, "uint8");
@@ -224,7 +220,7 @@
 
 
 ## Test input validation
-%!error randi ()
+%!error <Invalid call> randi ()
 %!error <must be integer bounds> randi ("test")
 %!error <must be integer bounds> randi (struct ("a", 1))
 %!error <must be integer bounds> randi (1.5)
--- a/scripts/general/rat.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/rat.m	Sun May 16 09:44:35 2021 +0200
@@ -65,7 +65,7 @@
 
 function [n, d] = rat (x, tol)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -223,8 +223,7 @@
 %!assert <*43374> (eval (rat (0.75)), [0.75])
 
 ## Test input validation
-%!error rat ()
-%!error rat (1, 2, 3)
+%!error <Invalid call> rat ()
 %!error <X must be a single or double array> rat (int8 (3))
 %!error <X must be a real, not complex, array> rat (1+1i)
 %!error <TOL must be a numeric scalar> rat (1, "a")
--- a/scripts/general/repelem.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/repelem.m	Sun May 16 09:44:35 2021 +0200
@@ -176,7 +176,7 @@
 
 function retval = repelem (x, varargin)
 
-  if (nargin <= 1)
+  if (nargin < 2)
     print_usage ();
 
   elseif (nargin == 2)
@@ -348,7 +348,7 @@
 
 ## nargin == 2 tests
 %!assert (repelem ([-1 0 1], 2), [-1 -1 0 0 1 1])
-%!assert (repelem ([-1 0 1]', 2), [-1; -1; 0; 0; 1; 1;])
+%!assert (repelem ([-1 0 1]', 2), [-1; -1; 0; 0; 1; 1])
 %!assert (repelem ([-1 0 1], [1 2 1]), [-1 0 0 1])
 %!assert (repelem ([-1 0 1]', [1 2 1]), [-1; 0; 0; 1])
 %!assert (repelem ([1 2 3 4 5]', [2 1 0 1 2]), [1 1 2 4 5 5]')
@@ -368,32 +368,32 @@
 %!        [1 1 1 0 0;1 1 1 0 0;0 0 0 -1 -1;0 0 0 -1 -1;0 0 0 -1 -1])
 %!assert (repelem (cat(3,[1 1 1 0;0 1 0 0],[1 1 1 1;0 0 0 1],[1 0 0 1;1 1 0 1]),
 %!                2, 3),
-%!        cat(3,[1 1 1 1 1 1 1 1 1 0 0 0
-%!               1 1 1 1 1 1 1 1 1 0 0 0
-%!               0 0 0 1 1 1 0 0 0 0 0 0
-%!               0 0 0 1 1 1 0 0 0 0 0 0],
-%!              [1 1 1 1 1 1 1 1 1 1 1 1
-%!               1 1 1 1 1 1 1 1 1 1 1 1
-%!               0 0 0 0 0 0 0 0 0 1 1 1
-%!               0 0 0 0 0 0 0 0 0 1 1 1],
-%!              [1 1 1 0 0 0 0 0 0 1 1 1
-%!               1 1 1 0 0 0 0 0 0 1 1 1
-%!               1 1 1 1 1 1 0 0 0 1 1 1
-%!               1 1 1 1 1 1 0 0 0 1 1 1]))
+%!        cat (3,[1 1 1 1 1 1 1 1 1 0 0 0
+%!                1 1 1 1 1 1 1 1 1 0 0 0
+%!                0 0 0 1 1 1 0 0 0 0 0 0
+%!                0 0 0 1 1 1 0 0 0 0 0 0],
+%!               [1 1 1 1 1 1 1 1 1 1 1 1
+%!                1 1 1 1 1 1 1 1 1 1 1 1
+%!                0 0 0 0 0 0 0 0 0 1 1 1
+%!                0 0 0 0 0 0 0 0 0 1 1 1],
+%!               [1 1 1 0 0 0 0 0 0 1 1 1
+%!                1 1 1 0 0 0 0 0 0 1 1 1
+%!                1 1 1 1 1 1 0 0 0 1 1 1
+%!                1 1 1 1 1 1 0 0 0 1 1 1]))
 %!assert (repelem (cat(3,[1 1 1 0;0 1 0 0],[1 1 1 1;0 0 0 1],[1 0 0 1;1 1 0 1]),
 %!                2, [3 3 3 3]), ...
-%!        cat(3,[1 1 1 1 1 1 1 1 1 0 0 0
-%!               1 1 1 1 1 1 1 1 1 0 0 0
-%!               0 0 0 1 1 1 0 0 0 0 0 0
-%!               0 0 0 1 1 1 0 0 0 0 0 0], ...
-%!              [1 1 1 1 1 1 1 1 1 1 1 1
-%!               1 1 1 1 1 1 1 1 1 1 1 1
-%!               0 0 0 0 0 0 0 0 0 1 1 1
-%!               0 0 0 0 0 0 0 0 0 1 1 1], ...
-%!              [1 1 1 0 0 0 0 0 0 1 1 1
-%!               1 1 1 0 0 0 0 0 0 1 1 1
-%!               1 1 1 1 1 1 0 0 0 1 1 1
-%!               1 1 1 1 1 1 0 0 0 1 1 1]));
+%!        cat (3,[1 1 1 1 1 1 1 1 1 0 0 0
+%!                1 1 1 1 1 1 1 1 1 0 0 0
+%!                0 0 0 1 1 1 0 0 0 0 0 0
+%!                0 0 0 1 1 1 0 0 0 0 0 0], ...
+%!               [1 1 1 1 1 1 1 1 1 1 1 1
+%!                1 1 1 1 1 1 1 1 1 1 1 1
+%!                0 0 0 0 0 0 0 0 0 1 1 1
+%!                0 0 0 0 0 0 0 0 0 1 1 1], ...
+%!               [1 1 1 0 0 0 0 0 0 1 1 1
+%!                1 1 1 0 0 0 0 0 0 1 1 1
+%!                1 1 1 1 1 1 0 0 0 1 1 1
+%!                1 1 1 1 1 1 0 0 0 1 1 1]));
 %!assert (repelem ([1 2 3 4 5], 2,[2 1 2 0 2]), [1 1 2 3 3 5 5;1 1 2 3 3 5 5])
 %
 ## nargin > 3 tests
@@ -409,16 +409,16 @@
 %!assert (repelem (repmat([-1 0;0 1],1,1,2,3),2,2,2,2,2), ...
 %!        repmat([-1 -1 0 0;-1 -1 0 0;0 0 1 1; 0 0 1 1],1,1,4,6,2))
 %!assert (repelem ([1,0,-1;-1,0,1],[2 3],[2 3 4],2), ...
-%!        cat(3,[ 1  1 0 0 0 -1 -1 -1 -1
-%!                1  1 0 0 0 -1 -1 -1 -1
-%!               -1 -1 0 0 0  1  1  1  1
-%!               -1 -1 0 0 0  1  1  1  1
-%!               -1 -1 0 0 0  1  1  1  1], ...
-%!              [ 1  1 0 0 0 -1 -1 -1 -1
-%!                1  1 0 0 0 -1 -1 -1 -1
-%!               -1 -1 0 0 0  1  1  1  1
-%!               -1 -1 0 0 0  1  1  1  1
-%!               -1 -1 0 0 0  1  1  1  1]));
+%!        cat (3,[ 1  1 0 0 0 -1 -1 -1 -1
+%!                 1  1 0 0 0 -1 -1 -1 -1
+%!                -1 -1 0 0 0  1  1  1  1
+%!                -1 -1 0 0 0  1  1  1  1
+%!                -1 -1 0 0 0  1  1  1  1], ...
+%!               [ 1  1 0 0 0 -1 -1 -1 -1
+%!                 1  1 0 0 0 -1 -1 -1 -1
+%!                -1 -1 0 0 0  1  1  1  1
+%!                -1 -1 0 0 0  1  1  1  1
+%!                -1 -1 0 0 0  1  1  1  1]));
 %!assert (repelem ([1 2 3;4 5 6],[0 2],2,2), repmat([4 4 5 5 6 6],2,1,2))
 
 ## test with structures
@@ -447,34 +447,33 @@
 %!         sparse ([8,8,1,1,6,6; 3,3,5,5,7,7; 4,4,9,9,2,2]));
 
 ## nargin <= 1 error tests
-%!error (repelem ());
-%!error (repelem ([]));
-%!error (repelem (5));
-%!error (repelem (5,[]));
-%!error (repelem ([1 2 3 3 2 1]));
-%!error (repelem ([1 2 3; 3 2 1]));
+%!error <Invalid call> repelem ()
+%!error <Invalid call> repelem (1)
+%!error repelem (5,[])
+%!error repelem ([1 2 3 3 2 1])
+%!error repelem ([1 2 3; 3 2 1])
 
 ## nargin == 2 error tests
-%!error (repelem ([1 2 3; 3 2 1],[]));
-%!error (repelem ([1 2 3; 3 2 1],2));
-%!error (repelem ([1 2 3; 3 2 1],2));
-%!error (repelem ([1 2 3; 3 2 1],[1 2 3]));
-%!error (repelem ([1 2 3; 3 2 1],[1 2 3]'));
-%!error (repelem ([1 2 3; 3 2 1],[1 2 2 1]));
-%!error (repelem ([1 2 3; 3 2 1],[1 2 3;4 5 6]));
-%!error (repelem ([1 2 3 4 5],[1 2 3 4 5;1 2 3 4 5]));
+%!error repelem ([1 2 3; 3 2 1],[])
+%!error repelem ([1 2 3; 3 2 1],2)
+%!error repelem ([1 2 3; 3 2 1],2)
+%!error repelem ([1 2 3; 3 2 1],[1 2 3])
+%!error repelem ([1 2 3; 3 2 1],[1 2 3]')
+%!error repelem ([1 2 3; 3 2 1],[1 2 2 1])
+%!error repelem ([1 2 3; 3 2 1],[1 2 3;4 5 6])
+%!error repelem ([1 2 3 4 5],[1 2 3 4 5;1 2 3 4 5])
 
 ## nargin == 3 error tests
-%!error (repelem ([1 2 3; 3 2 1], 1, [1 2;1 2]));
-%!error (repelem ([1 2 3; 3 2 1], 1, [1 2]));
-%!error (repelem ([1 2 3; 3 2 1], 2, []));
-%!error (repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3]));
-%!error (repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3 4]));
-%!error (repelem ([1 2 3; 3 2 1], [1 2], [1 2 3 4]));
+%!error repelem ([1 2 3; 3 2 1], 1, [1 2;1 2])
+%!error repelem ([1 2 3; 3 2 1], 1, [1 2])
+%!error repelem ([1 2 3; 3 2 1], 2, [])
+%!error repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3])
+%!error repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3 4])
+%!error repelem ([1 2 3; 3 2 1], [1 2], [1 2 3 4])
 
 ## nargin > 3 error tests
-%!error (repelem ([1 2 3; 3 2 1], 1, [1 2;1 2],1,2,3));
-%!error (repelem ([1 2 3; 3 2 1], [],1,2,3));
-%!error (repelem ([1 2 3; 3 2 1], [1 2], [1 2 3],1,2,[1 2;1 2]));
-%!error (repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3],1,2));
-%!error (repelem ([1 2 3; 3 2 1], [1 2], [1 2 3 4],1,2));
+%!error repelem ([1 2 3; 3 2 1], 1, [1 2;1 2],1,2,3)
+%!error repelem ([1 2 3; 3 2 1], [],1,2,3)
+%!error repelem ([1 2 3; 3 2 1], [1 2], [1 2 3],1,2,[1 2;1 2])
+%!error repelem ([1 2 3; 3 2 1], [1 2 3], [1 2 3],1,2)
+%!error repelem ([1 2 3; 3 2 1], [1 2], [1 2 3 4],1,2)
--- a/scripts/general/repmat.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/repmat.m	Sun May 16 09:44:35 2021 +0200
@@ -221,4 +221,4 @@
 %!assert (size (repmat ({1}, [0, 1])), [0, 1])
 %!assert (size (repmat ({1}, [0, 5])), [0, 5])
 
-%!error (size (repmat (".", -1, -1)))
+%!error size (repmat (".", -1, -1))
--- a/scripts/general/rescale.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/rescale.m	Sun May 16 09:44:35 2021 +0200
@@ -162,11 +162,11 @@
 %!assert (class (rescale (logical ([0, 1]))), "double")
 
 ## Test input validation
-%!error rescale ()
-%!error rescale (1, 2)
-%!error rescale (1, 2, 3, 4)
-%!error rescale (1, 2, 3, 4, 5, 6)
-%!error rescale (1, 2, 3, 4, 5, 6, 7, 8)
+%!error <Invalid call> rescale ()
+%!error <Invalid call> rescale (1, 2)
+%!error <Invalid call> rescale (1, 2, 3, 4)
+%!error <Invalid call> rescale (1, 2, 3, 4, 5, 6)
+%!error <Invalid call> rescale (1, 2, 3, 4, 5, 6, 7, 8)
 %!error <A must be a numeric or logical matrix> rescale ("abc")
 %!error <A must be a numeric or logical matrix> rescale ({ [1] })
 %!error <U must be numeric> rescale (1, 0, "A")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/rng.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,306 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {} rng (@var{seed})
+## @deftypefnx {} {} rng (@var{seed}, "@var{generator}")
+## @deftypefnx {} {} rng ("shuffle")
+## @deftypefnx {} {} rng ("shuffle", "@var{generator}")
+## @deftypefnx {} {} rng ("default")
+## @deftypefnx {} {@var{s} =} rng ()
+## @deftypefnx {} {} rng (@var{s})
+## @deftypefnx {} {@var{s} =} rng (@dots{})
+## Set or query the seed of the random number generator used by @code{rand} and
+## @code{randn}.
+##
+## The input @var{seed} is a scalar numeric value used to initialize the state
+## vector of the random number generator.
+##
+## The optional string @var{generator} specifies the type of random number
+## generator to be used.  Its value can be @qcode{"twister"},
+## @qcode{"v5uniform"}, or @qcode{"v5normal"}.  The @qcode{"twister"} keyword
+## is described below.  @qcode{"v5uniform"} and @qcode{"v5normal"} refer to
+## older versions of Octave that used to use a different random number
+## generator.
+##
+## The state or seed of the random number generator can be reset to a new
+## random value using the @qcode{"shuffle"} keyword.
+##
+## The random number generator can be reset to default values using the
+## @qcode{"default"} keyword.  The default values are to use the Mersenne
+## Twister generator with a seed of 0.
+##
+## The optional return value @var{s} contains the state of the random number
+## generator at the time the function is called (i.e., before it might be
+## modified according to the input arguments).  It is encoded as a structure
+## variable with three fields: @qcode{"Type"}, @qcode{"Seed"}, and
+## @qcode{"State"}.  The random number generator can be restored to the state
+## @var{s} using @code{rng (@var{s})}.  This is useful when the identical
+## sequence of pseudo-random numbers is required for an algorithm.
+##
+## By default, and with the @qcode{"twister"} option, pseudo-random sequences
+## are computed using the Mersenne Twister with a period of @math{2^{19937}-1}
+## (See @nospell{M. Matsumoto and T. Nishimura},
+## @cite{Mersenne Twister: A 623-dimensionally equidistributed uniform
+## pseudorandom number generator},
+## @nospell{ACM} Trans.@: on Modeling and Computer Simulation Vol.@: 8, No.@: 1,
+## pp.@: 3--30, January 1998,
+## @url{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html}).
+## Do @strong{not} use for cryptography without securely hashing several
+## returned values together, otherwise the generator state can be learned after
+## reading 624 consecutive values.
+##
+## @seealso{rand, randn}
+## @end deftypefn
+
+function retval = rng (varargin)
+
+  if (nargin > 2)
+    print_usage ();
+  endif
+
+  ## Store current settings of random number generator
+  ## FIXME: there doesn't seem to be a way to query the type of generator
+  ##        currently used in Octave - assume "twister".
+  ## FIXME: there doesn't seem to be a way to query the seed initialization
+  ##        value - use "Not applicable".
+  ## FIXME: rand and randn use different generators - storing both states.
+  ## For older Matlab generators (v4, v5), the settings are stored like this:
+  ##   struct ("Type","Legacy", "Seed", "Not applicable", "State",{[],[],...})
+
+  ## Type is the generator name.
+  ## Seed is the initial seed value.
+  ## State is a structure describing internal state of the generator.
+  s = struct ("Type", "twister",
+              "Seed", "Not applicable",
+              "State", {{rand("state"), randn("state")}});
+
+  if (nargin == 0)
+    retval = s;
+    return;
+  endif
+
+  arg1 = varargin{1};
+  if (isscalar (arg1) && isnumeric (arg1) && isreal (arg1) && arg1 >= 0)
+    s_rand = s_randn = arg1;
+    generator = check_generator (varargin(2:end));
+
+  elseif (ischar (arg1) && strcmpi (arg1, "shuffle"))
+    ## Seed the random number generator based on the current time
+    s_rand = s_randn = "reset";  # or sum (1000*clock)
+    generator = check_generator (varargin(2:end));
+
+  elseif (ischar (arg1) && strcmpi (arg1, "default") && nargin == 1)
+    generator = "twister";
+    s_rand = s_randn = 0;  # FIXME: In Matlab, seed 0 corresponds to 5489
+
+  elseif (isstruct (arg1) && isscalar (arg1) && nargin == 1)
+    if (numfields (arg1) != 3
+        || ! all (isfield (arg1, {"Type", "Seed", "State"})))
+      error ('rng: input structure requires "Type", "Seed", "State" fields"');
+    endif
+    ## Only the internal state "State" and generator type "Type" are needed
+    generator = arg1.Type;
+    if (iscell (arg1.State))
+      [s_rand, s_randn] = deal (arg1.State{:});
+    else
+      s_rand = s_randn = arg1.State;
+    endif
+
+  else
+    print_usage ();
+  endif
+
+  ## Set the type of random number generator and seed it
+  if (isempty (generator))
+    generator = s.Type;
+  endif
+  switch (generator)
+    case "twister"
+      rand ("state", s_rand);
+      randn ("state", s_randn);
+
+    case "legacy"
+      rand ("seed", s_rand);
+      randn ("seed", s_randn);
+
+    case "v5uniform"
+      rand ("seed", s_rand);
+
+    case "v5normal"
+      randn ("seed", s_randn);
+
+    otherwise
+      error ('rng: invalid GENERATOR: "%s"', generator);
+
+  endswitch
+
+  if (nargout > 0)
+    retval = s;
+  endif
+
+endfunction
+
+
+function gen = check_generator (val)
+
+  if (isempty (val))
+    gen = "";
+    return;
+  elseif (! iscellstr (val))
+    error ("rng: GENERATOR must be a string");
+  endif
+
+  gen = tolower (char (val));
+  if (any (strcmp (gen, {"simdtwister", "combrecursive", "philox", "threefry", "multfibonacci", "v4"})))
+    error ('rng: random number generator "%s" is not available in Octave', gen);
+  elseif (! any (strcmp (gen, {"twister", "v5uniform", "v5normal"})))
+    error ('rng: unknown random number generator "%s"', gen);
+  endif
+
+endfunction
+
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   rng (42);
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   rng (42);
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%!   s1 = rng ();
+%!   s2 = rng (42);
+%!   assert (isequal (s1, s2));
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   s3 = rng (42);
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   rng (42, "twister");
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   rng (42, "twister");
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%!   s1 = rng ();
+%!   s2 = rng (42, "twister");
+%!   assert (isequal (s1, s2));
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   s3 = rng (42, "twister");
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   rng ("shuffle");
+%!   rng ("shuffle", "twister");
+%!   s = rng ("shuffle");
+%!   assert (! isequal (s, rng ("shuffle")));
+%!   s = rng ("shuffle", "twister");
+%!   assert (! isequal (s, rng ("shuffle", "twister")));
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   rng ("default");
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   rng (0, "twister");
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%!   rng (0, "twister");
+%!   s = rng ("default");
+%!   assert (isequal (s, rng ()));
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+%!test
+%! state = rng ();
+%! unwind_protect
+%!   s = rng ();
+%!   ru1 = rand ();
+%!   rn1 = randn ();
+%!   rng (s);
+%!   ru2 = rand ();
+%!   rn2 = randn ();
+%!   assert (ru2, ru1);
+%!   assert (rn2, rn1);
+%!   rng (42);  rand (1,2);  x = rand (1,2);
+%!   rng (42);  rand (1,2);  s = rng ();  y = rand (1,2);
+%!   assert (x, y);
+%!   rng (s);  z = rand (1,2);
+%!   assert (x, z);
+%!   s1 = rng ();
+%!   s2 = rng (s1);
+%!   assert (isequal (s1, s2));
+%! unwind_protect_cleanup
+%!   rng (state);
+%! end_unwind_protect
+
+## Test input validation
+%!error <Invalid call> rng (1, 2, 3)
+%!error <Invalid call> rng (eye (2))
+%!error <Invalid call> rng ({})
+%!error <Invalid call> rng (2i)
+%!error <Invalid call> rng (-2)
+%!error <Invalid call> rng ("foobar")
+%!error <Invalid call> rng ("default", "twister")
+%!error <Invalid call> rng (struct ("Seed", {1, 2}))
+%!error <Invalid call> rng (struct ("Type",[],"State",[],"Seed",[]), "twister")
+%!error <input structure requires "Type"> rng (struct ())
+%!error <input structure requires "Type">
+%! rng (struct ("Type1",[],"State",[],"Seed",[]));
+%!error <GENERATOR must be a string> rng (0, struct ())
+%!error <"philox" is not available in Octave> rng (0, "philox")
+%!error <GENERATOR must be a string> rng ("shuffle", struct ())
+%!error <unknown random number generator "foobar"> rng ("shuffle", "foobar")
--- a/scripts/general/rot90.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/rot90.m	Sun May 16 09:44:35 2021 +0200
@@ -65,7 +65,7 @@
 
 function B = rot90 (A, k = 1)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -140,8 +140,7 @@
 %! assert (rot90 (a, 3), rot90 (b, 2));
 
 ## Test input validation
-%!error rot90 ()
-%!error rot90 (1, 2, 3)
+%!error <Invalid call> rot90 ()
 %!error rot90 (1, ones (2))
 %!error rot90 (1, 1.5)
 %!error rot90 (1, 1+i)
--- a/scripts/general/rotdim.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/rotdim.m	Sun May 16 09:44:35 2021 +0200
@@ -65,7 +65,7 @@
 
 function y = rotdim (x, n, plane)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -164,5 +164,4 @@
 ## FIXME: We need tests for multidimensional arrays
 ##        and different values of PLANE.
 
-%!error rotdim ()
-%!error rotdim (1, 2, 3, 4)
+%!error <Invalid call> rotdim ()
--- a/scripts/general/shift.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/shift.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function y = shift (x, b, dim)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -91,11 +91,11 @@
 %! assert (shift (m, -2), [c; a; b]);
 
 ## Test input validation
-%!error shift ()
-%!error shift (1, 2, 3, 4)
-%!error shift ([], 1)
-%!error shift (ones (2), ones (2))
-%!error shift (ones (2), 1.5)
-%!error shift (1, 1, 1.5)
-%!error shift (1, 1, 0)
-%!error shift (1, 1, 3)
+%!error <Invalid call> shift ()
+%!error <Invalid call> shift (1)
+%!error <X must not be empty> shift ([], 1)
+%!error <B must be an integer> shift (ones (2), ones (2))
+%!error <B must be an integer> shift (ones (2), 1.5)
+%!error <DIM must be an integer> shift (1, 1, 1.5)
+%!error <DIM must be .* a valid dimension> shift (1, 1, 0)
+%!error <DIM must be .* a valid dimension> shift (1, 1, 3)
--- a/scripts/general/shiftdim.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/shiftdim.m	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
 
 function [y, ns]  = shiftdim (x, n)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -104,7 +104,6 @@
 %!assert (size (shiftdim (rand (0, 1, 2))), [0 1 2])
 
 ## Test input validation
-%!error (shiftdim ())
-%!error (shiftdim (1,2,3))
-%!error (shiftdim (1, ones (2)))
-%!error (shiftdim (1, 1.5))
+%!error <Invalid call> shiftdim ()
+%!error shiftdim (1, ones (2))
+%!error shiftdim (1, 1.5)
--- a/scripts/general/sortrows.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/sortrows.m	Sun May 16 09:44:35 2021 +0200
@@ -53,7 +53,7 @@
 
 function [s, i] = sortrows (A, c)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -159,8 +159,7 @@
 %! assert (C2, flipud (C));
 
 ## Test input validation
-%!error sortrows ()
-%!error sortrows (1, 2, 3)
+%!error <Invalid call> sortrows ()
 %!error sortrows (1, "ascend")
 %!error sortrows (1, ones (2,2))
 %!error sortrows (1, 0)
--- a/scripts/general/sph2cart.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/sph2cart.m	Sun May 16 09:44:35 2021 +0200
@@ -26,22 +26,45 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {[@var{x}, @var{y}, @var{z}] =} sph2cart (@var{theta}, @var{phi}, @var{r})
 ## @deftypefnx {} {[@var{x}, @var{y}, @var{z}] =} sph2cart (@var{S})
-## @deftypefnx {} {@var{C} =} sph2cart (@dots{})
 ## Transform spherical coordinates to Cartesian coordinates.
 ##
 ## The inputs @var{theta}, @var{phi}, and @var{r} must be the same shape, or
 ## scalar.  If called with a single matrix argument then each row of @var{S}
-## represents the spherical coordinate (@var{theta}, @var{phi}, @var{r}).
+## must represent a spherical coordinate triplet (@var{theta}, @var{phi},
+## @var{r}).
 ##
-## @var{theta} describes the angle relative to the positive x-axis.
+## The outputs @var{x}, @var{y}, @var{z} match the shape of the inputs.  For a
+## matrix input @var{S} the outputs are column vectors with rows corresponding
+## to the rows of the input matrix.
 ##
-## @var{phi} is the angle relative to the xy-plane.
+## @var{theta} describes the azimuth angle relative to the positive x-axis
+## measured in the xy-plane.
+##
+## @var{phi} is the elevation angle measured relative to the xy-plane.
 ##
 ## @var{r} is the distance to the origin @w{(0, 0, 0)}.
 ##
-## If only a single return argument is requested then return a matrix @var{C}
-## where each row represents one Cartesian coordinate
-## (@var{x}, @var{y}, @var{z}).
+## The coordinate transformation is computed using:
+##
+## @tex
+## $$ x = r \cos \phi  \cos \theta $$
+## $$ y = r \cos \phi  \sin \theta $$
+## $$ z = r \sin \phi $$
+## @end tex
+## @ifnottex
+##
+## @example
+## @group
+## @var{x} = r * cos (@var{phi}) * cos (@var{theta})
+## @var{y} = r * cos (@var{phi}) * sin (@var{theta})
+## @var{z} = r * sin (@var{phi})
+## @end group
+## @end example
+##
+## @end ifnottex
+## @c FIXME: Remove this note in Octave 9.1 (two releases after 7.1).
+## Note: For @sc{matlab} compatibility, this function no longer returns a full
+## coordinate matrix when called with a single return argument.
 ## @seealso{cart2sph, pol2cart, cart2pol}
 ## @end deftypefn
 
@@ -52,19 +75,30 @@
   endif
 
   if (nargin == 1)
-    if (! (isnumeric (theta) && ismatrix (theta) && columns (theta) == 3))
-      error ("sph2cart: matrix input must have 3 columns [THETA, PHI, R]");
+    if (! (isnumeric (theta) && ismatrix (theta)))
+      error ("sph2cart: matrix input must be a 2-D numeric array");
+    endif
+    if (columns (theta) != 3 && numel (theta) != 3)
+      error ("sph2cart: matrix input must be a 3-element vector or 3-column array");
     endif
-    r = theta(:,3);
-    phi = theta(:,2);
-    theta = theta(:,1);
+
+    if (numel (theta) == 3)
+      r = theta(3);
+      phi = theta(2);
+      theta = theta(1);
+    else
+      r = theta(:,3);
+      phi = theta(:,2);
+      theta = theta(:,1);
+    endif
+
   else
-    if (! isnumeric (theta) || ! isnumeric (phi) || ! isnumeric (r))
-      error ("sph2cart: THETA, PHI, R must be numeric arrays of the same size, or scalar");
+    if (! (isnumeric (theta) && isnumeric (phi) && isnumeric (r)))
+      error ("sph2cart: THETA, PHI, R must be numeric arrays or scalars");
     endif
     [err, theta, phi, r] = common_size (theta, phi, r);
     if (err)
-      error ("sph2cart: THETA, PHI, R must be numeric arrays of the same size, or scalar");
+      error ("sph2cart: THETA, PHI, R must be the same size or scalars");
     endif
   endif
 
@@ -72,10 +106,6 @@
   y = r .* cos (phi) .* sin (theta);
   z = r .* sin (phi);
 
-  if (nargout <= 1)
-    x = [x(:), y(:), z(:)];
-  endif
-
 endfunction
 
 
@@ -89,13 +119,22 @@
 %! assert (z, [0, 0, 0]);
 
 %!test
+%! t = [0; 0; 0];
+%! p = [0; 0; 0];
+%! r = [0; 1; 2];
+%! [x, y, z] = sph2cart (t, p, r);
+%! assert (x, [0; 1; 2]);
+%! assert (y, [0; 0; 0]);
+%! assert (z, [0; 0; 0]);
+
+%!test
 %! t = 0;
 %! p = [0, 0, 0];
 %! r = [0, 1, 2];
-%! C = sph2cart (t, p, r);
-%! assert (C(:,1), r(:));
-%! assert (C(:,2), [0; 0; 0]);
-%! assert (C(:,3), [0; 0; 0]);
+%! [x, y, z] = sph2cart (t, p, r);
+%! assert (x, [0, 1, 2]);
+%! assert (y, [0, 0, 0]);
+%! assert (z, [0, 0, 0]);
 
 %!test
 %! t = [0, 0, 0];
@@ -123,31 +162,42 @@
 
 %!test
 %! S = [ 0, 0, 1; 0.5*pi, 0, 1; pi, 0, 1];
-%! C = [ 1, 0, 0; 0, 1, 0; -1, 0, 0];
-%! assert (sph2cart (S), C, eps);
+%! [x, y, z] = sph2cart (S);
+%! assert (x, [1; 0; -1], eps);
+%! assert (y, [0; 1; 0], eps);
+%! assert (z, [0; 0; 0], eps);
+
+%!test
+%! S = [ 0, 0, 1; 0.5*pi, 0, 1; pi, 0, 1; pi, pi, 1];
+%! [x, y, z] = sph2cart (S);
+%! assert (x, [1; 0; -1; 1], eps);
+%! assert (y, [0; 1; 0; 0], eps);
+%! assert (z, [0; 0; 0; 0], eps);
+
 
 %!test
 %! [t, p, r] = meshgrid ([0, pi/2], [0, pi/2], [0, 1]);
 %! [x, y, z] = sph2cart (t, p, r);
-%! X = zeros(2, 2, 2);
+%! X = zeros (2, 2, 2);
 %! X(1, 1, 2) = 1;
-%! Y = zeros(2, 2, 2);
+%! Y = zeros (2, 2, 2);
 %! Y(1, 2, 2) = 1;
-%! Z = zeros(2, 2, 2);
+%! Z = zeros (2, 2, 2);
 %! Z(2, :, 2) = [1 1];
 %! assert (x, X, eps);
 %! assert (y, Y, eps);
 %! assert (z, Z);
 
 ## Test input validation
-%!error sph2cart ()
-%!error sph2cart (1,2)
-%!error sph2cart (1,2,3,4)
-%!error <matrix input must have 3 columns> sph2cart ({1,2,3})
-%!error <matrix input must have 3 columns> sph2cart (ones (3,3,2))
-%!error <matrix input must have 3 columns> sph2cart ([1,2,3,4])
-%!error <numeric arrays of the same size> sph2cart ({1,2,3}, [1,2,3], [1,2,3])
-%!error <numeric arrays of the same size> sph2cart ([1,2,3], {1,2,3}, [1,2,3])
-%!error <numeric arrays of the same size> sph2cart ([1,2,3], [1,2,3], {1,2,3})
-%!error <numeric arrays of the same size> sph2cart (ones (3,3,3), 1, ones (3,2,3))
-%!error <numeric arrays of the same size> sph2cart (ones (3,3,3), ones (3,2,3), 1)
+%!error <Invalid call> sph2cart ()
+%!error <Invalid call> sph2cart (1,2)
+%!error <matrix input must be a 2-D numeric array> sph2cart ({1,2,3})
+%!error <matrix input must be a 2-D numeric array> sph2cart (ones (3,3,2))
+%!error <matrix input must be a 3-element> sph2cart ([1,2,3,4])
+%!error <matrix input must be a 3-element> sph2cart ([1,2,3,4; 1,2,3,4; 1,2,3,4])
+%!error <must be numeric arrays or scalars> sph2cart ({1,2,3}, [1,2,3], [1,2,3])
+%!error <must be numeric arrays or scalars> sph2cart ([1,2,3], {1,2,3}, [1,2,3])
+%!error <must be numeric arrays or scalars> sph2cart ([1,2,3], [1,2,3], {1,2,3})
+%!error <must be the same size or scalars> sph2cart ([1,2,3], [1,2,3], [1,2,3]')
+%!error <must be the same size or scalars> sph2cart (ones (3,3,3), 1, ones (3,2,3))
+%!error <must be the same size or scalars> sph2cart (ones (3,3,3), ones (3,2,3), 1)
--- a/scripts/general/structfun.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/structfun.m	Sun May 16 09:44:35 2021 +0200
@@ -70,7 +70,7 @@
 ## elements @qcode{"identifier"}, @qcode{"message"} and @qcode{"index"},
 ## giving respectively the error identifier, the error message, and the index
 ## into the input arguments of the element that caused the error.  For an
-## example on how to use an error handler, @pxref{XREFcellfun,,cellfun}.
+## example on how to use an error handler, @pxref{XREFcellfun,,@code{cellfun}}.
 ##
 ## @seealso{cellfun, arrayfun, spfun}
 ## @end deftypefn
--- a/scripts/general/subsindex.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/subsindex.m	Sun May 16 09:44:35 2021 +0200
@@ -69,7 +69,7 @@
 
 function idx = subsindex (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -82,5 +82,4 @@
 %!error <not defined for class "double"> subsindex (1)
 
 ## Test input validation
-%!error subsindex ()
-%!error subsindex (1, 2)
+%!error <Invalid call> subsindex ()
--- a/scripts/general/trapz.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/trapz.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 
 function z = trapz (x, y, dim)
 
-  if (nargin < 1) || (nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -153,8 +153,7 @@
 %!assert <*54277> (trapz (ones (3,1), 2), zeros (3,1))
 
 ## Test input validation
-%!error trapz ()
-%!error trapz (1,2,3,4)
+%!error <Invalid call> trapz ()
 %!error <DIM must be an integer> trapz (1, 2, [1 2])
 %!error <DIM must be an integer> trapz (1, 2, 1.5)
 %!error <DIM must be .* a valid dimension> trapz (1, 2, 0)
--- a/scripts/general/xor.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/general/xor.m	Sun May 16 09:44:35 2021 +0200
@@ -98,6 +98,6 @@
 %!assert (xor ([1 0], [1 1], [0 0]), logical ([0 1]))
 
 ## Test input validation
-%!error xor ()
-%!error xor (1)
+%!error <Invalid call> xor ()
+%!error <Invalid call> xor (1)
 %!error <X and Y must be of compatible size> xor (ones (3,2), ones (2,3))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/geometry/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/geometry/convhull.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/convhull.m	Sun May 16 09:44:35 2021 +0200
@@ -193,12 +193,12 @@
 %! assert (V == 2);
 
 ## Input validation tests
-%!error convhull ()
-%!error convhull (1,2,3,4,5)
+%!error <Invalid call> convhull ()
+%!error <Invalid call> convhull (1,2,3,4,5)
 %!error <X must be a matrix with 2 or 3 columns> convhull (ones (2,4))
-%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), struct())
+%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), struct ())
 %!error <X must be a matrix with 2 or 3 columns> convhull (ones (2,4), "")
-%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), ones (2,2), struct())
-%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), ones (2,2), ones (2,2), struct())
+%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), ones (2,2), struct ())
+%!error <OPTIONS must be a string or cell array> convhull (ones (2,2), ones (2,2), ones (2,2), struct ())
 %!error <X and Y must be the same size> convhull (1, [1 2])
 %!error <X, Y, and Z must be the same size> convhull (1, [1 2], [1 2])
--- a/scripts/geometry/delaunay.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/delaunay.m	Sun May 16 09:44:35 2021 +0200
@@ -209,12 +209,12 @@
 %! assert (sortrows (sort (delaunay (x, y, z), 2)), [1,2,3,4;1,2,4,5]);
 
 ## Input validation tests
-%!error delaunay ()
-%!error delaunay (1,2,3,4,5)
+%!error <Invalid call> delaunay ()
+%!error <Invalid call> delaunay (1,2,3,4,5)
 %!error <X must be a matrix with 2 or 3 columns> delaunay (ones (2,4))
-%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), struct())
+%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), struct ())
 %!error <X must be a matrix with 2 or 3 columns> delaunay (ones (2,4), "")
-%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), ones (2,2), struct())
-%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), ones (2,2), ones (2,2), struct())
+%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), ones (2,2), struct ())
+%!error <OPTIONS must be a string or cell array> delaunay (ones (2,2), ones (2,2), ones (2,2), struct ())
 %!error <X and Y must be the same size> delaunay (1, [1 2])
 %!error <X, Y, and Z must be the same size> delaunay (1, [1 2], [1 2])
--- a/scripts/geometry/delaunayn.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/delaunayn.m	Sun May 16 09:44:35 2021 +0200
@@ -106,8 +106,8 @@
     p12 = p1 - p2;
     p23 = p2 - p3;
     det = cross (p12, p23, 2);
-    idx = abs (det(:,3) ./ sqrt (sumsq (p12, 2))) < tol & ...
-          abs (det(:,3) ./ sqrt (sumsq (p23, 2))) < tol;
+    idx = abs (det (:,3) ./ sqrt (sumsq (p12, 2))) < tol & ...
+          abs (det (:,3) ./ sqrt (sumsq (p23, 2))) < tol;
   else
     ## FIXME: Vectorize this for loop or convert delaunayn to .oct function
     idx = [];
@@ -135,4 +135,4 @@
 ## FIXME: Need tests for delaunayn
 
 ## Input validation tests
-%!error delaunayn ()
+%!error <Invalid call> delaunayn ()
--- a/scripts/geometry/dsearch.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/dsearch.m	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
 
 function idx = dsearch (x, y, tri, xi, yi, s)
 
-  if (nargin < 5 || nargin > 6)
+  if (nargin < 5)
     print_usage ();
   endif
 
--- a/scripts/geometry/dsearchn.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/dsearchn.m	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,7 @@
 
 function [idx, d] = dsearchn (x, tri, xi, outval)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/geometry/griddata.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/griddata.m	Sun May 16 09:44:35 2021 +0200
@@ -27,123 +27,232 @@
 ## @deftypefn  {} {@var{zi} =} griddata (@var{x}, @var{y}, @var{z}, @var{xi}, @var{yi})
 ## @deftypefnx {} {@var{zi} =} griddata (@var{x}, @var{y}, @var{z}, @var{xi}, @var{yi}, @var{method})
 ## @deftypefnx {} {[@var{xi}, @var{yi}, @var{zi}] =} griddata (@dots{})
+## @deftypefnx {} {@var{vi} =} griddata (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi})
+## @deftypefnx {} {@var{vi} =} griddata (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi}, @var{method})
+## @deftypefnx {} {@var{vi} =} griddata (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi}, @var{method}, @var{options})
 ##
-## Generate a regular mesh from irregular data using interpolation.
+## Interpolate irregular 2-D and 3-D source data at specified points.
+##
+## For 2-D interpolation, the inputs @var{x} and @var{y} define the points
+## where the function @code{@var{z} = f (@var{x}, @var{y})} is evaluated.
+## The inputs @var{x}, @var{y}, @var{z} are either vectors of the same length,
+## or the unequal vectors @var{x}, @var{y} are expanded to a 2-D grid with
+## @code{meshgrid} and @var{z} is a 2-D matrix matching the resulting size of
+## the X-Y grid.
+##
+## The interpolation points are (@var{xi}, @var{yi}).  If, and only if,
+## @var{xi} is a row vector and @var{yi} is a column vector, then
+## @code{meshgrid} will be used to create a mesh of interpolation points.
 ##
-## The function is defined by @code{@var{z} = f (@var{x}, @var{y})}.  Inputs
-## @code{@var{x}, @var{y}, @var{z}} are vectors of the same length or
-## @code{@var{x}, @var{y}} are vectors and @code{@var{z}} is matrix.
+## For 3-D interpolation, the inputs @var{x}, @var{y}, and @var{z} define the
+## points where the function @code{@var{v} = f (@var{x}, @var{y}, @var{z})}
+## is evaluated.  The inputs @var{x}, @var{y}, @var{z} are either vectors of
+## the same length, or if they are of unequal length, then they are expanded to
+## a 3-D grid with @code{meshgrid}.  The size of the input @var{v} must match
+## the size of the original data, either as a vector or a matrix.
 ##
-## The interpolation points are all @code{(@var{xi}, @var{yi})}.  If @var{xi},
-## @var{yi} are vectors then they are made into a 2-D mesh.
+## The optional input interpolation @var{method} can be @qcode{"nearest"},
+## @qcode{"linear"}, or for 2-D data @qcode{"v4"}.  When the method is
+## @qcode{"nearest"}, the output @var{vi} will be the closest point in the
+## original data (@var{x}, @var{y}, @var{z}) to the query point (@var{xi},
+## @var{yi}, @var{zi}).  When the method is @qcode{"linear"}, the output
+## @var{vi} will be a linear interpolation between the two closest points in
+## the original source data in each dimension.  For 2-D cases only, the
+## @qcode{"v4"} method is also available which implements a biharmonic spline
+## interpolation.  If @var{method} is omitted or empty, it defaults to
+## @qcode{"linear"}.
 ##
-## The interpolation method can be @qcode{"nearest"}, @qcode{"cubic"} or
-## @qcode{"linear"}.  If method is omitted it defaults to @qcode{"linear"}.
+## For 3-D interpolation, the optional argument @var{options} is passed
+## directly to Qhull when computing the Delaunay triangulation used for
+## interpolation.  For more information on the defaults and how to pass
+## different values, @pxref{XREFdelaunayn,,@code{delaunayn}}.
+##
+## Programming Notes: If the input is complex the real and imaginary parts
+## are interpolated separately.  Interpolation is normally based on a
+## Delaunay triangulation.  Any query values outside the convex hull of the
+## input points will return @code{NaN}.  However, the @qcode{"v4"} method does
+## not use the triangulation and will return values outside the original data
+## (extrapolation).
 ## @seealso{griddata3, griddatan, delaunay}
 ## @end deftypefn
 
-## Algorithm: xi and yi are not "meshgridded" if both are vectors
-##            of the same size (for compatibility)
+function [rx, ry, rz] = griddata (x, y, z, varargin)
 
-function [rx, ry, rz] = griddata (x, y, z, xi, yi, method = "linear")
-
-  if (nargin < 5 || nargin > 7)
+  if (nargin < 5)
     print_usage ();
   endif
 
-  if (ischar (method))
-    method = tolower (method);
-  endif
-
-  ## Meshgrid if x and y are vectors but z is matrix
-  if (isvector (x) && isvector (y) && all ([numel(y), numel(x)] == size (z)))
-    [x, y] = meshgrid (x, y);
-  endif
-
-  if (isvector (x) && isvector (y) && isvector (z))
-    if (! isequal (length (x), length (y), length (z)))
-      error ("griddata: X, Y, and Z must be vectors of the same length");
-    endif
-  elseif (! size_equal (x, y, z))
-    error ("griddata: lengths of X, Y must match the columns and rows of Z");
-  endif
-
-  ## Meshgrid xi and yi if they are a row and column vector.
-  if (rows (xi) == 1 && columns (yi) == 1)
-    [xi, yi] = meshgrid (xi, yi);
-  elseif (isvector (xi) && isvector (yi))
-    ## Otherwise, convert to column vectors
-    xi = xi(:);
-    yi = yi(:);
-  endif
-
-  if (! size_equal (xi, yi))
-    error ("griddata: XI and YI must be vectors or matrices of same size");
-  endif
-
-  x = x(:);
-  y = y(:);
-  z = z(:);
-
-  ## Triangulate data.
-  tri = delaunay (x, y);
-  zi = NaN (size (xi));
-
-  if (strcmp (method, "cubic"))
-    error ("griddata: cubic interpolation not yet implemented");
+  if (nargin > 6)
+    ## Current 2D implementation has nargin max = 6, since no triangulation
+    ## options are passed to the 2D algorithm. 3D algorithm requires nargin >=7
 
-  elseif (strcmp (method, "nearest"))
-    ## Search index of nearest point.
-    idx = dsearch (x, y, tri, xi, yi);
-    valid = ! isnan (idx);
-    zi(valid) = z(idx(valid));
-
-  elseif (strcmp (method, "linear"))
-    ## Search for every point the enclosing triangle.
-    tri_list = tsearch (x, y, tri, xi(:), yi(:));
-
-    ## Only keep the points within triangles.
-    valid = ! isnan (tri_list);
-    tri_list = tri_list(valid);
-    nr_t = rows (tri_list);
-
-    tri = tri(tri_list,:);
-
-    ## Assign x,y,z for each point of triangle.
-    x1 = x(tri(:,1));
-    x2 = x(tri(:,2));
-    x3 = x(tri(:,3));
-
-    y1 = y(tri(:,1));
-    y2 = y(tri(:,2));
-    y3 = y(tri(:,3));
-
-    z1 = z(tri(:,1));
-    z2 = z(tri(:,2));
-    z3 = z(tri(:,3));
-
-    ## Calculate norm vector.
-    N = cross ([x2-x1, y2-y1, z2-z1], [x3-x1, y3-y1, z3-z1]);
-    ## Normalize.
-    N = diag (norm (N, "rows")) \ N;
-
-    ## Calculate D of plane equation
-    ## Ax+By+Cz+D = 0;
-    D = -(N(:,1) .* x1 + N(:,2) .* y1 + N(:,3) .* z1);
-
-    ## Calculate zi by solving plane equation for xi, yi.
-    zi(valid) = -(N(:,1).*xi(:)(valid) + N(:,2).*yi(:)(valid) + D) ./ N(:,3);
+    if (nargout > 1)
+      error ("griddata: only one output argument valid for 3-D interpolation");
+    endif
+    rx = griddata3 (x, y, z, varargin{:});
 
   else
-    error ("griddata: unknown interpolation METHOD");
-  endif
+    ## for nargin 5 or 6, assign varargin terms to variables for 2D algorithm
+    xi = varargin{1};
+    yi = varargin{2};
+
+    ## Meshgrid if x and y are vectors but z is matrix
+    if (isvector (x) && isvector (y) && all ([numel(y), numel(x)] == size (z)))
+      [x, y] = meshgrid (x, y);
+    endif
+
+    if (isvector (x) && isvector (y) && isvector (z))
+      if (! isequal (length (x), length (y), length (z)))
+        error ("griddata: X, Y, and Z must be vectors of the same length");
+      endif
+    elseif (! size_equal (x, y, z))
+      error ("griddata: lengths of X, Y must match the columns and rows of Z");
+    endif
+
+    ## Meshgrid xi and yi if they are a row and column vector, but not
+    ## if they are simply vectors of the same size (for compatibility).
+    if (isrow (xi) && iscolumn (yi))
+      [xi, yi] = meshgrid (xi, yi);
+    elseif (isvector (xi) && isvector (yi))
+      ## Otherwise, convert to column vectors
+      xi = xi(:);
+      yi = yi(:);
+    endif
+
+    if (! size_equal (xi, yi))
+      error ("griddata: XI and YI must be vectors or matrices of same size");
+    endif
+
+    if (nargin == 6)
+      method = varargin{3};
+      if (isempty (method))
+        method = "linear";
+      elseif (! ischar (method))
+        error ("griddata: METHOD must be a string");
+      else
+        method = tolower (method);
+      endif
+
+      if (any (strcmp (method, {"linear", "nearest", "v4"})))
+        ## Do nothing, these are implemented methods
+      elseif (any (strcmp (method, {"cubic", "natural"})))
+        ## FIXME: implement missing interpolation methods.
+        error ('griddata: "%s" interpolation not yet implemented', method);
+      else
+        error ('griddata: unknown interpolation METHOD: "%s"', method);
+      endif
+    else
+      method = "linear";
+    endif
+
+    x = x(:);
+    y = y(:);
+    z = z(:);
+
+    ## Triangulate data.
+    if (! strcmp (method, "v4"))
+      tri = delaunay (x, y);
+    endif
+    zi = NaN (size (xi));
+
+    if (strcmp (method, "linear"))
+      ## Search for every point the enclosing triangle.
+      tri_list = tsearch (x, y, tri, xi(:), yi(:));
+
+      ## Only keep the points within triangles.
+      valid = ! isnan (tri_list);
+      tri_list = tri_list(valid);
+      nr_t = rows (tri_list);
+
+      tri = tri(tri_list,:);
+
+      ## Assign x,y,z for each point of triangle.
+      x1 = x(tri(:,1));
+      x2 = x(tri(:,2));
+      x3 = x(tri(:,3));
 
-  if (nargout > 1)
-    rx = xi;
-    ry = yi;
-    rz = zi;
-  else
-    rx = zi;
+      y1 = y(tri(:,1));
+      y2 = y(tri(:,2));
+      y3 = y(tri(:,3));
+
+      z1 = z(tri(:,1));
+      z2 = z(tri(:,2));
+      z3 = z(tri(:,3));
+
+      ## Calculate norm vector.
+      N = cross ([x2-x1, y2-y1, z2-z1], [x3-x1, y3-y1, z3-z1]);
+      ## Normalize.
+      N = diag (norm (N, "rows")) \ N;
+
+      ## Calculate D of plane equation: Ax+By+Cz+D = 0
+      D = -(N(:,1) .* x1 + N(:,2) .* y1 + N(:,3) .* z1);
+
+      ## Calculate zi by solving plane equation for xi, yi.
+      zi(valid) = -(N(:,1).*xi(:)(valid) + N(:,2).*yi(:)(valid) + D) ./ N(:,3);
+
+    elseif (strcmp (method, "nearest"))
+      ## Search index of nearest point.
+      idx = dsearch (x, y, tri, xi, yi);
+      valid = ! isnan (idx);
+      zi(valid) = z(idx(valid));
+
+    elseif (strcmp (method, "v4"))
+      ## Use Biharmonic Spline Interpolation Green's Function method.
+      ## Compatible with Matlab v4 interpolation method, based on
+      ## D. Sandwell 1987 and Deng & Tang 2011.
+
+      ## The free space Green Function which solves the two dimensional
+      ## Biharmonic PDE
+      ##
+      ## Delta(Delta(G(X))) = delta(X)
+      ##
+      ## for a point source yields
+      ##
+      ## G(X) = |X|^2 * (ln|X|-1) / (8 * pi)
+      ##
+      ## An N-point Biharmonic Interpolation at the point X is given by
+      ##
+      ## z(X) = sum_j_N (alpha_j * G(X-Xj))
+      ##      = sum_j_N (alpha_j * G(rj))
+      ##
+      ## in which the coefficients alpha_j are the unknowns.  rj is the
+      ## Euclidean distance between X and Xj.
+      ## From N datapoints {zi, Xi} an equation system can be formed:
+      ##
+      ## zi(Xi) = sum_j_N (alpha_j * G(Xi-Xj))
+      ##        = sum_j_N (alpha_j * G(rij))
+      ##
+      ## Its inverse yields the unknowns alpha_j.
+
+      ## Step1: Solve for weight coefficients alpha_j depending on the
+      ## Euclidean distances and the training data set {x,y,z}
+      r = sqrt ((x - x.').^2 + (y - y.').^2);  # size N^2
+      D = (r.^2) .* (log (r) - 1);
+      D(isnan (D)) = 0;  # Fix Green Function for r=0
+      alpha_j = D \ z;
+
+      ## Step2 - Use alphas and Green's functions to get interpolated points.
+      ## Use dim3 projection for vectorized calculation to avoid loops.
+      ## Memory usage is proportional to Ni x N.
+      ## FIXME: if this approach is too memory intensive, revert portion to loop
+      x = permute (x, [3, 2, 1]);
+      y = permute (y, [3, 2, 1]);
+      alpha_j = permute (alpha_j, [3, 2, 1]);
+      r_i = sqrt ((xi - x).^2 + (yi - y).^2);  # size Ni x N
+      Di = (r_i.^2) .* (log (r_i) - 1);
+      Di(isnan (Di)) = 0;  # Fix Green's Function for r==0
+      zi = sum (Di .* alpha_j, 3);
+
+    endif
+
+    if (nargout > 1)
+      rx = xi;
+      ry = yi;
+      rz = zi;
+    else
+      rx = zi;
+    endif
+
   endif
 
 endfunction
@@ -155,10 +264,10 @@
 %! x = 2*rand (100,1) - 1;
 %! y = 2*rand (size (x)) - 1;
 %! z = sin (2*(x.^2 + y.^2));
-%! [xx,yy] = meshgrid (linspace (-1,1,32));
+%! [xx,yy] = meshgrid (linspace (-1, 1, 32));
 %! zz = griddata (x,y,z,xx,yy);
 %! mesh (xx, yy, zz);
-%! title ("nonuniform grid sampled at 100 points");
+%! title ("non-uniform grid sampled at 100 points");
 
 %!demo
 %! clf;
@@ -166,10 +275,11 @@
 %! x = 2*rand (1000,1) - 1;
 %! y = 2*rand (size (x)) - 1;
 %! z = sin (2*(x.^2 + y.^2));
-%! [xx,yy] = meshgrid (linspace (-1,1,32));
+%! [xx,yy] = meshgrid (linspace (-1, 1, 32));
 %! zz = griddata (x,y,z,xx,yy);
 %! mesh (xx, yy, zz);
-%! title ("nonuniform grid sampled at 1000 points");
+%! title ({"non-uniform grid sampled at 1,000 points",
+%!         'method = "linear"'});
 
 %!demo
 %! clf;
@@ -177,34 +287,63 @@
 %! x = 2*rand (1000,1) - 1;
 %! y = 2*rand (size (x)) - 1;
 %! z = sin (2*(x.^2 + y.^2));
-%! [xx,yy] = meshgrid (linspace (-1,1,32));
+%! [xx,yy] = meshgrid (linspace (-1, 1, 32));
 %! zz = griddata (x,y,z,xx,yy,"nearest");
 %! mesh (xx, yy, zz);
-%! title ("nonuniform grid sampled at 1000 points with nearest neighbor");
+%! title ({"non-uniform grid sampled at 1,000 points",
+%!         'method = "nearest neighbor"'});
 
 %!testif HAVE_QHULL
-%! [xx,yy] = meshgrid (linspace (-1,1,32));
+%! [xx, yy] = meshgrid (linspace (-1, 1, 32));
 %! x = xx(:);
 %! x = x + 10*(2*round (rand (size (x))) - 1) * eps;
 %! y = yy(:);
 %! y = y + 10*(2*round (rand (size (y))) - 1) * eps;
 %! z = sin (2*(x.^2 + y.^2));
-%! zz = griddata (x,y,z,xx,yy,"linear");
+%! zz = griddata (x,y,z,xx,yy, "linear");
 %! zz2 = sin (2*(xx.^2 + yy.^2));
 %! zz2(isnan (zz)) = NaN;
 %! assert (zz, zz2, 100*eps);
 
+%!testif HAVE_QHULL
+%! [xx, yy] = meshgrid (linspace (-1, 1, 5));
+%! x = xx(:);
+%! x = x + 10*(2*round (rand (size (x))) - 1) * eps;
+%! y = yy(:);
+%! y = y + 10*(2*round (rand (size (y))) - 1) * eps;
+%! z = 2*(x.^2 + y.^2);
+%! zz = griddata (x,y,z,xx,yy, "v4");
+%! zz2 = 2*(xx.^2 + yy.^2);
+%! zz2(isnan (zz)) = NaN;
+%! assert (zz, zz2, 100*eps);
+
+%!testif HAVE_QHULL
+%! [xx, yy] = meshgrid (linspace (-1, 1, 5));
+%! x = xx(:);
+%! x = x + 10*(2*round (rand (size (x))) - 1) * eps;
+%! y = yy(:);
+%! y = y + 10*(2*round (rand (size (y))) - 1) * eps;
+%! z = 2*(x.^2 + y.^2);
+%! zz = griddata (x,y,z,xx,yy, "nearest");
+%! zz2 = 2*(xx.^2 + yy.^2);
+%! zz2(isnan (zz)) = NaN;
+%! assert (zz, zz2, 100*eps);
+
 ## Test input validation
-%!error griddata ()
-%!error griddata (1)
-%!error griddata (1,2)
-%!error griddata (1,2,3)
-%!error griddata (1,2,3,4)
-%!error griddata (1,2,3,4,5,6,7)
+%!error <Invalid call> griddata ()
+%!error <Invalid call> griddata (1)
+%!error <Invalid call> griddata (1,2)
+%!error <Invalid call> griddata (1,2,3)
+%!error <Invalid call> griddata (1,2,3,4)
+%!error <only one output argument> [xi,yi] = griddata (1,2,3,4,5,6,7)
+%!error <vectors of the same length> griddata (1:4, 1:3, 1:3, 1:3, 1:3)
+%!error <vectors of the same length> griddata (1:3, 1:4, 1:3, 1:3, 1:3)
 %!error <vectors of the same length> griddata (1:3, 1:3, 1:4, 1:3, 1:3)
-%!error <vectors of the same length> griddata (1:3, 1:4, 1:3, 1:3, 1:3)
-%!error <vectors of the same length> griddata (1:4, 1:3, 1:3, 1:3, 1:3)
 %!error <the columns and rows of Z> griddata (1:4, 1:3, ones (4,4), 1:3, 1:3)
 %!error <the columns and rows of Z> griddata (1:4, 1:3, ones (3,5), 1:3, 1:3)
-%!error <matrices of same size> griddata (1:3, 1:3, 1:3, 1:4, 1:3)
-%!error <matrices of same size> griddata (1:3, 1:3, 1:3, 1:3, 1:4)
+%!error <XI and YI .* matrices of same size> griddata (1:3, 1:3, 1:3, 1:4, 1:3)
+%!error <XI and YI .* matrices of same size> griddata (1:3, 1:3, 1:3, 1:3, 1:4)
+%!error <METHOD must be a string> griddata (1,2,3,4,5, {"linear"})
+%!error <"cubic" .* not yet implemented> griddata (1,2,3,4,5, "cubic")
+%!error <"natural" .* not yet implemented> griddata (1,2,3,4,5, "natural")
+%!error <unknown interpolation METHOD: "foobar"> griddata (1,2,3,4,5, "foobar")
--- a/scripts/geometry/griddata3.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/griddata3.m	Sun May 16 09:44:35 2021 +0200
@@ -28,18 +28,34 @@
 ## @deftypefnx {} {@var{vi} =} griddata3 (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi}, @var{method})
 ## @deftypefnx {} {@var{vi} =} griddata3 (@var{x}, @var{y}, @var{z}, @var{v}, @var{xi}, @var{yi}, @var{zi}, @var{method}, @var{options})
 ##
-## Generate a regular mesh from irregular data using interpolation.
+## Interpolate irregular 3-D source data at specified points.
 ##
-## The function is defined by @code{@var{v} = f (@var{x}, @var{y}, @var{z})}.
+## The inputs @var{x}, @var{y}, and @var{z} define the points where the
+## function @code{@var{v} = f (@var{x}, @var{y}, @var{z})} is evaluated.  The
+## inputs @var{x}, @var{y}, @var{z} are either vectors of the same length, or
+## if they are of unequal length, then they are expanded to a 3-D grid with
+## @code{meshgrid}.  The size of the input @var{v} must match the size of the
+## original data, either as a vector or a matrix.
+##
 ## The interpolation points are specified by @var{xi}, @var{yi}, @var{zi}.
 ##
-## The interpolation method can be @qcode{"nearest"} or @qcode{"linear"}.
-## If method is omitted it defaults to @qcode{"linear"}.
+## The optional input interpolation @var{method} can be @qcode{"nearest"} or
+## @qcode{"linear"}.  When the method is @qcode{"nearest"}, the output @var{vi}
+## will be the closest point in the original data (@var{x}, @var{y}, @var{z})
+## to the query point (@var{xi}, @var{yi}, @var{zi}).  When the method is
+## @qcode{"linear"}, the output @var{vi} will be a linear interpolation between
+## the two closest points in the original source data in each dimension.
+## If @var{method} is omitted or empty, it defaults to @qcode{"linear"}.
 ##
 ## The optional argument @var{options} is passed directly to Qhull when
 ## computing the Delaunay triangulation used for interpolation.  See
 ## @code{delaunayn} for information on the defaults and how to pass different
 ## values.
+##
+## Programming Notes: If the input is complex the real and imaginary parts
+## are interpolated separately.  Interpolation is based on a Delaunay
+## triangulation and any query values outside the convex hull of the input
+## points will return @code{NaN}.
 ## @seealso{griddata, griddatan, delaunayn}
 ## @end deftypefn
 
@@ -105,3 +121,7 @@
 %! vi = griddata3 (x, y, z, v, xi, yi, zi, "nearest");
 %! vv = vi - xi.^2 - yi.^2 - zi.^2;
 %! assert (max (abs (vv(:))), 0.385, 0.1);
+
+## FIXME: Ideally, there should be BIST tests for input validation.
+## However, this function is deprecated in Matlab and it probably isn't worth
+## the coding time to work on a function that will be removed soon.
--- a/scripts/geometry/griddatan.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/griddatan.m	Sun May 16 09:44:35 2021 +0200
@@ -28,18 +28,56 @@
 ## @deftypefnx {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}, @var{method})
 ## @deftypefnx {} {@var{yi} =} griddatan (@var{x}, @var{y}, @var{xi}, @var{method}, @var{options})
 ##
-## Generate a regular mesh from irregular data using interpolation.
+## Interpolate irregular source data @var{x}, @var{y} at points specified by
+## @var{xi}.
 ##
-## The function is defined by @code{@var{y} = f (@var{x})}.
-## The interpolation points are all @var{xi}.
+## The input @var{x} is an MxN matrix representing M points in an N-dimensional
+## space.  The input @var{y} is a single-valued column vector (Mx1)
+## representing a function evaluated at the points @var{x}, i.e.,
+## @code{@var{y} = fcn (@var{x})}.  The input @var{xi} is a list of points
+## for which the function output @var{yi} should be approximated through
+## interpolation.  @var{xi} must have the same number of columns (@var{N})
+## as @var{x} so that the dimensionality matches.
 ##
-## The interpolation method can be @qcode{"nearest"} or @qcode{"linear"}.
-## If method is omitted it defaults to @qcode{"linear"}.
+## The optional input interpolation @var{method} can be @qcode{"nearest"} or
+## @qcode{"linear"}.  When the method is @qcode{"nearest"}, the output @var{yi}
+## will be the closest point in the original data @var{x} to the query point
+## @var{xi}.  When the method is @qcode{"linear"}, the output @var{yi} will
+## be a linear interpolation between the two closest points in the original
+## source data.  If @var{method} is omitted or empty, it defaults to
+## @qcode{"linear"}.
 ##
 ## The optional argument @var{options} is passed directly to Qhull when
 ## computing the Delaunay triangulation used for interpolation.  See
 ## @code{delaunayn} for information on the defaults and how to pass different
 ## values.
+##
+## Example
+##
+## @example
+## @group
+## ## Evaluate sombrero() function at irregular data points
+## x = 16*gallery ("uniformdata", [200,1], 1) - 8;
+## y = 16*gallery ("uniformdata", [200,1], 11) - 8;
+## z = sin (sqrt (x.^2 + y.^2)) ./ sqrt (x.^2 + y.^2);
+## ## Create a regular grid and interpolate data
+## [xi, yi] = ndgrid (linspace (-8, 8, 50));
+## zi = griddatan ([x, y], z, [xi(:), yi(:)]);
+## zi = reshape (zi, size (xi));
+## ## Plot results
+## clf ();
+## plot3 (x, y, z, "or");
+## hold on
+## surf (xi, yi, zi);
+## legend ("Original Data", "Interpolated Data");
+## @end group
+## @end example
+##
+## Programming Notes: If the input is complex the real and imaginary parts
+## are interpolated separately.  Interpolation is based on a Delaunay
+## triangulation and any query values outside the convex hull of the input
+## points will return @code{NaN}.  For 2-D and 3-D data additional
+## interpolation methods are available by using the @code{griddata} function.
 ## @seealso{griddata, griddata3, delaunayn}
 ## @end deftypefn
 
@@ -49,15 +87,41 @@
     print_usage ();
   endif
 
-  if (ischar (method))
-    method = tolower (method);
-  endif
-
   [m, n] = size (x);
   [mi, ni] = size (xi);
 
-  if (n != ni || rows (y) != m || columns (y) != 1)
-    error ("griddatan: dimensional mismatch");
+  if (m < n + 1)
+    error ("griddatan: number of points in X (rows of X) must be greater than dimensionality of data + 1 (columns of X + 1)");
+  endif
+  if (! iscolumn (y) || rows (y) != m)
+    error ("griddatan: Y must be a column vector with the same number of points (rows) as X");
+  endif
+  if (n != ni)
+    error ("griddatan: dimension of query data XI (columns) must match X");
+  endif
+
+  if (nargin > 3)
+    if (isempty (method))
+      method = "linear";
+    elseif (! ischar (method))
+      error ("griddatan: METHOD must be a string");
+    else
+      method = tolower (method);
+    endif
+
+    if (strcmp (method, "linear") || strcmp (method, "nearest"))
+      ## Do nothing, these are implemented methods
+    elseif (strcmp (method, "v4"))
+      error ('griddatan: "%s" METHOD is available for 2-D inputs by using "griddata"', method);
+
+    elseif (any (strcmp (method, {"cubic", "natural"})))
+      ## FIXME: Remove when griddata.m supports these methods.
+      error ('griddatan: "%s" interpolation METHOD not yet implemented', method);
+
+    else
+      error ('griddatan: unknown interpolation METHOD: "%s"', method);
+    endif
+
   endif
 
   ## triangulate data
@@ -65,13 +129,7 @@
 
   yi = NaN (mi, 1);
 
-  if (strcmp (method, "nearest"))
-    ## search index of nearest point
-    idx = dsearchn (x, tri, xi);
-    valid = ! isnan (idx);
-    yi(valid) = y(idx(valid));
-
-  elseif (strcmp (method, "linear"))
+  if (strcmp (method, "linear"))
     ## search for every point the enclosing triangle
     [tri_list, bary_list] = tsearchn (x, tri, xi);
 
@@ -90,7 +148,11 @@
     endif
 
   else
-    error ("griddatan: unknown interpolation METHOD");
+    ## search index of nearest point
+    idx = dsearchn (x, tri, xi);
+    valid = ! isnan (idx);
+    yi(valid) = y(idx(valid));
+
   endif
 
 endfunction
@@ -102,8 +164,8 @@
 %! x = 2*rand (100,2) - 1;
 %! x = [x;1,1;1,-1;-1,-1;-1,1];
 %! y = sin (2 * sum (x.^2,2));
-%! zz = griddatan (x,y,xi,"linear");
-%! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2),"linear");
+%! zz = griddatan (x,y,xi, "linear");
+%! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2), "linear");
 %! assert (zz, zz2, 1e-10);
 
 %!testif HAVE_QHULL
@@ -112,8 +174,8 @@
 %! x = 2*rand (100,2) - 1;
 %! x = [x;1,1;1,-1;-1,-1;-1,1];
 %! y = sin (2*sum (x.^2,2));
-%! zz = griddatan (x,y,xi,"nearest");
-%! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2),"nearest");
+%! zz = griddatan (x,y,xi, "nearest");
+%! zz2 = griddata (x(:,1),x(:,2),y,xi(:,1),xi(:,2), "nearest");
 %! assert (zz, zz2, 1e-10);
 
 %!testif HAVE_QHULL <*56515>
@@ -121,3 +183,17 @@
 %! y = [ 1; 2; 3; 4 ];
 %! xi = [ .5, .5 ];
 %! yi = griddatan (x, y, xi);
+
+## Test input validation
+%!error <Invalid call> griddatan ()
+%!error <Invalid call> griddatan (1)
+%!error <Invalid call> griddatan (1,2)
+%!error <number of points in X> griddatan (1,2,3)
+%!error <Y must be a column vector> griddatan ([1;2],[3,4], 1)
+%!error <Y must .* same number of points .* as X> griddatan ([1;2],[3;4;5], 1)
+%!error <dimension of .* XI .* must match X> griddatan ([1;2],[3;4], [1, 2])
+%!error <METHOD must be a string> griddatan ([1;2],[3;4], 1, 5)
+%!error <"v4" METHOD is available for 2-D> griddatan ([1;2],[3;4], 1, "v4")
+%!error <"cubic" .* not yet implemented> griddatan ([1;2],[3;4], 1, "cubic")
+%!error <"natural" .* not yet implemented> griddatan ([1;2],[3;4], 1, "natural")
+%!error <unknown .* METHOD: "foobar"> griddatan ([1;2],[3;4], 1, "foobar")
--- a/scripts/geometry/inpolygon.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/inpolygon.m	Sun May 16 09:44:35 2021 +0200
@@ -158,10 +158,9 @@
 %! assert (on, ON);
 
 ## Test input validation
-%!error inpolygon ()
-%!error inpolygon (1, 2)
-%!error inpolygon (1, 2, 3)
-%!error inpolygon (1, 2, 3, 4, 5)
+%!error <Invalid call> inpolygon ()
+%!error <Invalid call> inpolygon (1, 2)
+%!error <Invalid call> inpolygon (1, 2, 3)
 %!error <X and Y must be real> inpolygon (1i, 1, [3, 4], [5, 6])
 %!error <X and Y must be real> inpolygon (1, {1}, [3, 4], [5, 6])
 %!error <X and Y must be .* the same size> inpolygon (1, [1,2], [3, 4], [5, 6])
--- a/scripts/geometry/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/convhull.m \
   %reldir%/delaunay.m \
   %reldir%/delaunayn.m \
--- a/scripts/geometry/rotx.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/rotx.m	Sun May 16 09:44:35 2021 +0200
@@ -27,8 +27,8 @@
 ## @deftypefn {} {@var{T} =} rotx (@var{angle})
 ##
 ## @code{rotx} returns the 3x3 transformation matrix corresponding to an active
-## rotation of the vector about the x-axis by the specified @var{angle}, given
-## in degrees, where a positive angle corresponds to a counterclockwise
+## rotation of a vector about the x-axis by the specified @var{angle}, given in
+## degrees, where a positive angle corresponds to a counterclockwise
 ## rotation when viewing the y-z plane from the positive x side.
 ##
 ## The form of the transformation matrix is:
@@ -51,7 +51,8 @@
 ## @end ifnottex
 ##
 ## This rotation matrix is intended to be used as a left-multiplying matrix
-## when acting on a column vector, using the notation @var{v} = @var{T}@var{u}.
+## when acting on a column vector, using the notation
+## @code{@var{v} = @var{T}*@var{u}}.
 ## For example, a vector, @var{u}, pointing along the positive y-axis, rotated
 ## 90-degrees about the x-axis, will result in a vector pointing along the
 ## positive z-axis:
@@ -81,28 +82,28 @@
 ## @seealso{roty, rotz}
 ## @end deftypefn
 
-function retmat = rotx (angle_in_deg)
+function T = rotx (angle)
 
-  if ((nargin != 1) || ! isscalar (angle_in_deg))
+  if (nargin < 1 || ! isscalar (angle))
     print_usage ();
   endif
 
-  angle_in_rad = angle_in_deg * pi / 180;
+  angle *= pi / 180;
 
-  s = sin (angle_in_rad);
-  c = cos (angle_in_rad);
+  s = sin (angle);
+  c = cos (angle);
 
-  retmat = [1 0 0; 0 c -s; 0 s c];
+  T = [1 0 0; 0 c -s; 0 s c];
 
 endfunction
 
+
 ## Function output tests
-%!assert (rotx (0), [1 0 0; 0 1 0; 0 0 1]);
-%!assert (rotx (45), [1, 0, 0; [0; 0],[(sqrt(2)/2).*[1 -1; 1 1]]], 1e-12);
-%!assert (rotx (90), [1 0 0; 0 0 -1; 0 1 0], 1e-12);
-%!assert (rotx (180), [1 0 0; 0 -1 0; 0 0 -1], 1e-12);
+%!assert (rotx (0), [1 0 0; 0 1 0; 0 0 1])
+%!assert (rotx (45), [1, 0, 0; [0; 0],[(sqrt(2)/2).*[1 -1; 1 1]]], 1e-12)
+%!assert (rotx (90), [1 0 0; 0 0 -1; 0 1 0], 1e-12)
+%!assert (rotx (180), [1 0 0; 0 -1 0; 0 0 -1], 1e-12)
 
 ## Test input validation
-%!error rotx ()
-%!error rotx (1, 2)
-%!error rotx ([1 2 3])
+%!error <Invalid call> rotx ()
+%!error <Invalid call> rotx ([1 2 3])
--- a/scripts/geometry/roty.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/roty.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,8 @@
 ## @end ifnottex
 ##
 ## This rotation matrix is intended to be used as a left-multiplying matrix
-## when acting on a column vector, using the notation @var{v} = @var{T}@var{u}.
+## when acting on a column vector, using the notation
+## @code{@var{v} = @var{T}*@var{u}}.
 ## For example, a vector, @var{u}, pointing along the positive z-axis, rotated
 ## 90-degrees about the y-axis, will result in a vector pointing along the
 ## positive x-axis:
@@ -81,28 +82,28 @@
 ## @seealso{rotx, rotz}
 ## @end deftypefn
 
-function retmat = roty (angle_in_deg)
+function T = roty (angle)
 
-  if ((nargin != 1) || ! isscalar (angle_in_deg))
+  if (nargin < 1 || ! isscalar (angle))
     print_usage ();
   endif
 
-  angle_in_rad = angle_in_deg * pi / 180;
+  angle *= pi / 180;
 
-  s = sin (angle_in_rad);
-  c = cos (angle_in_rad);
+  s = sin (angle);
+  c = cos (angle);
 
-  retmat = [c 0 s; 0 1 0; -s 0 c];
+  T = [c 0 s; 0 1 0; -s 0 c];
 
 endfunction
 
+
 ## Function output tests
-%!assert (roty (0), [1 0 0; 0 1 0; 0 0 1]);
-%!assert (roty (45), [sqrt(2) 0 sqrt(2); 0 2 0; -sqrt(2) 0 sqrt(2)]./2, 1e-12);
-%!assert (roty (90), [0 0 1; 0 1 0; -1 0 0], 1e-12);
-%!assert (roty (180), [-1 0 0; 0 1 0; 0 0 -1], 1e-12);
+%!assert (roty (0), [1 0 0; 0 1 0; 0 0 1])
+%!assert (roty (45), [sqrt(2) 0 sqrt(2); 0 2 0; -sqrt(2) 0 sqrt(2)]./2, 1e-12)
+%!assert (roty (90), [0 0 1; 0 1 0; -1 0 0], 1e-12)
+%!assert (roty (180), [-1 0 0; 0 1 0; 0 0 -1], 1e-12)
 
 ## Test input validation
-%!error roty ()
-%!error roty (1, 2)
-%!error roty ([1 2 3])
+%!error <Invalid call> roty ()
+%!error <Invalid call> roty ([1 2 3])
--- a/scripts/geometry/rotz.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/rotz.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,8 @@
 ## @end ifnottex
 ##
 ## This rotation matrix is intended to be used as a left-multiplying matrix
-## when acting on a column vector, using the notation @var{v} = @var{T}@var{u}.
+## when acting on a column vector, using the notation
+## @code{@var{v} = @var{T}*@var{u}}.
 ## For example, a vector, @var{u}, pointing along the positive x-axis, rotated
 ## 90-degrees about the z-axis, will result in a vector pointing along the
 ## positive y-axis:
@@ -81,28 +82,28 @@
 ## @seealso{rotx, roty}
 ## @end deftypefn
 
-function retmat = rotz (angle_in_deg)
+function T = rotz (angle)
 
-  if ((nargin != 1) || ! isscalar (angle_in_deg))
+  if (nargin < 1 || ! isscalar (angle))
     print_usage ();
   endif
 
-  angle_in_rad = angle_in_deg * pi / 180;
+  angle = angle * pi / 180;
 
-  s = sin (angle_in_rad);
-  c = cos (angle_in_rad);
+  s = sin (angle);
+  c = cos (angle);
 
-  retmat = [c -s 0; s c 0; 0 0 1];
+  T = [c -s 0; s c 0; 0 0 1];
 
 endfunction
 
+
 ## Function output tests
-%!assert (rotz (0), [1 0 0; 0 1 0; 0 0 1]);
-%!assert (rotz (45), [(sqrt(2)/2).*[1 -1; 1 1] ,[0; 0]; 0, 0, 1], 1e-12);
-%!assert (rotz (90), [0 -1 0; 1 0 0; 0 0 1], 1e-12);
-%!assert (rotz (180), [-1 0 0; 0 -1 0; 0 0 1], 1e-12);
+%!assert (rotz (0), [1 0 0; 0 1 0; 0 0 1])
+%!assert (rotz (45), [(sqrt(2)/2).*[1 -1; 1 1] ,[0; 0]; 0, 0, 1], 1e-12)
+%!assert (rotz (90), [0 -1 0; 1 0 0; 0 0 1], 1e-12)
+%!assert (rotz (180), [-1 0 0; 0 -1 0; 0 0 1], 1e-12)
 
 ## Test input validation
-%!error rotz ()
-%!error rotz (1, 2)
-%!error rotz ([1 2 3])
+%!error <Invalid call> rotz ()
+%!error <Invalid call> rotz ([1 2 3])
--- a/scripts/geometry/voronoi.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/voronoi.m	Sun May 16 09:44:35 2021 +0200
@@ -224,7 +224,7 @@
 
 
 ## Input validation tests
-%!error voronoi ()
+%!error <Invalid call> voronoi ()
 %!error voronoi (ones (3,1))
 %!error voronoi (ones (3,1), ones (3,1), "invalid1", "invalid2", "invalid3")
 %!error <HAX argument must be an axes object> voronoi (0, ones (3,1), ones (3,1))
--- a/scripts/geometry/voronoin.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/geometry/voronoin.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
 
 function [C, F] = voronoin (pts, options)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -80,6 +80,5 @@
 
 ## FIXME: Need functional tests
 
-%!error voronoin ()
-%!error voronoin (1,2,3)
+%!error <Invalid call> voronoin ()
 %!error <number of points must be greater than their dimension> voronoin ([1 2])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gui/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/gui/errordlg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/errordlg.m	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,7 @@
 ## ("\n"), or it may be a cellstr array with one element for each line.
 ##
 ## The third optional argument @var{opt} controls the behavior of the dialog.
-## See @code{msgbox} for details.
+## For details, @pxref{XREFmsgbox,,@code{msgbox}}.
 ##
 ## The return value @var{h} is a handle to the figure object used for
 ## building the dialog.
--- a/scripts/gui/getappdata.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/getappdata.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 
 function value = getappdata (h, name)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -90,8 +90,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error getappdata ()
-%!error getappdata (1,2,3)
+%!error <Invalid call> getappdata ()
 %!error <H must be a scalar .* graphic handle> getappdata (-1, "hello")
 %!error <NAME must be a string> getappdata (0, 1)
 %!error <Only one handle H may be used when fetching appdata> getappdata ([0 0])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gui/getpixelposition.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,126 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{pos} =} getpixelposition (@var{h})
+## @deftypefnx {} {@var{pos} =} getpixelposition (@var{h}, @var{rel_to_fig})
+## Return the position of a user interface component in pixel units.
+##
+## The first argument @var{h} must be a handle to a valid graphics object of
+## type uibuttongroup, uicontrol, uipanel, uitable, axes, or figure.  For other
+## object types, the function returns zeros.
+##
+## By default, the position is returned relative to the object's parent.
+## If the second argument @var{rel_to_fig} is logically true, the position
+## is computed relative to the enclosing figure object.
+##
+## The return value @var{pos} is a 4-element vector with values
+## @code{[ lower_left_X, lower_left_Y, width, height ]}.
+##
+## @seealso{get}
+## @end deftypefn
+
+function pos = getpixelposition (h, rel_to_fig = false)
+
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (! isscalar (h) || ! ishghandle (h))
+    error ("getpixelposition: H must be a scalar graphics handle");
+  endif
+
+  if (! any (strcmp (get (h, "type"), {"uibuttongroup", "uicontrol", ...
+                                       "uitable", "uipanel", ...
+                                       "axes", "figure"})))
+    pos = zeros (1, 4);
+    return;
+  endif
+
+  pos = __get_position__ (h, "pixels");
+
+  if (rel_to_fig)
+    while (! isfigure (h))
+      h = get (h, "parent");
+      pos(1:2) += __get_position__ (h, "pixels")(1:2);
+    endwhile
+  endif
+
+endfunction
+
+
+%!demo
+%! clf ();
+%! hax = axes ("position", [0.25 0.25 0.5 0.5])
+%! pos = getpixelposition (hax);
+%! han = annotation ("rectangle");
+%! set (han, "units", "pixels", "position", pos, "color", "r")
+
+%!demo
+%! hf = clf ();
+%! hbg = uibuttongroup (hf, "position", [0.2 0.7 0.2 0.2]);
+%! hb1 = uicontrol (hbg, "style", "radiobutton", ...
+%!                       "string", "Choice 1", ...
+%!                       "units", "normalized", ...
+%!                       "position", [0.01 0.5 0.98 0.5]);
+%! hb2 = uicontrol (hbg, "style", "radiobutton", ...
+%!                       "string", "Choice 2", ...
+%!                       "units", "normalized", ...
+%!                       "position", [0.01 0 0.98 0.5]);
+%! pos = getpixelposition (hbg);
+%! han = annotation ("rectangle");
+%! set (han, "units", "pixels", "position", pos, "color", "r")
+
+
+%!test
+%! pos = [0 0 400 400];
+%! hf = figure ("visible", "off", "menubar", "none", "position", pos);
+%! unwind_protect
+%!   hp = uipanel (hf, "position", [0.5 0.5 0.5 0.5]);
+%!   hax = axes (hp, "position", [0.5 0.5 0.5 0.5]);
+%!   assert (getpixelposition (hax), [100 100 100 100], 2);
+%!   assert (getpixelposition (hax, true), [300 300 100 100], 2);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+%!test
+%! ## Compatibility: return zeros for root figure
+%! assert (getpixelposition (groot), zeros (1, 4));
+
+%!test
+%! ## Compatibility: return the same for figures regardless of rel_to_fig
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   assert (getpixelposition (hf), getpixelposition (hf, true));
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <Invalid call> getpixelposition ()
+%!error <H must be a scalar> getpixelposition ([1, 2])
+%!error <H must be a .* graphics handle> getpixelposition (-1)
+
--- a/scripts/gui/guidata.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/guidata.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function dataout = guidata (h, data)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -65,7 +65,6 @@
 
 
 ## Test input validation
-%!error guidata ()
-%!error guidata (1,2,3)
+%!error <Invalid call> guidata ()
 %!error <H must be a valid object handle> guidata ({1})
 %!error <no ancestor figure of H found> guidata (0)
--- a/scripts/gui/guihandles.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/guihandles.m	Sun May 16 09:44:35 2021 +0200
@@ -42,10 +42,6 @@
 
 function hdata = guihandles (h)
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (nargin == 1)
     if (! ishghandle (h))
       error ("guidata: H must be a valid object handle");
--- a/scripts/gui/isappdata.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/isappdata.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function valid = isappdata (h, name)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -66,7 +66,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error isappdata ()
-%!error isappdata (1,2,3)
+%!error <Invalid call> isappdata ()
 %!error <H must be a scalar .* graphic handle> isappdata (-1, "hello")
 %!error <NAME must be a string> isappdata (0, 1)
--- a/scripts/gui/listdlg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/listdlg.m	Sun May 16 09:44:35 2021 +0200
@@ -200,7 +200,8 @@
 %! endfor
 
 ## Test input validation
-%!error listdlg ()
+%!error <Invalid call> listdlg ()
+%!error <Invalid call> listdlg (1)
 %!error listdlg ("SelectionMode")
 %!error <must occur in pairs> listdlg ("SelectionMode", "multiple", "Name")
 %!error <invalid KEY .FooBar.> listdlg ("FooBar", 1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/gui/listfonts.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,74 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {fonts =} listfonts ()
+## @deftypefnx {} {fonts =} listfonts (@var{h})
+## List system fonts.
+##
+## If a handle to a graphics object @var{h} is provided, also include the
+## font from the object's @qcode{"FontName"} property in the list.
+##
+## Programming Note: On systems that don't use FontConfig natively (all but
+## Linux), the font cache is built when Octave is installed.  You will need to
+## run @code{system ("fc-cache -fv")} manually after installing new fonts.
+##
+## @seealso{uisetfont, text, axes, uicontrol}
+## @end deftypefn
+
+function fonts = listfonts (h)
+
+  if (nargin == 1 && (! ishghandle (h) || ! isprop (h, "fontname")))
+    error (['listfonts: H must be a handle to a graphics object ', ...
+            'with a "fontname" property']);
+  endif
+
+  persistent sysfonts = get_fonts ();
+  fonts = sysfonts;
+
+  if (nargin == 1 && ! isempty (h))
+    font = get (h, "fontname");
+    if (! strcmp (font, "*"))
+      fonts = unique ([fonts font]);
+    endif
+  endif
+
+endfunction
+
+function fonts = get_fonts ()
+
+  fontfiles = __get_system_fonts__ ();
+
+  fonts = unique ({fontfiles.family, "FreeSans"});
+
+endfunction
+
+
+## Test input validation
+%!error listfonts (0, 0)
+%!error <H must be a handle to a graphics object with a "fontname" property>
+%! s = listfonts (0);
+%!error <H must be a handle to a graphics object>
+%! s = listfonts (struct ());
--- a/scripts/gui/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -14,14 +14,17 @@
   %reldir%/private/__uiputfile_fltk__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/dialog.m \
   %reldir%/errordlg.m \
   %reldir%/getappdata.m \
+  %reldir%/getpixelposition.m \
   %reldir%/guidata.m \
   %reldir%/guihandles.m \
   %reldir%/helpdlg.m \
   %reldir%/inputdlg.m \
   %reldir%/isappdata.m \
+  %reldir%/listfonts.m \
   %reldir%/listdlg.m \
   %reldir%/movegui.m \
   %reldir%/msgbox.m \
--- a/scripts/gui/movegui.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/movegui.m	Sun May 16 09:44:35 2021 +0200
@@ -185,8 +185,8 @@
         if (fpos(2) > y(3))
           fpos(2) = y(3) - 30;
         endif
-        fpos(1) = max(fpos(1), 30);
-        fpos(2) = max(fpos(2), 30);
+        fpos(1) = max (fpos(1), 30);
+        fpos(2) = max (fpos(2), 30);
       otherwise
         error ("movegui: invalid position");
     endswitch
--- a/scripts/gui/msgbox.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/msgbox.m	Sun May 16 09:44:35 2021 +0200
@@ -359,7 +359,7 @@
 %!         "Dialog Title", "custom", cdata, copper (64));
 
 ## Test input validation
-%!error msgbox ()
+%!error <Invalid call> msgbox ()
 %!error <MSG must be a string or cell array of strings> msgbox (1)
 %!error <invalid value "foobar" for WindowStyle>
 %! msgbox ("msg", struct ("WindowStyle", "foobar"))
--- a/scripts/gui/private/__file_filter__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/private/__file_filter__.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,6 @@
 
 function [retval, defname, defdir] = __file_filter__ (caller, file_filter)
 
-  #keyboard;
   retval = {};
   defname = "";
   defdir = "";
--- a/scripts/gui/private/__ok_cancel_dlg__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/private/__ok_cancel_dlg__.m	Sun May 16 09:44:35 2021 +0200
@@ -24,14 +24,14 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {[@var{hf}, @var{hok}, @var{hcancel}] =} __ok_cancel_dlg__ (@var{title})
+## @deftypefn {} {[@var{hf}, @var{hok}, @var{hcancel}] =} __ok_cancel_dlg__ (@var{dlg_title})
 ## Undocumented internal function.
 ## @seealso{}
 ## @end deftypefn
 
-function [hf, hok, hcancel, hpanel] = __ok_cancel_dlg__ (ttl, varargin)
+function [hf, hok, hcancel, hpanel] = __ok_cancel_dlg__ (dlg_title, varargin)
 
-  hf = dialog ("name", ttl, varargin{:});
+  hf = dialog ("name", dlg_title, varargin{:});
   setappdata (hf, "__ok_cancel_btn__", "cancel");
 
   hpanel = uipanel (hf, "units", "pixels", "bordertype", "none");
@@ -46,6 +46,7 @@
 endfunction
 
 function  cb_fix_button_position (hf, evt, hcancel, hok, hpanel)
+
   persistent margin = 20;
   persistent hgt = 30;
   persistent wd = 70;
@@ -62,4 +63,5 @@
   unwind_protect_cleanup
     set (hf, "units", units);
   end_unwind_protect
+
 endfunction
--- a/scripts/gui/private/__uiobject_split_args__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/private/__uiobject_split_args__.m	Sun May 16 09:44:35 2021 +0200
@@ -39,20 +39,20 @@
       parent = in_args{1};
       offset = 2;
     elseif (! ischar (in_args{1}) && ! isstruct (in_args{1}))
-      error ("%s: invalid parent handle.", who);
+      error ("%s: invalid parent handle", who);
     endif
 
     args = in_args(offset:end);
   endif
 
   if (! isempty (args))
-    i = find (strcmpi (args, "parent"), 1, "first");
-    if (! isempty (i) && numel (args) > i)
-      parent = args{i+1};
+    i = find (strcmpi (args(1:2:end), "parent"), 1, "first");
+    if (! isempty (i) && numel (args) >= 2*i)
+      parent = args{2*i};
       if (! ishghandle (parent))
-        error ("%s: invalid parent handle.", who);
+        error ("%s: invalid parent handle", who);
       endif
-      args(i:i+1) = [];
+      args((2*i-1):2*i) = [];
     endif
   endif
 
--- a/scripts/gui/questdlg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/questdlg.m	Sun May 16 09:44:35 2021 +0200
@@ -186,8 +186,8 @@
 %! endif
 
 ## Test input validation
-%!error questdlg ()
-%!error questdlg (1,2,3,4,5,6,7)
+%!error <Invalid call> questdlg ()
+%!error <Invalid call> questdlg (1,2,3,4,5,6,7)
 %!error <MSG must be a character string or cellstr array> questdlg (1)
 %!error <TITLE must be a character string> questdlg ("msg", 1)
 %!error <DEFAULT must match one of the button> questdlg ("msg", "title", "ABC")
--- a/scripts/gui/rmappdata.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/rmappdata.m	Sun May 16 09:44:35 2021 +0200
@@ -78,8 +78,8 @@
 %! assert (isappdata (0, "%data2%"), false);
 
 ## Test input validation
-%!error rmappdata ()
-%!error rmappdata (1)
+%!error <Invalid call> rmappdata ()
+%!error <Invalid call> rmappdata (1)
 %!error <H must be a scalar .* graphic handle> rmappdata (-1, "hello")
 %!error <NAME must be a string> rmappdata (0, 1)
 %!error <appdata 'foobar' is not present> rmappdata (0, "foobar")
--- a/scripts/gui/setappdata.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/setappdata.m	Sun May 16 09:44:35 2021 +0200
@@ -127,9 +127,9 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error setappdata ()
-%!error setappdata (0)
-%!error setappdata (0, "name")
+%!error <Invalid call> setappdata ()
+%!error <Invalid call> setappdata (0)
+%!error <Invalid call> setappdata (0, "name")
 %!error <H must be a scalar .* graphic handle> setappdata (-1, "foo", "bar")
 %!error <NAME/VALUE arguments must occur in pairs> setappdata (0, "1", 2, "3")
 %!error <only 3 arguments possible> setappdata (0, {"1"}, 2, "3", 4)
--- a/scripts/gui/uicontrol.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/uicontrol.m	Sun May 16 09:44:35 2021 +0200
@@ -119,6 +119,16 @@
 
   [h, args] = __uiobject_split_args__ ("uicontrol", varargin,
                                        {"figure", "uipanel", "uibuttongroup"});
+
+  ## Validate style
+  idx = find (strcmpi (args(1:2:end), "style"), 1, "last");
+  if (! isempty (idx) && 2*idx <= numel (args))
+    if (strcmpi (args{2*idx}, "frame"))
+      warning ("Octave:unimplemented-matlab-functionality",
+               'uicontrol: "frame" style is not implemented.  Use uipanel() or uibuttongroup() instead');
+    endif
+  endif
+
   htmp = __go_uicontrol__ (h, args{:});
 
   if (nargout > 0)
@@ -126,3 +136,12 @@
   endif
 
 endfunction
+
+
+%!warning <"frame" style is not implemented>
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   h = uicontrol (hf, "string", "Hello World", "Style", "frame");
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
--- a/scripts/gui/uigetdir.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/uigetdir.m	Sun May 16 09:44:35 2021 +0200
@@ -41,10 +41,6 @@
 
 function dirname = uigetdir (init_path = pwd, dialog_name = "Select Directory to Open")
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (! ischar (init_path) || ! ischar (dialog_name))
     error ("uigetdir: INIT_PATH and DIALOG_NAME must be string arguments");
   endif
--- a/scripts/gui/uisetfont.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/uisetfont.m	Sun May 16 09:44:35 2021 +0200
@@ -38,14 +38,18 @@
 ## @code{FontWeight}, @code{FontAngle}, @code{FontUnits}, and @code{FontSize},
 ## indicating the initially selected font.
 ##
-## The title of the dialog window can be changed using the last argument
+## The title of the dialog window can be specified by using the last argument
 ## @var{title}.
 ##
 ## If an output argument @var{fontstruct} is requested, the selected font
 ## structure is returned.  Otherwise, the font information is displayed
 ## onscreen.
 ##
-## @seealso{text, axes, uicontrol}
+## Programming Note: On systems that don't use FontConfig natively (all but
+## Linux), the font cache is built when Octave is installed.  You will need to
+## run @code{system ("fc-cache -fv")} manually after installing new fonts.
+##
+## @seealso{listfonts, text, axes, uicontrol}
 ## @end deftypefn
 
 function varargout = uisetfont (varargin)
@@ -71,7 +75,7 @@
     typ = get (h, "type");
     if (! any (strcmp (typ, {"axes", "text", "uicontrol"})))
       error ("Octave:uisetfont:bad-object",
-             'uisetfont: unhandled object type "%s"', typ);
+             "uisetfont: H must be a handle to an axes, text, or uicontrol object");
     endif
     nargin--;
     varargin(1) = [];
@@ -333,7 +337,7 @@
 
 endfunction
 
-function cb_button (h, evt, hlists, role)
+function cb_button (h, ~, hlists, role)
 
   fontstruct = [];
   if (strcmp (role, "ok"))
@@ -345,7 +349,7 @@
 
 endfunction
 
-function cb_list_value_changed (h, evt, hlists, htext, sysfonts)
+function cb_list_value_changed (h, ~, hlists, htext, sysfonts)
 
   if (h == hlists(1))
     set (hlists(2), "string", getstylestring (sysfonts(get (h, "value"))),
@@ -363,7 +367,7 @@
 %!testif HAVE_FONTCONFIG
 %! fail ("uisetfont (110, struct ())", "Invalid call");
 %!testif HAVE_FONTCONFIG
-%! fail ("uisetfont (groot ())", "unhandled object type");
+%! fail ("uisetfont (groot ())", "H must be a handle to an axes");
 %!testif HAVE_FONTCONFIG
 %! fail ("uisetfont (struct ())", "FONTSTRUCT .* must have fields FontName,.*");
 %!testif HAVE_FONTCONFIG
--- a/scripts/gui/waitforbuttonpress.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/waitforbuttonpress.m	Sun May 16 09:44:35 2021 +0200
@@ -39,10 +39,6 @@
 
 function b = waitforbuttonpress ()
 
-  if (nargin != 0 || nargout > 1)
-    print_usage ();
-  endif
-
   [x, y, k] = ginput (1);
 
   if (nargout == 1)
@@ -54,8 +50,3 @@
   endif
 
 endfunction
-
-
-## Test input validation
-%!error waitforbuttonpress (1)
-%!error [a,b,c] = waitforbuttonpress ()
--- a/scripts/gui/warndlg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/gui/warndlg.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 ## ("\n"), or it may be a cellstr array with one element for each line.
 ##
 ## The third optional argument @var{opt} controls the behavior of the dialog.
-## See @code{msgbox} for details.
+## For details, @pxref{XREFmsgbox,,@code{msgbox}}.
 ##
 ## The return value @var{h} is a handle to the figure object used for
 ## building the dialog.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/help/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/help/__gripe_missing_component__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/__gripe_missing_component__.m	Sun May 16 09:44:35 2021 +0200
@@ -62,14 +62,13 @@
 endfunction
 
 
-## WARNING: Tests cannot rely on the exact error strings shown above because we
-##          specifically allow these messages to be overridden by
-##          missing_component_hook.  The prefix is all we can be sure of.
+## NOTE: Tests cannot rely on the exact error strings shown above because we
+##       specifically allow these messages to be overridden by
+##       missing_component_hook.  The prefix is all we can be sure of.
 %!error <abc: .*> __gripe_missing_component__ ("abc", "info-file")
 %!error <abc: .*> __gripe_missing_component__ ("abc", "octave")
 %!error <abc: .*> __gripe_missing_component__ ("abc", "octave-config")
 %!error <abc: .*> __gripe_missing_component__ ("abc", "xyz")
 
-%!error __gripe_missing_component__ ()
-%!error __gripe_missing_component__ ("fcn")
-%!error __gripe_missing_component__ ("fcn", 1 , 2)
+%!error <Invalid call> __gripe_missing_component__ ()
+%!error <Invalid call> __gripe_missing_component__ ("fcn")
--- a/scripts/help/__makeinfo__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/__makeinfo__.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 function [retval, status] = __makeinfo__ (text, output_type = "plain text", fsee_also)
 
   ## Check input
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -161,8 +161,8 @@
       ## original return value usually more useful
       if (status_force)
         status = status_force;
-      end
-    end
+      endif
+    endif
 
     ## Clean up extra newlines generated by makeinfo
     if (strcmpi (output_type, "plain text"))
--- a/scripts/help/__unimplemented__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/__unimplemented__.m	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,7 @@
 
 function txt = __unimplemented__ (fcn)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -561,7 +561,7 @@
           txt = sprintf (["'%s' is a method of class '%s'; it must be ", ...
                           "called with a '%s' argument (see 'help @@%s/%s')."],
                          fcn, cls, cls, cls, fcn);
-          return
+          return;
         endif
       endfor
       txt = sprintf ("%s but has not yet been implemented.", txt);
@@ -736,7 +736,6 @@
   "edges",
   "empty",
   "enableservice",
-  "endsWith",
   "enumeration",
   "eraseBetween",
   "eventlisteners",
@@ -759,7 +758,6 @@
   "filemarker",
   "fileMode",
   "fileName",
-  "fill3",
   "fillmissing",
   "filloutliers",
   "fimplicit",
@@ -813,7 +811,6 @@
   "getNumOutputs",
   "getNumRows",
   "getOpenFiles",
-  "getpixelposition",
   "getpoints",
   "getProfiles",
   "getqualitydesc",
@@ -959,8 +956,6 @@
   "javaMethodEDT",
   "javaObjectEDT",
   "join",
-  "jsondecode",
-  "jsonencode",
   "juliandate",
   "labeledge",
   "labelnode",
@@ -975,7 +970,6 @@
   "libpointer",
   "libstruct",
   "linkdata",
-  "listfonts",
   "loadlibrary",
   "lsqminnorm",
   "lsqr",
@@ -990,15 +984,11 @@
   "memmapfile",
   "memoize",
   "MemoizedFunction",
-  "memory",
   "mergecats",
   "meta.abstractDetails",
-  "meta.class.fromName",
   "meta.DynamicProperty",
   "meta.EnumeratedValue",
   "meta.MetaData",
-  "meta.package.fromName",
-  "meta.package.getAllPackages",
   "methodsview",
   "MException",
   "milliseconds",
@@ -1053,7 +1043,6 @@
   "odextend",
   "openFile",
   "opengl",
-  "ordqz",
   "outdegree",
   "outerjoin",
   "pad",
@@ -1086,7 +1075,6 @@
   "printpreview",
   "profsave",
   "propedit",
-  "properties",
   "propertyeditor",
   "PutCharArray",
   "PutFullMatrix",
@@ -1129,10 +1117,8 @@
   "replace",
   "replaceBetween",
   "resample",
-  "rescale",
   "retime",
   "reverse",
-  "rgb2gray",
   "rlim",
   "rmboundary",
   "rmedge",
@@ -1140,7 +1126,6 @@
   "rmmissing",
   "rmnode",
   "rmslivers",
-  "rng",
   "rowfun",
   "rtickangle",
   "rtickformat",
@@ -1165,7 +1150,6 @@
   "setHCompSmooth",
   "setinterpmethod",
   "setpixelposition",
-  "setstr",
   "setTileDim",
   "settimeseriesnames",
   "setTscale",
@@ -1193,13 +1177,11 @@
   "ss2tf",
   "stack",
   "standardizeMissing",
-  "startsWith",
   "stats",
   "step",
   "stopasync",
   "str2mat",
   "streamparticles",
-  "streamribbon",
   "streamslice",
   "string",
   "strings",
@@ -1336,20 +1318,18 @@
   "xmlread",
   "xmlwrite",
   "xslt",
-  "xtickangle",
   "xtickformat",
   "year",
   "years",
   "ymd",
-  "ytickangle",
   "ytickformat",
   "yyaxis",
   "yyyymmdd",
-  "ztickangle",
   "ztickformat",
   };
 
   rlist = list;
+
 endfunction
 
 
--- a/scripts/help/bessel.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/bessel.m	Sun May 16 09:44:35 2021 +0200
@@ -101,4 +101,4 @@
 endfunction
 
 
-%!error bessel ()
+%!error <you must use besselj, ...> bessel ()
--- a/scripts/help/doc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/doc.m	Sun May 16 09:44:35 2021 +0200
@@ -41,10 +41,6 @@
 
 function retval = doc (function_name)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 1)
     if (! ischar (function_name))
       error ("doc: FUNCTION_NAME must be a string");
@@ -55,10 +51,12 @@
     ftype = 0;
   endif
 
-  ## if GUI is running, let it display the function
-  if (isguirunning ())
-    status = ! __event_manager_show_doc__ (function_name);
-  else
+  ## Give event manager the first shot.
+
+  status = ! __event_manager_show_documentation__ (function_name);
+
+  if (status)
+
     if (ftype == 2 || ftype == 3)
       ffile = which (function_name);
     else
--- a/scripts/help/get_first_help_sentence.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/get_first_help_sentence.m	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
 
 function [text, status] = get_first_help_sentence (name, max_len = 80)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -109,7 +109,9 @@
       text = help_text(1:max_len);
     endif
   endif
+
   status = 0;
+
 endfunction
 
 ## This function extracts the first sentence from a Texinfo help text.
@@ -182,8 +184,7 @@
 %!        "Return the first sentence...")
 
 ## Test input validation
-%!error get_first_help_sentence ()
-%!error get_first_help_sentence (1, 2, 3)
+%!error <Invalid call> get_first_help_sentence ()
 %!error <NAME must be a string> get_first_help_sentence (1)
 %!error <MAX_LEN must be positive integer> get_first_help_sentence ("ls", "a")
 %!error <MAX_LEN must be positive integer> get_first_help_sentence ("ls", 0)
--- a/scripts/help/help.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/help.m	Sun May 16 09:44:35 2021 +0200
@@ -224,5 +224,5 @@
 
 ## Test input validation
 %!error <invalid input> help (42)
-%!error <invalid input> help ("abc", "def")
+%!error <called with too many inputs> help ("abc", "def")
 %!error <'_! UNLIKELY_FCN! _' not found> help ("_! UNLIKELY_FCN! _")
--- a/scripts/help/lookfor.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/lookfor.m	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,8 @@
 ## related functions that are not a part of Octave.
 ##
 ## The speed of lookup is greatly enhanced by having a cached documentation
-## file.  See @code{doc_cache_create} for more information.
+## file.  For more information,
+## @pxref{XREFdoc_cache_create,,@code{doc_cache_create}}.
 ## @seealso{help, doc, which, path, doc_cache_create}
 ## @end deftypefn
 
--- a/scripts/help/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -7,6 +7,7 @@
   %reldir%/private/__strip_html_tags__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__gripe_missing_component__.m \
   %reldir%/__makeinfo__.m \
   %reldir%/__unimplemented__.m \
--- a/scripts/help/print_usage.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/print_usage.m	Sun May 16 09:44:35 2021 +0200
@@ -45,7 +45,7 @@
       error ("Octave:invalid-context", "print_usage: invalid function\n");
     endif
     fullname = evalin ("caller", 'mfilename ("fullpath")');
-    if (strcmp (fullname(end-length(name)+1:end), name))
+    if (strcmp (fullname(end-length (name)+1:end), name))
       fullname = [fullname ".m"];
     endif
   elseif (! ischar (name))
--- a/scripts/help/private/__strip_html_tags__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/private/__strip_html_tags__.m	Sun May 16 09:44:35 2021 +0200
@@ -37,7 +37,7 @@
   stop  = find (html_text == ">");
   if (length (start) == length (stop))
     text = html_text;
-    for n = length(start):-1:1
+    for n = length (start):-1:1
       text (start (n):stop (n)) = [];
     endfor
     text = strip_superfluous_endlines (text);
--- a/scripts/help/slash.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/slash.m	Sun May 16 09:44:35 2021 +0200
@@ -61,10 +61,10 @@
 ##
 ## For dense matrices, backslash uses the Gaussian Elimination algorithm
 ## with partial pivoting.  For sparse matrices, backslash uses a direct
-## method to compute an LU factorization (@pxref{XREFlu,,lu}).  The direct
-## method tries to minimize ``fill-in'' of zeros but it could nonetheless use a
-## lot of memory; if this is a concern, consider an iterative method
-## (@pxref{XREFcgs,,cgs} or @pxref{XREFgmres,,gmres}).
+## method to compute an LU factorization (@pxref{XREFlu,,@code{lu}}).  The
+## direct method tries to minimize ``fill-in'' of zeros but it could
+## nonetheless use a lot of memory; if this is a concern, consider an iterative
+## method (@pxref{XREFcgs,,@code{cgs}} or @pxref{XREFgmres,,@code{gmres}}).
 ##
 ## @item @code{/} Matrix Right Division
 ## The forward slash notation can be used to solve systems of the form
--- a/scripts/help/type.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/type.m	Sun May 16 09:44:35 2021 +0200
@@ -155,5 +155,5 @@
 %!assert (type ("+"){1}, "+ is an operator")
 %!assert (type ("end"){1}, "end is a keyword")
 
-%!error type ()
+%!error <Invalid call> type ()
 %!error <'__NO_NAME__' undefined> type ('__NO_NAME__')
--- a/scripts/help/warning_ids.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/warning_ids.m	Sun May 16 09:44:35 2021 +0200
@@ -139,6 +139,13 @@
 ## By default, the @code{Octave:built-in-variable-assignment} warning is
 ## enabled.
 ##
+## @item Octave:charmat-truncated
+## If the @code{Octave:charmat-truncated} warning is enabled, a warning is
+## printed when a character matrix with multiple rows is converted to a string.
+## In this case, the Octave interpreter keeps only the first row and discards
+## the others.
+## By default, the @code{Octave:charmat-truncated} warning is enabled.
+##
 ## @item Octave:classdef-to-struct
 ## If the @code{Octave:classdef-to-struct} warning is enabled, a warning
 ## is issued when a classdef object is forcibly converted into a struct with
@@ -230,6 +237,12 @@
 ## printed for implicit conversions of complex numbers to real numbers.
 ## By default, the @code{Octave:imag-to-real} warning is disabled.
 ##
+## @item Octave:infinite-loop
+## If the @code{Octave:infinite-loop} warning is enabled, a warning is
+## printed when an infinite loop is detected such as @code{for i = 1:Inf} or
+## @code{while (1)}.
+## By default, the @code{Octave:infinite-loop} warning is enabled.
+##
 ## @item Octave:language-extension
 ## Print warnings when using features that are unique to the Octave
 ## language and that may still be missing in @sc{matlab}.
@@ -384,6 +397,14 @@
 ## the warning message is printed just once per Octave session.
 ## By default, the @code{Octave:glyph-render} warning is enabled.
 ##
+## @item Octave:unimplemented-matlab-functionality
+## If the @code{Octave:unimplemented-matlab-functionality} warning is enabled,
+## a warning is printed when a @sc{matlab} code construct is used which the
+## Octave interpreter parses as valid, but for which Octave does not yet
+## implement the functionality.
+## By default, the @code{Octave:unimplemented-matlab-functionality} warning is
+## enabled.
+##
 ## @item Octave:variable-switch-label
 ## If the @code{Octave:variable-switch-label} warning is enabled, Octave
 ## will print a warning if a switch label is not a constant or constant
--- a/scripts/help/which.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/help/which.m	Sun May 16 09:44:35 2021 +0200
@@ -113,6 +113,6 @@
 %! str = which ("fftw");
 %! assert (str(end-7:end), "fftw.oct");
 
-%!error which ()
-%!error which (1)
+%!error <Invalid call> which ()
+%!error <Invalid call> which (1)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/image/autumn.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/autumn.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 
 function map = autumn (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("autumn: N must be a scalar");
     endif
--- a/scripts/image/bone.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/bone.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 
 function map = bone (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("bone: N must be a scalar");
     endif
--- a/scripts/image/brighten.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/brighten.m	Sun May 16 09:44:35 2021 +0200
@@ -46,7 +46,7 @@
 
 function rmap = brighten (arg1, beta)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/image/cmpermute.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/cmpermute.m	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,7 @@
 
 function [Y, newmap] = cmpermute (X, map, index)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -131,8 +131,8 @@
 %! assert (X, max (Y(:)) + 1 - Y);
 
 ## Test input validation
-%!error cmpermute ()
-%!error cmpermute (1,2,3,4)
+%!error <Invalid call> cmpermute ()
+%!error <Invalid call> cmpermute (1)
 %!error <invalid data type 'uint32'> cmpermute (uint32 (magic (16)), jet (256))
 %!error <X must be an indexed image> cmpermute (1+i, jet (256))
 %!error <X must be an indexed image> cmpermute (sparse (1), jet (256))
--- a/scripts/image/cmunique.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/cmunique.m	Sun May 16 09:44:35 2021 +0200
@@ -60,7 +60,7 @@
 
 function [Y, newmap] = cmunique (X, map)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -193,8 +193,7 @@
 %! assert (Id, newmap(:,3)(Y+1));
 
 ## Test input validation
-%!error cmpermute ()
-%!error cmpermute (1,2,3)
+%!error <Invalid call> cmunique ()
 %!error <X is of invalid data type> cmunique (uint32 (magic (16)))
 %!error <MAP must be a valid colormap> cmunique (1, "a")
 %!error <MAP must be a valid colormap> cmunique (1, i)
--- a/scripts/image/colorcube.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/colorcube.m	Sun May 16 09:44:35 2021 +0200
@@ -42,12 +42,8 @@
 
   if (nargin == 0)
     n = rows (colormap);
-  elseif (nargin == 1)
-    if (! isscalar (n))
-      error ("colorcube: N must be a scalar");
-    endif
-  else
-    print_usage ();
+  elseif (! isscalar (n))
+    error ("colorcube: N must be a scalar");
   endif
 
   if (n < 9)
--- a/scripts/image/colormap.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/colormap.m	Sun May 16 09:44:35 2021 +0200
@@ -58,6 +58,7 @@
 ## @multitable @columnfractions 0.15 .85
 ## @headitem Map @tab Description
 ## @item viridis @tab default
+## @item turbo @tab colormap traversing blue, cyan, green, yellow, red; modern replacement for jet.
 ## @item jet @tab colormap traversing blue, cyan, green, yellow, red.
 ## @item cubehelix @tab colormap traversing black, blue, green, red, white with increasing intensity.
 ## @item hsv @tab cyclic colormap traversing Hue, Saturation, Value space.
@@ -83,7 +84,7 @@
 ## @item ------------- @tab ---------------------------------------------------------------------------------------------
 ## @item white @tab all white colormap (no colors).
 ## @end multitable
-## @seealso{viridis, jet, cubehelix, hsv, rainbow, hot, cool, spring, summer, autumn, winter, gray, bone, copper, pink, ocean, colorcube, flag, lines, prism, white}
+## @seealso{viridis, turbo, jet, cubehelix, hsv, rainbow, hot, cool, spring, summer, autumn, winter, gray, bone, copper, pink, ocean, colorcube, flag, lines, prism, white}
 ## @end deftypefn
 
 function cmap = colormap (varargin)
@@ -177,7 +178,7 @@
 %!error colormap (1,2,3)
 %!error <MAP must be a real-valued N x 3> colormap ({1,2,3})
 %!error <MAP must be a real-valued N x 3> colormap ([1 i 1])
-%!error <MAP must be a real-valued N x 3> colormap (ones(3,3,3))
+%!error <MAP must be a real-valued N x 3> colormap (ones (3,3,3))
 %!error <MAP must be a real-valued N x 3> colormap ([1 0 1 0])
 %!error <all MAP values must be in the range> colormap ([-1 0 0])
 %!error <all MAP values must be in the range> colormap ([2 0 0])
--- a/scripts/image/contrast.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/contrast.m	Sun May 16 09:44:35 2021 +0200
@@ -35,9 +35,7 @@
 
 function cmap = contrast (x, n)
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     hf = get (0, "currentfigure");
     if (! isempty (hf))
       n = rows (get (hf, "colormap"));
--- a/scripts/image/cool.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/cool.m	Sun May 16 09:44:35 2021 +0200
@@ -35,9 +35,7 @@
 
 function map = cool (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("cool: N must be a scalar");
     endif
--- a/scripts/image/copper.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/copper.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 
 function map = copper (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("copper: N must be a scalar");
     endif
--- a/scripts/image/cubehelix.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/cubehelix.m	Sun May 16 09:44:35 2021 +0200
@@ -26,6 +26,7 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{map} =} cubehelix ()
 ## @deftypefnx {} {@var{map} =} cubehelix (@var{n})
+## @deftypefnx {} {@var{map} =} cubehelix (@var{n}, @var{start}, @var{rots}, @var{hue}, @var{gamma})
 ## Create cubehelix colormap.
 ##
 ## This colormap varies from black to white going though blue, green, and red
@@ -50,9 +51,7 @@
 
 function map = cubehelix (n, start = 0.5, rots = -1.5, hue = 1, gamma = 1)
 
-  if (nargin > 5)
-    print_usage ();
-  elseif (nargin > 0)
+  if (nargin > 0)
     if (! isscalar (n))
       error ("cubehelix: N must be a scalar");
     endif
--- a/scripts/image/flag.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/flag.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 
 function map = flag (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("flag: N must be a scalar");
     endif
--- a/scripts/image/frame2im.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/frame2im.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function [x, map] = frame2im (frame)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! all (isfield (frame, {"cdata", "colormap"})))
     error ("frame2im: F must be a struct with the fields colormap and cdata");
--- a/scripts/image/gray.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/gray.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 
 function map = gray (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("gray: N must be a scalar");
     endif
--- a/scripts/image/gray2ind.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/gray2ind.m	Sun May 16 09:44:35 2021 +0200
@@ -42,9 +42,9 @@
 
 function [I, map] = gray2ind (I, n = 64)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
-  elseif (! isreal (I) || issparse (I) || ! ismatrix(I))
+  elseif (! isreal (I) || issparse (I) || ! ismatrix (I))
     error ("gray2ind: I must be a grayscale or binary image");
   elseif (! isscalar (n) || n < 1 || n > 65536)
     error ("gray2ind: N must be a positive integer in the range [1, 65536]");
@@ -106,8 +106,7 @@
 %! assert (class (gray2ind ([0.0 0.5 1.0], 257)), "uint16");
 
 ## Test input validation
-%!error gray2ind ()
-%!error gray2ind (1,2,3)
+%!error <Invalid call> gray2ind ()
 %!error <I must be a grayscale or binary image> gray2ind ({1})
 %!error <I must be a grayscale or binary image> gray2ind ([1+i])
 %!error <I must be a grayscale or binary image> gray2ind (sparse ([1]))
--- a/scripts/image/hot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/hot.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 
 function map = hot (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("hot: N must be a scalar");
     endif
--- a/scripts/image/hsv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/hsv.m	Sun May 16 09:44:35 2021 +0200
@@ -40,9 +40,7 @@
 
 function map = hsv (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("hsv: N must be a scalar");
     endif
--- a/scripts/image/hsv2rgb.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/hsv2rgb.m	Sun May 16 09:44:35 2021 +0200
@@ -64,7 +64,7 @@
   ## where f_x(hue) is a piecewise defined function for
   ## each color with f_r(hue-2/3) = f_g(hue) = f_b(hue-1/3).
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -136,8 +136,7 @@
 %!assert (hsv2rgb (sparse ([1 1 1])), sparse ([1 0 0]))
 
 ## Test input validation
-%!error hsv2rgb ()
-%!error hsv2rgb (1,2)
+%!error <Invalid call> hsv2rgb ()
 %!error <invalid data type> hsv2rgb ({1})
 %!error <HSV must be a colormap or HSV image> hsv2rgb (ones (2,2))
 
--- a/scripts/image/im2double.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/im2double.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
 
 function img = im2double (img, im_type)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/image/im2frame.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/im2frame.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function frame = im2frame (x, map = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (ndims (x) > 4)
     error ("im2frame: X and RGB must be a single image");
--- a/scripts/image/imfinfo.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/imfinfo.m	Sun May 16 09:44:35 2021 +0200
@@ -188,7 +188,7 @@
 %! assert (error_thrown, true);
 
 ## Test input validation
-%!error imfinfo ()
-%!error imfinfo (1,2,3)
+%!error <Invalid call> imfinfo ()
+%!error <Invalid call> imfinfo (1,2,3)
 %!error <FILENAME must be a string> imfinfo (1)
 %!error <EXT must be a string> imfinfo ("foo", 1)
--- a/scripts/image/imformats.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/imformats.m	Sun May 16 09:44:35 2021 +0200
@@ -77,11 +77,7 @@
 
 function varargout = imformats (arg1, arg2, arg3)
 
-  if (nargin > 3)
-    print_usage ();
-  endif
-
-  mlock (); # prevent formats to be removed by "clear all"
+  mlock ();  # prevent formats being removed by "clear all"
   persistent formats = default_formats ();
 
   if (nargin == 0 && nargout == 0)
@@ -96,7 +92,7 @@
       switch (tolower (arg1))
         case "add",
           if (! isstruct (arg2))
-            error ("imformats: FORMAT to %s must be a structure.", arg1);
+            error ("imformats: FORMAT to %s must be a structure", arg1);
           endif
           arrayfun (@is_valid_format, arg2);
           formats(end + 1: end + numel (arg2)) = arg2;
@@ -104,21 +100,21 @@
 
         case {"remove", "update"},
           if (! ischar (arg2))
-            error ("imformats: EXT to %s must be a string.", arg1);
+            error ("imformats: EXT to %s must be a string", arg1);
           endif
-          ## FIXME: suppose a format with multiple extensions.  If one of
+          ## FIXME: Suppose a format with multiple extensions; if one of
           ##        them is requested to be removed, should we remove the
           ##        whole format, or just that extension from the format?
           match = find_ext_idx (formats, arg2);
           if (! any (match))
-            error ("imformats: no EXT '%s' found.", arg2);
+            error ("imformats: no EXT '%s' found", arg2);
           endif
           if (strcmpi (arg1, "remove"))
             formats(match) = [];
           else
             ## then it's update
             if (! isstruct (arg3))
-              error ("imformats: FORMAT to update must be a structure.");
+              error ("imformats: FORMAT to update must be a structure");
             endif
             is_valid_format (arg3);
             formats(match) = arg3;
@@ -130,7 +126,7 @@
         otherwise
           ## then we look for a format with that extension.
           match = find_ext_idx (formats, arg1);
-          ## For matlab compatibility, if we don't find any format we must
+          ## For Matlab compatibility, if we don't find any format we must
           ## return an empty struct with NO fields.  We can't use match as mask
           if (any (match))
             varargout{1} = formats(match);
@@ -139,7 +135,7 @@
           endif
       endswitch
     else
-      error ("imformats: first argument must be either a structure or string.");
+      error ("imformats: first argument must be either a structure or string");
     endif
   else
     varargout{1} = formats;
@@ -247,7 +243,7 @@
             "XWD",  {"xwd"},          false;
             };
 
-  for fidx = 1: rows(coders)
+  for fidx = 1:rows (coders)
     formats(fidx).coder = coders{fidx, 1};
     formats(fidx).ext   = coders{fidx, 2};
     formats(fidx).alpha = coders{fidx, 3};
@@ -268,21 +264,24 @@
 endfunction
 
 function is_valid_format (format)
+
   ## the minimal list of fields required in the structure.  We don't
   ## require multipage because it doesn't exist in matlab
   min_fields  = {"ext", "read", "isa", "write", "info", "alpha", "description"};
   fields_mask = isfield (format, min_fields);
   if (! all (fields_mask))
-    error ("imformats: structure has missing field '%s'.", min_fields(! fields_mask){1});
+    error ("imformats: structure has missing field '%s'", min_fields(! fields_mask){1});
   endif
 
 endfunction
 
 function match = find_ext_idx (formats, ext)
+
   ## FIXME: what should we do if there's more than one hit?
   ##        Should this function prevent the addition of
   ##        duplicated extensions?
   match = cellfun (@(x) any (strcmpi (x, ext)), {formats.ext});
+
 endfunction
 
 function bool = isa_magick (coder, filename)
@@ -372,7 +371,7 @@
 %! unwind_protect
 %!   fmt = imformats ("jpg"); # take jpg as template
 %!   fmt.ext = "new_fmt";
-%!   fmt.read = @() true ();
+%!   fmt.read = @(~) true ();
 %!   imformats ("add", fmt);
 %!   assert (imread (fname), true);
 %! unwind_protect_cleanup
@@ -391,7 +390,7 @@
 %! unwind_protect
 %!   fmt = imformats ("jpg"); # take jpg as template
 %!   fmt.ext = "new_fmt1";
-%!   fmt.read = @() true();
+%!   fmt.read = @(~) true ();
 %!   fmt(2) = fmt(1);
 %!   fmt(2).ext = "new_fmt2";
 %!   imformats ("add", fmt);
--- a/scripts/image/imshow.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/imshow.m	Sun May 16 09:44:35 2021 +0200
@@ -268,7 +268,7 @@
 %! title ({"imshow with random 100x100x3 matrix", "RGB values > 1 are clipped"});
 
 ## Test input validation
-%!error imshow ()
+%!error <Invalid call> imshow ()
 %!error <IM must be an image> imshow ({"cell"})
 %!error <TrueColor image must be uint8> imshow (ones (3,3,3, "uint32"))
 %!error <TrueColor image must be uint8> imshow (ones (3,3,3, "int16"))
--- a/scripts/image/imwrite.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/imwrite.m	Sun May 16 09:44:35 2021 +0200
@@ -129,8 +129,8 @@
 
 
 ## Test input validation
-%!error imwrite ()                            # Wrong # of args
-%!error imwrite (1)                           # Wrong # of args
+%!error <Invalid call> imwrite ()             # Wrong # of args
+%!error <Invalid call> imwrite (1)            # Wrong # of args
 %!error imwrite ({"cell"}, "filename.jpg")    # Wrong class for img
 %!error imwrite (1, [], "filename.jpg")       # Empty image map
 %!error imwrite (1, 2, 3)                     # No filename specified
--- a/scripts/image/ind2gray.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/ind2gray.m	Sun May 16 09:44:35 2021 +0200
@@ -77,9 +77,8 @@
 %!assert (gray2ind (i2g, 100), uint8 (0:99))
 
 ## Test input validation
-%!error ind2gray ()
-%!error ind2gray (1)
-%!error ind2gray (1,2,3)
+%!error <Invalid call> ind2gray ()
+%!error <Invalid call> ind2gray (1)
 %!error <X must be an indexed image> ind2gray (ones (3,3,3), jet (64))
 %!error <X must be an indexed image> ind2gray (1+i, jet (64))
 %!error <X must be an indexed image> ind2gray (sparse (1), jet (64))
--- a/scripts/image/ind2rgb.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/ind2rgb.m	Sun May 16 09:44:35 2021 +0200
@@ -66,7 +66,7 @@
                    [1 2 4 3]);
     else
       ## we should never reach here since ind2x() should filter them out
-      error ("ind2rgb: an indexed image must have 2 or 4 dimensions.");
+      error ("ind2rgb: an indexed image must have 2 or 4 dimensions");
     endif
   endif
 
@@ -102,8 +102,8 @@
 %! assert (rgb(:,3,:), 1/63 * ones (1,1,3));
 
 ## Test input validation
-%!error ind2rgb ()
-%!error ind2rgb (1,2,3)
+%!error <Invalid call> ind2rgb ()
+%!error <Invalid call> ind2rgb (1)
 %!error <X must be an indexed image> ind2rgb (ones (3,3,3), jet (64))
 %!error <X must be an indexed image> ind2rgb (1+i, jet (64))
 %!error <X must be an indexed image> ind2rgb (sparse (1), jet (64))
@@ -127,10 +127,10 @@
 %! cmap = repmat (linspace (0, 1, 9)(:), [1 3]);
 %! ind = [0 3 6; 1 4 7; 2 5 8];
 %! rgb = repmat (reshape (linspace (0, 1, 9), [3 3]), [1 1 3]);
-%! assert (ind2rgb (uint8  (ind), cmap), rgb)
-%! assert (ind2rgb (uint16 (ind), cmap), rgb)
-%! assert (ind2rgb (uint32 (ind), cmap), rgb)
-%! assert (ind2rgb (uint64 (ind), cmap), rgb)
+%! assert (ind2rgb (uint8  (ind), cmap), rgb);
+%! assert (ind2rgb (uint16 (ind), cmap), rgb);
+%! assert (ind2rgb (uint32 (ind), cmap), rgb);
+%! assert (ind2rgb (uint64 (ind), cmap), rgb);
 %! fail ("ind2rgb (int8  (ind), cmap)", "X must be an indexed image")
 %! fail ("ind2rgb (int16 (ind), cmap)", "X must be an indexed image")
 %! fail ("ind2rgb (int32 (ind), cmap)", "X must be an indexed image")
@@ -139,5 +139,10 @@
 %! cmap(65541,:) = cmap(9,:); # index outside the uint16 range
 %! cmap(9,:) = 0;
 %! ind(3,3) = 65540;
-%! assert (ind2rgb (uint32 (ind), cmap), rgb)
-%! assert (ind2rgb (uint64 (ind), cmap), rgb)
+%! assert (ind2rgb (uint32 (ind), cmap), rgb);
+%! assert (ind2rgb (uint64 (ind), cmap), rgb);
+
+%!test <*59242>
+%! warning ("off", "Octave:ind2rgb:invalid-idx-img", "local");
+%! assert (ind2rgb (uint64 (intmax ("uint64")), jet (64)), ...
+%!         reshape ([0.5,0,0], [1,1,3]));
--- a/scripts/image/iscolormap.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/iscolormap.m	Sun May 16 09:44:35 2021 +0200
@@ -40,8 +40,8 @@
 
 function retval = iscolormap (cmap)
 
-  if (nargin != 1)
-    print_usage;
+  if (nargin < 1)
+    print_usage ();
   endif
 
   retval = (isnumeric (cmap) && isreal (cmap)
--- a/scripts/image/jet.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/jet.m	Sun May 16 09:44:35 2021 +0200
@@ -31,14 +31,17 @@
 ##
 ## The argument @var{n} must be a scalar.
 ## If unspecified, the length of the current colormap, or 64, is used.
-## @seealso{colormap}
+##
+## Programming Note: The @code{jet} colormap is not perceptually uniform.
+## Try the @code{viridis} colormap if that is important.  For a drop-in
+## replacement for @code{jet} with better perceptual characteristics try
+## the @code{turbo} colormap.
+## @seealso{colormap, turbo}
 ## @end deftypefn
 
 function map = jet (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("jet: N must be a scalar");
     endif
--- a/scripts/image/lines.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/lines.m	Sun May 16 09:44:35 2021 +0200
@@ -38,9 +38,7 @@
 function map = lines (n)
 
   hf = get (groot, "currentfigure");
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("lines: N must be a scalar");
     endif
--- a/scripts/image/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -13,6 +13,7 @@
   %reldir%/private/ind2x.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/autumn.m \
   %reldir%/bone.m \
   %reldir%/brighten.m \
@@ -58,6 +59,7 @@
   %reldir%/spinmap.m \
   %reldir%/spring.m \
   %reldir%/summer.m \
+  %reldir%/turbo.m \
   %reldir%/viridis.m \
   %reldir%/white.m \
   %reldir%/winter.m
--- a/scripts/image/movie.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/movie.m	Sun May 16 09:44:35 2021 +0200
@@ -244,7 +244,8 @@
 %! movie (mov, 3, 25);
 
 ## Test input validation
-%!error movie ()
+%!error <Invalid call> movie ()
+%!error <Invalid call> movie (1,2,3,4,5)
 %!error <MOV must be a frame struct array> movie ({2})
 %!error <MOV must contain at least two frames>
 %! movie (struct ("cdata", [], "colormap", []));
--- a/scripts/image/ocean.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/ocean.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 
 function map = ocean (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("ocean: N must be a scalar");
     endif
--- a/scripts/image/pink.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/pink.m	Sun May 16 09:44:35 2021 +0200
@@ -38,9 +38,7 @@
 
 function map = pink (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("pink: N must be a scalar");
     endif
--- a/scripts/image/prism.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/prism.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,7 @@
 
 function map = prism (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("prism: N must be a scalar");
     endif
--- a/scripts/image/private/__imfinfo__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/private/__imfinfo__.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function info = __imfinfo__ (filename)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ("imfinfo");
   elseif (! ischar (filename))
     error ("imfinfo: FILENAME must be a string");
--- a/scripts/image/private/ind2x.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/private/ind2x.m	Sun May 16 09:44:35 2021 +0200
@@ -58,22 +58,28 @@
   ## It is possible that an integer storage class may not have enough room
   ## to make the switch, in which case we convert the data to single.
   maxidx = max (x(:));
-  if (isinteger (x))
+  is_int = isinteger (x);
+  if (is_int)
     if (maxidx == intmax (x))
       x = single (x);
     endif
-    x      += 1;
-    maxidx += 1;
+    x += 1;
   endif
 
   ## When there are more colors in the image, than there are in the map,
   ## pad the colormap with the last color in the map for Matlab compatibility.
   num_colors = rows (map);
-  if (num_colors < maxidx)
+  if (num_colors - is_int < maxidx)
     warning (["Octave:" caller ":invalid-idx-img"],
              [caller ": indexed image contains colors outside of colormap"]);
-    pad = repmat (map(end,:), maxidx - num_colors, 1);
-    map(end+1:maxidx, :) = pad;
+    if (numel (x) > maxidx - num_colors + is_int)
+      ## The image is large. So extend the map.
+      pad = repmat (map(end,:), maxidx - num_colors + is_int, 1);
+      map(end+(1:rows (pad)), :) = pad;
+    else
+      ## The map extension would be large. So clip the image.
+      x(x > rows (map)) = rows (map);
+    endif
   endif
 
 endfunction
--- a/scripts/image/rainbow.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/rainbow.m	Sun May 16 09:44:35 2021 +0200
@@ -39,9 +39,7 @@
 
 function map = rainbow (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("rainbow: N must be a scalar");
     endif
--- a/scripts/image/rgb2gray.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/rgb2gray.m	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 
 function I = rgb2gray (rgb)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -161,7 +161,6 @@
 %! assert (rgb2gray (single (rgb_double)), single (expected));
 
 ## Test input validation
-%!error rgb2gray ()
-%!error rgb2gray (1,2)
+%!error <Invalid call> rgb2gray ()
 %!error <invalid data type 'cell'> rgb2gray ({1})
 %!error <RGB must be a colormap or RGB image> rgb2gray (ones (2,2))
--- a/scripts/image/rgb2hsv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/rgb2hsv.m	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,7 @@
 
 function hsv = rgb2hsv (rgb)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -113,8 +113,7 @@
 %!assert (rgb2hsv (sparse ([1 1 1])), sparse ([0 0 1]))
 
 ## Test input validation
-%!error rgb2hsv ()
-%!error rgb2hsv (1,2)
+%!error <Invalid call> rgb2hsv ()
 %!error <invalid data type 'cell'> rgb2hsv ({1})
 %!error <RGB must be a colormap or RGB image> rgb2hsv (ones (2,2))
 
--- a/scripts/image/rgb2ind.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/rgb2ind.m	Sun May 16 09:44:35 2021 +0200
@@ -103,8 +103,8 @@
 
 
 ## Test input validation
-%!error rgb2ind ()
-%!error rgb2ind (1,2,3,4,5,6,7)
+%!error <Invalid call> rgb2ind ()
+%!error <Invalid call> rgb2ind (1,2)
 %!error <RGB> rgb2ind (rand (10, 10, 4))
 
 ## FIXME: the following tests simply make sure that rgb2ind and ind2rgb
--- a/scripts/image/rgbplot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/rgbplot.m	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
 
 function h = rgbplot (cmap, style = "profile")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -91,8 +91,7 @@
 %!  rgbplot (ocean, "composite");
 
 ## Test input validation
-%!error rgbplot ()
-%!error rgbplot (1,2)
+%!error <Invalid call> rgbplot ()
 %!error <CMAP must be a valid colormap> rgbplot ({0 1 0})
 %!error <STYLE must be a string> rgbplot ([0 1 0], 2)
 %!error <unknown STYLE 'nostyle'> rgbplot ([0 1 0], "nostyle")
--- a/scripts/image/spinmap.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/spinmap.m	Sun May 16 09:44:35 2021 +0200
@@ -42,9 +42,7 @@
 
 function spinmap (t = 5, inc = 2)
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (ischar (t))
+  if (ischar (t))
     if (strcmpi (t, "inf"))
       t = Inf;
     else
@@ -56,8 +54,8 @@
 
   cmap = cmap_orig = get (gcf (), "colormap");
 
-  t0 = clock;
-  while (etime (clock, t0) < t)
+  t0 = clock ();
+  while (etime (clock (), t0) < t)
     cmap = shift (cmap, inc, 1);
     set (gcf (), "colormap", cmap);
     drawnow ();
--- a/scripts/image/spring.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/spring.m	Sun May 16 09:44:35 2021 +0200
@@ -35,9 +35,7 @@
 
 function map = spring (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("spring: N must be a scalar");
     endif
--- a/scripts/image/summer.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/summer.m	Sun May 16 09:44:35 2021 +0200
@@ -35,9 +35,7 @@
 
 function map = summer (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("summer: N must be a scalar");
     endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/turbo.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,327 @@
+########################################################################
+##
+## Copyright (C) 2021 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{map} =} turbo ()
+## @deftypefnx {} {@var{map} =} turbo (@var{n})
+## Create color colormap.  This colormap ranges from dark blue through green
+## to dark red; similar to the outdated @code{jet} colormap but perceptually
+## uniform.
+##
+## The argument @var{n} must be a scalar.
+## If unspecified, the length of the current colormap, or 64, is used.
+## @seealso{colormap}
+## @end deftypefn
+
+## This is a port to Octave of the Google LLC colormap "turbo"
+## by Anton Mikhailov.  The original file is distributed under Apache-2.0:
+## https://opensource.org/licenses/Apache-2.0
+
+function map = turbo (n)
+
+  if (nargin == 1)
+    if (! isscalar (n))
+      error ("turbo: N must be a scalar");
+    endif
+    n = double (n);
+  else
+    hf = get (0, "currentfigure");
+    if (! isempty (hf))
+      n = rows (get (hf, "colormap"));
+    else
+      n = 64;
+    endif
+  endif
+
+  persistent turbo_lut = [0.18995, 0.07176, 0.23217;
+                          0.19483, 0.08339, 0.26149;
+                          0.19956, 0.09498, 0.29024;
+                          0.20415, 0.10652, 0.31844;
+                          0.20860, 0.11802, 0.34607;
+                          0.21291, 0.12947, 0.37314;
+                          0.21708, 0.14087, 0.39964;
+                          0.22111, 0.15223, 0.42558;
+                          0.22500, 0.16354, 0.45096;
+                          0.22875, 0.17481, 0.47578;
+                          0.23236, 0.18603, 0.50004;
+                          0.23582, 0.19720, 0.52373;
+                          0.23915, 0.20833, 0.54686;
+                          0.24234, 0.21941, 0.56942;
+                          0.24539, 0.23044, 0.59142;
+                          0.24830, 0.24143, 0.61286;
+                          0.25107, 0.25237, 0.63374;
+                          0.25369, 0.26327, 0.65406;
+                          0.25618, 0.27412, 0.67381;
+                          0.25853, 0.28492, 0.69300;
+                          0.26074, 0.29568, 0.71162;
+                          0.26280, 0.30639, 0.72968;
+                          0.26473, 0.31706, 0.74718;
+                          0.26652, 0.32768, 0.76412;
+                          0.26816, 0.33825, 0.78050;
+                          0.26967, 0.34878, 0.79631;
+                          0.27103, 0.35926, 0.81156;
+                          0.27226, 0.36970, 0.82624;
+                          0.27334, 0.38008, 0.84037;
+                          0.27429, 0.39043, 0.85393;
+                          0.27509, 0.40072, 0.86692;
+                          0.27576, 0.41097, 0.87936;
+                          0.27628, 0.42118, 0.89123;
+                          0.27667, 0.43134, 0.90254;
+                          0.27691, 0.44145, 0.91328;
+                          0.27701, 0.45152, 0.92347;
+                          0.27698, 0.46153, 0.93309;
+                          0.27680, 0.47151, 0.94214;
+                          0.27648, 0.48144, 0.95064;
+                          0.27603, 0.49132, 0.95857;
+                          0.27543, 0.50115, 0.96594;
+                          0.27469, 0.51094, 0.97275;
+                          0.27381, 0.52069, 0.97899;
+                          0.27273, 0.53040, 0.98461;
+                          0.27106, 0.54015, 0.98930;
+                          0.26878, 0.54995, 0.99303;
+                          0.26592, 0.55979, 0.99583;
+                          0.26252, 0.56967, 0.99773;
+                          0.25862, 0.57958, 0.99876;
+                          0.25425, 0.58950, 0.99896;
+                          0.24946, 0.59943, 0.99835;
+                          0.24427, 0.60937, 0.99697;
+                          0.23874, 0.61931, 0.99485;
+                          0.23288, 0.62923, 0.99202;
+                          0.22676, 0.63913, 0.98851;
+                          0.22039, 0.64901, 0.98436;
+                          0.21382, 0.65886, 0.97959;
+                          0.20708, 0.66866, 0.97423;
+                          0.20021, 0.67842, 0.96833;
+                          0.19326, 0.68812, 0.96190;
+                          0.18625, 0.69775, 0.95498;
+                          0.17923, 0.70732, 0.94761;
+                          0.17223, 0.71680, 0.93981;
+                          0.16529, 0.72620, 0.93161;
+                          0.15844, 0.73551, 0.92305;
+                          0.15173, 0.74472, 0.91416;
+                          0.14519, 0.75381, 0.90496;
+                          0.13886, 0.76279, 0.89550;
+                          0.13278, 0.77165, 0.88580;
+                          0.12698, 0.78037, 0.87590;
+                          0.12151, 0.78896, 0.86581;
+                          0.11639, 0.79740, 0.85559;
+                          0.11167, 0.80569, 0.84525;
+                          0.10738, 0.81381, 0.83484;
+                          0.10357, 0.82177, 0.82437;
+                          0.10026, 0.82955, 0.81389;
+                          0.09750, 0.83714, 0.80342;
+                          0.09532, 0.84455, 0.79299;
+                          0.09377, 0.85175, 0.78264;
+                          0.09287, 0.85875, 0.77240;
+                          0.09267, 0.86554, 0.76230;
+                          0.09320, 0.87211, 0.75237;
+                          0.09451, 0.87844, 0.74265;
+                          0.09662, 0.88454, 0.73316;
+                          0.09958, 0.89040, 0.72393;
+                          0.10342, 0.89600, 0.71500;
+                          0.10815, 0.90142, 0.70599;
+                          0.11374, 0.90673, 0.69651;
+                          0.12014, 0.91193, 0.68660;
+                          0.12733, 0.91701, 0.67627;
+                          0.13526, 0.92197, 0.66556;
+                          0.14391, 0.92680, 0.65448;
+                          0.15323, 0.93151, 0.64308;
+                          0.16319, 0.93609, 0.63137;
+                          0.17377, 0.94053, 0.61938;
+                          0.18491, 0.94484, 0.60713;
+                          0.19659, 0.94901, 0.59466;
+                          0.20877, 0.95304, 0.58199;
+                          0.22142, 0.95692, 0.56914;
+                          0.23449, 0.96065, 0.55614;
+                          0.24797, 0.96423, 0.54303;
+                          0.26180, 0.96765, 0.52981;
+                          0.27597, 0.97092, 0.51653;
+                          0.29042, 0.97403, 0.50321;
+                          0.30513, 0.97697, 0.48987;
+                          0.32006, 0.97974, 0.47654;
+                          0.33517, 0.98234, 0.46325;
+                          0.35043, 0.98477, 0.45002;
+                          0.36581, 0.98702, 0.43688;
+                          0.38127, 0.98909, 0.42386;
+                          0.39678, 0.99098, 0.41098;
+                          0.41229, 0.99268, 0.39826;
+                          0.42778, 0.99419, 0.38575;
+                          0.44321, 0.99551, 0.37345;
+                          0.45854, 0.99663, 0.36140;
+                          0.47375, 0.99755, 0.34963;
+                          0.48879, 0.99828, 0.33816;
+                          0.50362, 0.99879, 0.32701;
+                          0.51822, 0.99910, 0.31622;
+                          0.53255, 0.99919, 0.30581;
+                          0.54658, 0.99907, 0.29581;
+                          0.56026, 0.99873, 0.28623;
+                          0.57357, 0.99817, 0.27712;
+                          0.58646, 0.99739, 0.26849;
+                          0.59891, 0.99638, 0.26038;
+                          0.61088, 0.99514, 0.25280;
+                          0.62233, 0.99366, 0.24579;
+                          0.63323, 0.99195, 0.23937;
+                          0.64362, 0.98999, 0.23356;
+                          0.65394, 0.98775, 0.22835;
+                          0.66428, 0.98524, 0.22370;
+                          0.67462, 0.98246, 0.21960;
+                          0.68494, 0.97941, 0.21602;
+                          0.69525, 0.97610, 0.21294;
+                          0.70553, 0.97255, 0.21032;
+                          0.71577, 0.96875, 0.20815;
+                          0.72596, 0.96470, 0.20640;
+                          0.73610, 0.96043, 0.20504;
+                          0.74617, 0.95593, 0.20406;
+                          0.75617, 0.95121, 0.20343;
+                          0.76608, 0.94627, 0.20311;
+                          0.77591, 0.94113, 0.20310;
+                          0.78563, 0.93579, 0.20336;
+                          0.79524, 0.93025, 0.20386;
+                          0.80473, 0.92452, 0.20459;
+                          0.81410, 0.91861, 0.20552;
+                          0.82333, 0.91253, 0.20663;
+                          0.83241, 0.90627, 0.20788;
+                          0.84133, 0.89986, 0.20926;
+                          0.85010, 0.89328, 0.21074;
+                          0.85868, 0.88655, 0.21230;
+                          0.86709, 0.87968, 0.21391;
+                          0.87530, 0.87267, 0.21555;
+                          0.88331, 0.86553, 0.21719;
+                          0.89112, 0.85826, 0.21880;
+                          0.89870, 0.85087, 0.22038;
+                          0.90605, 0.84337, 0.22188;
+                          0.91317, 0.83576, 0.22328;
+                          0.92004, 0.82806, 0.22456;
+                          0.92666, 0.82025, 0.22570;
+                          0.93301, 0.81236, 0.22667;
+                          0.93909, 0.80439, 0.22744;
+                          0.94489, 0.79634, 0.22800;
+                          0.95039, 0.78823, 0.22831;
+                          0.95560, 0.78005, 0.22836;
+                          0.96049, 0.77181, 0.22811;
+                          0.96507, 0.76352, 0.22754;
+                          0.96931, 0.75519, 0.22663;
+                          0.97323, 0.74682, 0.22536;
+                          0.97679, 0.73842, 0.22369;
+                          0.98000, 0.73000, 0.22161;
+                          0.98289, 0.72140, 0.21918;
+                          0.98549, 0.71250, 0.21650;
+                          0.98781, 0.70330, 0.21358;
+                          0.98986, 0.69382, 0.21043;
+                          0.99163, 0.68408, 0.20706;
+                          0.99314, 0.67408, 0.20348;
+                          0.99438, 0.66386, 0.19971;
+                          0.99535, 0.65341, 0.19577;
+                          0.99607, 0.64277, 0.19165;
+                          0.99654, 0.63193, 0.18738;
+                          0.99675, 0.62093, 0.18297;
+                          0.99672, 0.60977, 0.17842;
+                          0.99644, 0.59846, 0.17376;
+                          0.99593, 0.58703, 0.16899;
+                          0.99517, 0.57549, 0.16412;
+                          0.99419, 0.56386, 0.15918;
+                          0.99297, 0.55214, 0.15417;
+                          0.99153, 0.54036, 0.14910;
+                          0.98987, 0.52854, 0.14398;
+                          0.98799, 0.51667, 0.13883;
+                          0.98590, 0.50479, 0.13367;
+                          0.98360, 0.49291, 0.12849;
+                          0.98108, 0.48104, 0.12332;
+                          0.97837, 0.46920, 0.11817;
+                          0.97545, 0.45740, 0.11305;
+                          0.97234, 0.44565, 0.10797;
+                          0.96904, 0.43399, 0.10294;
+                          0.96555, 0.42241, 0.09798;
+                          0.96187, 0.41093, 0.09310;
+                          0.95801, 0.39958, 0.08831;
+                          0.95398, 0.38836, 0.08362;
+                          0.94977, 0.37729, 0.07905;
+                          0.94538, 0.36638, 0.07461;
+                          0.94084, 0.35566, 0.07031;
+                          0.93612, 0.34513, 0.06616;
+                          0.93125, 0.33482, 0.06218;
+                          0.92623, 0.32473, 0.05837;
+                          0.92105, 0.31489, 0.05475;
+                          0.91572, 0.30530, 0.05134;
+                          0.91024, 0.29599, 0.04814;
+                          0.90463, 0.28696, 0.04516;
+                          0.89888, 0.27824, 0.04243;
+                          0.89298, 0.26981, 0.03993;
+                          0.88691, 0.26152, 0.03753;
+                          0.88066, 0.25334, 0.03521;
+                          0.87422, 0.24526, 0.03297;
+                          0.86760, 0.23730, 0.03082;
+                          0.86079, 0.22945, 0.02875;
+                          0.85380, 0.22170, 0.02677;
+                          0.84662, 0.21407, 0.02487;
+                          0.83926, 0.20654, 0.02305;
+                          0.83172, 0.19912, 0.02131;
+                          0.82399, 0.19182, 0.01966;
+                          0.81608, 0.18462, 0.01809;
+                          0.80799, 0.17753, 0.01660;
+                          0.79971, 0.17055, 0.01520;
+                          0.79125, 0.16368, 0.01387;
+                          0.78260, 0.15693, 0.01264;
+                          0.77377, 0.15028, 0.01148;
+                          0.76476, 0.14374, 0.01041;
+                          0.75556, 0.13731, 0.00942;
+                          0.74617, 0.13098, 0.00851;
+                          0.73661, 0.12477, 0.00769;
+                          0.72686, 0.11867, 0.00695;
+                          0.71692, 0.11268, 0.00629;
+                          0.70680, 0.10680, 0.00571;
+                          0.69650, 0.10102, 0.00522;
+                          0.68602, 0.09536, 0.00481;
+                          0.67535, 0.08980, 0.00449;
+                          0.66449, 0.08436, 0.00424;
+                          0.65345, 0.07902, 0.00408;
+                          0.64223, 0.07380, 0.00401;
+                          0.63082, 0.06868, 0.00401;
+                          0.61923, 0.06367, 0.00410;
+                          0.60746, 0.05878, 0.00427;
+                          0.59550, 0.05399, 0.00453;
+                          0.58336, 0.04931, 0.00486;
+                          0.57103, 0.04474, 0.00529;
+                          0.55852, 0.04028, 0.00579;
+                          0.54583, 0.03593, 0.00638;
+                          0.53295, 0.03169, 0.00705;
+                          0.51989, 0.02756, 0.00780;
+                          0.50664, 0.02354, 0.00863;
+                          0.49321, 0.01963, 0.00955;
+                          0.47960, 0.01583, 0.01055];
+
+  p = rows (turbo_lut);
+  map = interp1 (1:p, turbo_lut, linspace (1, p, n), "linear");
+
+endfunction
+
+
+%!demo
+%! ## Show the 'turbo' colormap profile and as an image
+%! cmap = turbo (256);
+%! subplot (2, 1, 1);
+%!  rgbplot (cmap, "composite");
+%! subplot (2, 1, 2);
+%!  rgbplot (cmap);
--- a/scripts/image/viridis.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/viridis.m	Sun May 16 09:44:35 2021 +0200
@@ -40,9 +40,7 @@
 
 function map = viridis (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("viridis: N must be a scalar");
     endif
--- a/scripts/image/white.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/white.m	Sun May 16 09:44:35 2021 +0200
@@ -35,9 +35,7 @@
 
 function map = white (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("white: N must be a scalar");
     endif
--- a/scripts/image/winter.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/image/winter.m	Sun May 16 09:44:35 2021 +0200
@@ -35,9 +35,7 @@
 
 function map = winter (n)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isscalar (n))
       error ("winter: N must be a scalar");
     endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/io/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/io/beep.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/io/beep.m	Sun May 16 09:44:35 2021 +0200
@@ -27,7 +27,7 @@
 ## @deftypefn {} {} beep ()
 ## Produce a beep from the speaker (or visual bell).
 ##
-## This function sends the alarm character @qcode{"@xbackslashchar{}a"} to
+## This function sends the alarm character @qcode{"@backslashchar{}a"} to
 ## the terminal.  Depending on the user's configuration this may produce an
 ## audible beep, a visual bell, or nothing at all.
 ## @seealso{puts, fputs, printf, fprintf}
@@ -35,13 +35,9 @@
 
 function beep ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   puts ("\a");
 
 endfunction
 
 
-%!error (beep (1))
+%!error beep (1)
--- a/scripts/io/csvread.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/io/csvread.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 ## @end example
 ##
 ## Any optional arguments are passed directly to @code{dlmread}
-## (@pxref{XREFdlmread,,dlmread}).
+## (@pxref{XREFdlmread,,@code{dlmread}}).
 ## @seealso{dlmread, textscan, csvwrite, dlmwrite}
 ## @end deftypefn
 
--- a/scripts/io/csvwrite.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/io/csvwrite.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 ## @end example
 ##
 ## Any optional arguments are passed directly to @code{dlmwrite}
-## (@pxref{XREFdlmwrite,,dlmwrite}).
+## (@pxref{XREFdlmwrite,,@code{dlmwrite}}).
 ## @seealso{csvread, dlmwrite, dlmread}
 ## @end deftypefn
 
--- a/scripts/io/dlmwrite.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/io/dlmwrite.m	Sun May 16 09:44:35 2021 +0200
@@ -58,9 +58,9 @@
 ##
 ## @item @qcode{"newline"}
 ## The character(s) to separate each row.  Three special cases exist for this
-## option.  @qcode{"unix"} is changed into @qcode{"@xbackslashchar{}n"},
-## @qcode{"pc"} is changed into @qcode{"@xbackslashchar{}r@xbackslashchar{}n"},
-## and @qcode{"mac"} is changed into @qcode{"@xbackslashchar{}r"}.  Any other
+## option.  @qcode{"unix"} is changed into @qcode{"@backslashchar{}n"},
+## @qcode{"pc"} is changed into @qcode{"@backslashchar{}r@backslashchar{}n"},
+## and @qcode{"mac"} is changed into @qcode{"@backslashchar{}r"}.  Any other
 ## value is used directly as the newline separator.
 ##
 ## @item @qcode{"roffset"}
--- a/scripts/io/fileread.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/io/fileread.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function str = fileread (filename)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -64,6 +64,5 @@
 %! assert (str, [cstr{1} "\n" cstr{2} "\n" cstr{3} "\n"]);
 
 ## Test input validation
-%!error fileread ()
-%!error fileread (1, 2)
+%!error <Invalid call> fileread ()
 %!error <FILENAME argument must be a string> fileread (1)
--- a/scripts/io/importdata.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/io/importdata.m	Sun May 16 09:44:35 2021 +0200
@@ -69,7 +69,7 @@
 
 function [output, delimiter, header_rows] = importdata (fname, delimiter = "", header_rows = -1)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -82,7 +82,7 @@
   if (nargin > 1)
     if (! ischar (delimiter)
         || (length (delimiter) > 1 && ! strcmp (delimiter, '\t')))
-      error("importdata: DELIMITER must be a single character");
+      error ("importdata: DELIMITER must be a single character");
     endif
     if (strcmp (delimiter, '\t'))
       delimiter = "\t";
@@ -98,7 +98,7 @@
 
   ## Check file format
   ## Get the extension from the filename.
-  [~, ~, ext, ~] = fileparts (fname);
+  [~, ~, ext] = fileparts (fname);
   ext = lower (ext);
 
   switch (ext)
@@ -175,8 +175,8 @@
 
     ## If no delimiter determined yet, make a guess.
     if (isempty (delimiter))
-      ## This pattern can be fooled, but mostly does the job just fine.
-      delim = regexpi (row, '[-+\d.e*ij ]+([^-+\de.ij])[-+\de*.ij ]',
+      ## Look for number, DELIMITER, DELIMITER*, number
+      delim = regexpi (row, '[-+]?\d*[.]?\d+(?:[ed][-+]?\d+)?[ij]?([^-+\d.deij])\1*[-+]?\d*[.]?\d+(?:[ed][-+]?\d+)?[ij]?',
                        'tokens', 'once');
       if (! isempty (delim))
         delimiter = delim{1};
@@ -200,6 +200,14 @@
       row = -1;
       break;
     else
+      ## The number of header rows and header columns is now known.
+      header_cols = find (! isnan (row_data), 1) - 1;
+      has_rowheaders = (header_cols == 1);
+
+      ## Set colheaders output from textdata if appropriate
+      ## NOTE: Octave chooses to be Matlab incompatible and return
+      ## both 'rowheaders' and 'colheaders' when they are present.
+      ## Matlab allows only one to be present at a time.
       if (! isempty (output.textdata))
         if (delimiter == " ")
           output.colheaders = regexp (strtrim (output.textdata{end}),
@@ -207,9 +215,22 @@
         else
           output.colheaders = ostrsplit (output.textdata{end}, delimiter);
         endif
+
+        nc_hdr = numel (output.colheaders);
+        nc_dat = numel (row_data);
+        if (! has_rowheaders)
+          if (nc_hdr != nc_dat)
+            output = rmfield (output, {"rowheaders", "colheaders"});
+          else
+            output = rmfield (output, "rowheaders");
+          endif
+        else
+          if (nc_hdr != nc_dat-1)
+            output = rmfield (output, "colheaders");
+          endif
+        endif
       endif
-      header_cols = find (! isnan (row_data), 1) - 1;
-      ## The number of header rows and header columns is now known.
+
       break;
     endif
 
@@ -243,19 +264,31 @@
   fclose (fid);
 
   if (num_header_rows >= 0)
-    header_rows = num_header_rows;
+    ## User has defined a number of header rows which disagrees with the
+    ## auto-detected number.  Print a warning.
+    if (num_header_rows < header_rows)
+      warning ("Octave:importdata:headerrows_mismatch",
+               "importdata: detected %d header rows, but HEADER_ROWS input configured %d rows", header_rows, num_header_rows);
+    endif
+  else
+    ## use the automatically detected number of header rows
+    num_header_rows = header_rows;
   endif
 
   ## Now, let the efficient built-in routine do the bulk of the work.
   if (delimiter == " ")
-    output.data = dlmread (fname, "", header_rows, header_cols,
+    output.data = dlmread (fname, "", num_header_rows, header_cols,
                            "emptyvalue", NA);
   else
-    output.data = dlmread (fname, delimiter, header_rows, header_cols,
+    output.data = dlmread (fname, delimiter, num_header_rows, header_cols,
                            "emptyvalue", NA);
   endif
 
   ## Go back and correct any individual values that did not convert.
+  ## FIXME: This is only efficient when the number of bad conversions is small.
+  ##        Any file with 'rowheaders' will cause the for loop to execute over
+  ##        *every* line in the file.
+
   na_idx = isna (output.data);
   if (header_cols > 0)
     na_idx = [(true (rows (na_idx), header_cols)), na_idx];
@@ -265,8 +298,11 @@
     file_content = ostrsplit (fileread (fname), "\r\n", true);
 
     na_rows = find (any (na_idx, 2));
+    ## Prune text lines in header that were already collected
+    idx = (na_rows(1:min (header_rows, end)) + num_header_rows) <= header_rows;
+    na_rows(idx) = [];
     for ridx = na_rows(:)'
-      row = file_content{ridx+header_rows};
+      row = file_content{ridx+num_header_rows};
       if (delimiter == " ")
         fields = regexp (strtrim (row), ' +', 'split');
       else
@@ -277,28 +313,45 @@
       if (! size_equal (missing_idx, fields))
         ## Fields completely missing at end of line.  Replace with NA.
         col = columns (fields);
-        output.data(ridx, (col+1):end) = NA;
+        ## FIXME: This code should be redundant because dlmread was called
+        ##        with "emptyval", NA.  Delete if there are no problems
+        ##        detected after some time.  Commented out: 5/23/2020.
+        ##output.data(ridx, (col+1):end) = NA;
         missing_idx = missing_idx(1:col);
       endif
       text = fields(missing_idx);
 
       text = text(! strcmpi (text, "NA"));  #  Remove valid "NA" entries
+      text = text(! strcmpi (text, ""));    #  Remove empty entries
       if (! isempty (text))
-        output.textdata = [output.textdata; text(:)];
+        output.textdata(end+1, 1:columns (text)) = text;
       endif
 
-      if (header_cols)
-        output.rowheaders(end+1, :) = fields(1:header_cols);
+      if (has_rowheaders)
+        output.rowheaders(end+1, 1) = fields(1);
       endif
     endfor
 
   endif
 
-  ## Final cleanup to satisfy output configuration
+  ## Final cleanup to satisfy Matlab compatibility
   if (all (cellfun ("isempty", output.textdata)))
     output = output.data;
-  elseif (! isempty (output.rowheaders) && ! isempty (output.colheaders))
-    output = struct ("data", {output.data}, "textdata", {output.textdata});
+  else
+    ## Text fields should be cell array of strings, rather than just cell.
+    try
+      output.textdata = cellstr (output.textdata);
+    end_try_catch
+    try
+      output.rowheaders = cellstr (output.rowheaders);
+    end_try_catch
+    try
+      output.colheaders = cellstr (output.colheaders);
+    end_try_catch
+  endif
+
+  if (num_header_rows != header_rows)
+    header_rows = num_header_rows;
   endif
 
 endfunction
@@ -377,7 +430,6 @@
 %! A.data = [3.1 -7.2 0; 0.012 6.5 128];
 %! A.textdata = {"This is a header row."; ...
 %!               "this row does not contain any data, but the next one does."};
-%! A.colheaders = A.textdata (2);
 %! fn  = tempname ();
 %! fid = fopen (fn, "w");
 %! fprintf (fid, "%s\n", A.textdata{:});
@@ -393,6 +445,7 @@
 %! ## Column headers, only last row is returned in colheaders
 %! A.data = [3.1 -7.2 0; 0.012 6.5 128];
 %! A.textdata = {"Label1\tLabel2\tLabel3";
+%!               "";
 %!               "col 1\tcol 2\tcol 3"};
 %! A.colheaders = {"col 1", "col 2", "col 3"};
 %! fn  = tempname ();
@@ -404,7 +457,7 @@
 %! unlink (fn);
 %! assert (a, A);
 %! assert (d, "\t");
-%! assert (h, 2);
+%! assert (h, 3);
 
 %!test
 %! ## Row headers
@@ -425,9 +478,11 @@
 %! ## Row/Column headers and Header Text
 %! A.data = [3.1 -7.2 0; 0.012 6.5 128];
 %! A.textdata = {"This is introductory header text"
-%!               "      col1 col2 col3"
+%!               "col1\tcol2\tcol3"
 %!               "row1"
 %!               "row2"};
+%! A.rowheaders = A.textdata(3:4);
+%! A.colheaders = {"col1", "col2", "col3"};
 %! fn  = tempname ();
 %! fid = fopen (fn, "w");
 %! fprintf (fid, "%s\n", A.textdata{1:2});
@@ -480,7 +535,7 @@
 %! assert (d, "\t");
 %! assert (h, 0);
 
-%!xtest <47413>
+%!test <47413>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! if (! ismac ()), return; endif
 %! ## Complex numbers
@@ -511,8 +566,7 @@
 %!test
 %! ## Missing values and Text Values
 %! A.data = [3.1 NA 0; 0.012 NA 128];
-%! A.textdata = {char(zeros(1,0))
-%!               "NO DATA"};
+%! A.textdata = {"NO DATA"};
 %! fn  = tempname ();
 %! fid = fopen (fn, "w");
 %! fputs (fid, "3.1\t\t0\n0.012\tNO DATA\t128");
@@ -585,8 +639,37 @@
 %! assert (d, "");
 %! assert (h, 3);
 
-%!error importdata ()
-%!error importdata (1,2,3,4)
+%!test <*58294>
+%! ## Varying values of header lines field
+%! fn  = tempname ();
+%! fid = fopen (fn, "w");
+%! fputs (fid, "header1\nheader2\n3.1\n4.2");
+%! fclose (fid);
+%! warning ("off", "Octave:importdata:headerrows_mismatch", "local");
+%! ## Base import
+%! [a, d, h] = importdata (fn, "");
+%! assert (a.data, [3.1; 4.2]);
+%! assert (a.textdata, {"header1"; "header2"});
+%! assert (h, 2);
+%! ## Import with 0 header lines
+%! [a, d, h] = importdata (fn, "", 0);
+%! assert (a.data, [NA; NA; 3.1; 4.2]);
+%! assert (a.textdata, {"header1"; "header2"});
+%! assert (h, 0);
+%! ## Import with 1 header lines
+%! [a, d, h] = importdata (fn, "", 1);
+%! assert (a.data, [NA; 3.1; 4.2]);
+%! assert (a.textdata, {"header1"; "header2"});
+%! assert (h, 1);
+%! ## Import with 3 header lines
+%! [a, d, h] = importdata (fn, "", 3);
+%! assert (a.data, [4.2]);
+%! assert (a.textdata, {"header1"; "header2"; "3.1"});
+%! assert (h, 3);
+%! unlink (fn);
+
+## Test input validation
+%!error <Invalid call> importdata ()
 %!error <FNAME must be a string> importdata (1)
 %!error <option -pastespecial not implemented> importdata ("-pastespecial")
 %!error <DELIMITER must be a single character> importdata ("foo", 1)
@@ -594,3 +677,10 @@
 %!error <HEADER_ROWS must be an integer> importdata ("foo", " ", "1")
 %!error <HEADER_ROWS must be an integer> importdata ("foo", " ", 1.5)
 %!error <not implemented for file format .avi> importdata ("foo.avi")
+%!warning <detected 2 header rows, but HEADER_ROWS input configured 1 rows>
+%! fn  = tempname ();
+%! fid = fopen (fn, "w");
+%! fputs (fid, "header1\nheader2\n3.1");
+%! fclose (fid);
+%! a = importdata (fn, "", 1);
+%! unlink (fn);
--- a/scripts/io/is_valid_file_id.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/io/is_valid_file_id.m	Sun May 16 09:44:35 2021 +0200
@@ -31,18 +31,18 @@
 
 function retval = is_valid_file_id (fid)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   retval = false;
 
-  if (nargin == 1)
-    try
-      if (isscalar (fid))
-        [file, mode, arch] = fopen (fid);
-        retval = ! isempty (file);
-      endif
-    end_try_catch
-  else
-    print_usage ();
-  endif
+  try
+    if (isscalar (fid))
+      [file, mode, arch] = fopen (fid);
+      retval = ! isempty (file);
+    endif
+  end_try_catch
 
 endfunction
 
--- a/scripts/io/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/io/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/beep.m \
   %reldir%/csvread.m \
   %reldir%/csvwrite.m \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/java/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/java/javachk.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/java/javachk.m	Sun May 16 09:44:35 2021 +0200
@@ -69,7 +69,7 @@
 
 function msg = javachk (feature, caller = "")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! ischar (feature))
     error ("javachk: FEATURE must be a string");
@@ -133,7 +133,7 @@
 endfunction
 
 
-%!testif ; ! __octave_config_info__().build_features.JAVA
+%!testif ; ! __octave_config_info__ ().build_features.JAVA
 %! msg = javachk ("desktop");
 %! assert (msg.message, "javachk: this function is not supported, Octave was not compiled with Java support");
 %! assert (msg.identifier, "Octave:javachk:java-not-supported");
@@ -158,7 +158,7 @@
 %! assert (javachk ("jvm"), stnul);
 
 ## Test input validation
-%!error javachk ()
-%!error javachk (1)
+%!error <Invalid call> javachk ()
+%!error <FEATURE must be a string> javachk (1)
 %!error javachk ("jvm", 2)
 %!error javachk ("jvm", "feature", "ok")
--- a/scripts/java/javaclasspath.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/java/javaclasspath.m	Sun May 16 09:44:35 2021 +0200
@@ -62,10 +62,6 @@
 
 function [path1, path2] = javaclasspath (what = "")
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   ## dynamic classpath
   dynamic_path = javaMethod ("getClassPath", "org.octave.ClassHelper");
   dynamic_path_list = ostrsplit (dynamic_path, pathsep ());
--- a/scripts/java/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/java/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/javaArray.m \
   %reldir%/java_get.m \
   %reldir%/java_set.m \
--- a/scripts/java/usejava.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/java/usejava.m	Sun May 16 09:44:35 2021 +0200
@@ -54,7 +54,7 @@
 
 function retval = usejava (feature)
 
-  if (nargin != 1 || ! ischar (feature))
+  if (nargin < 1 || ! ischar (feature))
     print_usage ();
   endif
 
@@ -92,7 +92,6 @@
 %! assert (usejava ("jvm"), true);
 
 ## Test input validation
-%!error usejava ()
-%!error usejava (1, 2)
-%!error usejava (1)
+%!error <Invalid call> usejava ()
+%!error <Invalid call> usejava (1)
 %!error <unrecognized FEATURE> usejava ("abc")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/legacy/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/legacy/@inline/argnames.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/@inline/argnames.m	Sun May 16 09:44:35 2021 +0200
@@ -32,7 +32,7 @@
 
 function args = argnames (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/legacy/@inline/char.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/@inline/char.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function expr = char (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/legacy/@inline/formula.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/@inline/formula.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function expr = formula (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/legacy/@inline/vectorize.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/@inline/vectorize.m	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
 
 function fcn = vectorize (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/legacy/findstr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/findstr.m	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
              "findstr is obsolete; use strfind instead\n");
   endif
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -157,6 +157,6 @@
 %!assert (findstr ("aba", "abababa", 0), [1, 5])
 
 ## Test input validation
-%!error findstr ()
-%!error findstr ("foo", "bar", 3, 4)
+%!error <Invalid call> findstr ()
+%!error <Invalid call> findstr ("str1")
 %!error <must have only one non-singleton dimension> findstr (["AB" ; "CD"], "C")
--- a/scripts/legacy/flipdim.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/flipdim.m	Sun May 16 09:44:35 2021 +0200
@@ -40,4 +40,5 @@
   endif
 
   y = flip (varargin{:});
+
 endfunction
--- a/scripts/legacy/genvarname.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/genvarname.m	Sun May 16 09:44:35 2021 +0200
@@ -114,7 +114,7 @@
              "genvarname is obsolete; use matlab.lang.makeValidName or matlab.lang.makeUniqueStrings instead\n");
   endif
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -227,8 +227,7 @@
 %!assert (genvarname ("x", {"a", "b"; "x", "d"}), "x1")
 
 ## Test input validation
-%!error genvarname ()
-%!error genvarname (1,2,3)
+%!error <Invalid call> genvarname ()
 %!error <more than one STR is given, it must be a cellstr> genvarname (char ("a", "b", "c"))
 %!error <STR must be a string or cellstr> genvarname (1)
 %!error <more than one exclusion is given, it must be a cellstr> genvarname ("x", char ("a", "b", "c"))
--- a/scripts/legacy/isdir.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/isdir.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
              "isdir is obsolete; use isfolder or dir_in_loadpath instead\n");
   endif
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -69,5 +69,4 @@
 %!assert (isdir (pwd ()))
 %!assert (! isdir (tempname ()))
 
-%!error isdir ()
-%!error isdir (1, 2)
+%!error <Invalid call> isdir ()
--- a/scripts/legacy/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__vectorize__.m \
   %reldir%/findstr.m \
   %reldir%/flipdim.m \
--- a/scripts/legacy/setstr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/setstr.m	Sun May 16 09:44:35 2021 +0200
@@ -7,19 +7,21 @@
 ##
 ## This file is part of Octave.
 ##
-## Octave is free software; you can redistribute it and/or modify it
+## Octave is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or (at
-## your option) any later version.
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
 ##
 ## Octave is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with Octave; see the file COPYING.  If not, see
-## <http://www.gnu.org/licenses/>.
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
 
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{s} =} setstr (@var{x})
--- a/scripts/legacy/strmatch.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/strmatch.m	Sun May 16 09:44:35 2021 +0200
@@ -71,7 +71,7 @@
              "strmatch is obsolete; use strncmp or strcmp instead\n");
   endif
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -162,7 +162,7 @@
 ## Test input validation
 %!error <Invalid call to strmatch> strmatch ()
 %!error <Invalid call to strmatch> strmatch ("a")
-%!error <Invalid call to strmatch> strmatch ("a", "aaa", "exact", 1)
+%!error <called with too many inputs> strmatch ("a", "aaa", "exact", 1)
 %!error <S must contain only one string> strmatch ({"a", "b"}, "aaa")
 %!error <S must be a string> strmatch (1, "aaa")
 %!error <S must be a string> strmatch (char ("a", "bb"), "aaa")
--- a/scripts/legacy/strread.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/strread.m	Sun May 16 09:44:35 2021 +0200
@@ -163,14 +163,14 @@
 ## @item @qcode{"whitespace"}
 ## Any character in @var{value} will be interpreted as whitespace and trimmed;
 ## the string defining whitespace must be enclosed in double quotes for proper
-## processing of special characters like @qcode{"@xbackslashchar{}t"}.  In
+## processing of special characters like @qcode{"@backslashchar{}t"}.  In
 ## each data field, multiple consecutive whitespace characters are collapsed
 ## into one space and leading and trailing whitespace is removed.  The default
 ## value for whitespace is
 ## @c Note: the next line specifically has a newline which generates a space
 ## @c       in the output of qcode, but keeps the next line < 80 characters.
 ## @qcode{"
-## @xbackslashchar{}b@xbackslashchar{}r@xbackslashchar{}n@xbackslashchar{}t"}
+## @backslashchar{}b@backslashchar{}r@backslashchar{}n@backslashchar{}t"}
 ## (note the space).  Whitespace is always added to the set of delimiter
 ## characters unless at least one @qcode{"%s"} format conversion specifier is
 ## supplied; in that case only whitespace explicitly specified in
@@ -186,11 +186,11 @@
 ## the last character of @var{str}:
 ##
 ## @table @asis
-## @item last character = @qcode{"@xbackslashchar{}n"}
+## @item last character = @qcode{"@backslashchar{}n"}
 ## Data columns are padded with empty fields or NaN so that all columns have
 ## equal length
 ##
-## @item last character is not @qcode{"@xbackslashchar{}n"}
+## @item last character is not @qcode{"@backslashchar{}n"}
 ## Data columns are not padded; strread returns columns of unequal length
 ##
 ## @end table
@@ -354,7 +354,7 @@
     ## Check for unsupported format specifiers
     errpat = '(\[.*\]|[cq]|[nfdu]8|[nfdu]16|[nfdu]32|[nfdu]64)';
     if (! all (cellfun ("isempty", regexp (fmt_words(idy2), errpat))))
-      error ("strread: %q, %c, %[] or bit width format specifiers are not supported yet.");
+      error ("strread: %q, %c, %[] or bit width format specifiers are not supported yet");
     endif
 
     ## Format conversion specifiers following literals w/o space/delim
--- a/scripts/legacy/textread.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/textread.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 ##
 ## @item @qcode{"endofline"}:
 ## Specify a single character or
-## @qcode{"@xbackslashchar{}r@xbackslashchar{}n"}.  If no value is given, it
+## @qcode{"@backslashchar{}r@backslashchar{}n"}.  If no value is given, it
 ## will be inferred from the file.  If set to @qcode{""} (empty string) EOLs
 ## are ignored as delimiters.
 ## @end itemize
@@ -346,7 +346,7 @@
 ## Read multiple lines using empty format string
 %!test
 %! f = tempname ();
-%! unlink (f);
+%! sts = unlink (f);
 %! fid = fopen (f, "w");
 %! d = rand (1, 4);
 %! fprintf (fid, "  %f %f   %f  %f ", d);
@@ -358,7 +358,7 @@
 ## Empty format, corner case = one line w/o EOL
 %!test
 %! f = tempname ();
-%! unlink (f);
+%! sts = unlink (f);
 %! fid = fopen (f, "w");
 %! d = rand (1, 4);
 %! fprintf (fid, "  %f %f   %f  %f ", d);
--- a/scripts/legacy/vectorize.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/legacy/vectorize.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
              "vectorize is unreliable; its use is strongly discouraged\n");
   endif
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -68,8 +68,10 @@
   else
     error ("vectorize: FUN must be a string or anonymous function handle");
   endif
+
 endfunction
 
+
 %!assert (vectorize ("x.^2 + 1"), "x.^2 + 1")
 %!test
 %! fh = @(x) x.^2 + 1;
@@ -91,7 +93,5 @@
 %! assert (finfo.function, "@(x) 2 .^ x .^ 5");
 
 ## Test input validation
-%!error vectorize ()
-%!error vectorize (1, 2)
+%!error <Invalid call> vectorize ()
 %!error <FUN must be a string or anonymous function handle> vectorize (1)
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/linear-algebra/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/linear-algebra/bandwidth.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/bandwidth.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function [lower, upper] = bandwidth (A, type)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -108,8 +108,7 @@
 %! assert ([a,b], [4,4]);
 
 ## Test input validation
-%!error bandwidth ()
-%!error bandwidth (1,2,3)
+%!error <Invalid call> bandwidth ()
 %!error <A must be a 2-D numeric or logical> bandwidth ("string", "lower")
 %!error <A must be a 2-D numeric or logical> bandwidth (ones (3,3,3), "lower")
 %!error <TYPE must be "lower" or "upper"> bandwidth (ones (2), "uper")
--- a/scripts/linear-algebra/commutation_matrix.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/commutation_matrix.m	Sun May 16 09:44:35 2021 +0200
@@ -76,7 +76,7 @@
 
 function k = commutation_matrix (m, n)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   else
     if (! (isscalar (m) && m == fix (m) && m > 0))
--- a/scripts/linear-algebra/cond.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/cond.m	Sun May 16 09:44:35 2021 +0200
@@ -39,8 +39,8 @@
 ##
 ## By default, @code{@var{p} = 2} is used which implies a (relatively slow)
 ## singular value decomposition.  Other possible selections are
-## @code{@var{p} = 1, Inf, "fro"} which are generally faster.  See @code{norm}
-## for a full discussion of possible @var{p} values.
+## @code{@var{p} = 1, Inf, "fro"} which are generally faster.  For a full
+## discussion of possible @var{p} values, @pxref{XREFnorm,,@code{norm}}.
 ##
 ## The condition number of a matrix quantifies the sensitivity of the matrix
 ## inversion operation when small changes are made to matrix elements.  Ideally
@@ -53,7 +53,7 @@
 
 function retval = cond (A, p = 2)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -95,8 +95,7 @@
 %!assert (cond ([1, 2; 2, 1]), 3, sqrt (eps))
 %!assert (cond ([1, 2, 3; 4, 5, 6; 7, 8, 9]) > 1.0e+16)
 
-%!error cond ()
-%!error cond (1, 2, 3)
+%!error <Invalid call> cond ()
 %!error <A must be a 2-D matrix> cond (ones (1,3,3))
 %!error <A must not contain Inf or NaN value> cond ([1, 2;Inf 4])
 %!error <A must not contain Inf or NaN value> cond ([1, 2;NaN 4])
--- a/scripts/linear-algebra/condeig.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/condeig.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 
 function [v, lambda, c] = condeig (a)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -134,12 +134,11 @@
 %! assert (lambda, expected_lambda, 0.001);
 %! assert (c, expected_c, 0.001);
 
-# Test empty input
+## Test empty input
 %!assert (condeig ([]), [])
 
 ## Test input validation
-%!error condeig ()
-%!error condeig (1,2)
+%!error <Invalid call> condeig ()
 %!error <A must be a square numeric matrix> condeig ({1})
 %!error <A must be a square numeric matrix> condeig (ones (3,2))
 %!error <A must be a square numeric matrix> condeig (ones (2,2,2))
--- a/scripts/linear-algebra/condest.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/condest.m	Sun May 16 09:44:35 2021 +0200
@@ -26,8 +26,12 @@
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{cest} =} condest (@var{A})
 ## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{t})
-## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{solvefun}, @var{t}, @var{p1}, @var{p2}, @dots{})
-## @deftypefnx {} {@var{cest} =} condest (@var{Afcn}, @var{solvefun}, @var{t}, @var{p1}, @var{p2}, @dots{})
+## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{Ainvfcn})
+## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{Ainvfcn}, @var{t})
+## @deftypefnx {} {@var{cest} =} condest (@var{A}, @var{Ainvfcn}, @var{t}, @var{p1}, @var{p2}, @dots{})
+## @deftypefnx {} {@var{cest} =} condest (@var{Afcn}, @var{Ainvfcn})
+## @deftypefnx {} {@var{cest} =} condest (@var{Afcn}, @var{Ainvfcn}, @var{t})
+## @deftypefnx {} {@var{cest} =} condest (@var{Afcn}, @var{Ainvfcn}, @var{t}, @var{p1}, @var{p2}, @dots{})
 ## @deftypefnx {} {[@var{cest}, @var{v}] =} condest (@dots{})
 ##
 ## Estimate the 1-norm condition number of a square matrix @var{A} using
@@ -35,54 +39,56 @@
 ##
 ## The optional input @var{t} specifies the number of test vectors (default 5).
 ##
-## If the matrix is not explicit, e.g., when estimating the condition number of
-## @var{A} given an LU@tie{}factorization, @code{condest} uses the following
-## functions:
+## The input may be a matrix @var{A} (the algorithm is particularly
+## appropriate for large, sparse matrices).  Alternatively, the behavior of
+## the matrix can be defined implicitly by functions.  When using an implicit
+## definition, @code{condest} requires the following functions:
 ##
 ## @itemize @minus
-## @item @var{Afcn} which must return
+## @item @code{@var{Afcn} (@var{flag}, @var{x})} which must return
 ##
 ## @itemize @bullet
 ## @item
-## the dimension @var{n} of @var{a}, if @var{flag} is @qcode{"dim"}
+## the dimension @var{n} of @var{A}, if @var{flag} is @qcode{"dim"}
 ##
 ## @item
-## true if @var{a} is a real operator, if @var{flag} is @qcode{"real"}
+## true if @var{A} is a real operator, if @var{flag} is @qcode{"real"}
 ##
 ## @item
-## the result @code{@var{a} * @var{x}}, if @var{flag} is "notransp"
+## the result @code{@var{A} * @var{x}}, if @var{flag} is "notransp"
 ##
 ## @item
-## the result @code{@var{a}' * @var{x}}, if @var{flag} is "transp"
+## the result @code{@var{A}' * @var{x}}, if @var{flag} is "transp"
 ## @end itemize
 ##
-## @item @var{solvefun} which must return
+## @item @code{@var{Ainvfcn} (@var{flag}, @var{x})} which must return
 ##
 ## @itemize @bullet
 ## @item
-## the dimension @var{n} of @var{a}, if @var{flag} is @qcode{"dim"}
+## the dimension @var{n} of @code{inv (@var{A})}, if @var{flag} is
+## @qcode{"dim"}
 ##
 ## @item
-## true if @var{a} is a real operator, if @var{flag} is @qcode{"real"}
+## true if @code{inv (@var{A})} is a real operator, if @var{flag} is
+## @qcode{"real"}
 ##
 ## @item
-## the result @code{@var{a} \ @var{x}}, if @var{flag} is "notransp"
+## the result @code{inv (@var{A}) * @var{x}}, if @var{flag} is "notransp"
 ##
 ## @item
-## the result @code{@var{a}' \ @var{x}}, if @var{flag} is "transp"
+## the result @code{inv (@var{A})' * @var{x}}, if @var{flag} is "transp"
 ## @end itemize
 ## @end itemize
 ##
-## The parameters @var{p1}, @var{p2}, @dots{} are arguments of
+## Any parameters @var{p1}, @var{p2}, @dots{} are additional arguments of
 ## @code{@var{Afcn} (@var{flag}, @var{x}, @var{p1}, @var{p2}, @dots{})}
-## and @code{@var{solvefcn} (@var{flag}, @var{x}, @var{p1}, @var{p2},
-## @dots{})}.
+## and @code{@var{Ainvfcn} (@var{flag}, @var{x}, @var{p1}, @var{p2}, @dots{})}.
 ##
 ## The principal output is the 1-norm condition number estimate @var{cest}.
 ##
-## The optional second output is an approximate null vector when @var{cest} is
-## large; it satisfies the equation
-## @code{norm (A*v, 1) == norm (A, 1) * norm (@var{v}, 1) / @var{est}}.
+## The optional second output @var{v} is an approximate null vector; it
+## satisfies the equation @code{norm (@var{A}*@var{v}, 1) ==
+## norm (@var{A}, 1) * norm (@var{v}, 1) / @var{cest}}.
 ##
 ## Algorithm Note: @code{condest} uses a randomized algorithm to approximate
 ## the 1-norms.  Therefore, if consistent results are required, the
@@ -104,7 +110,7 @@
 ## Pseudospectra}.  @url{https://citeseer.ist.psu.edu/223007.html}
 ## @end itemize
 ##
-## @seealso{cond, norm, normest1, normest}
+## @seealso{cond, rcond, norm, normest1, normest}
 ## @end deftypefn
 
 ## Code originally licensed under:
@@ -142,10 +148,6 @@
 ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 ## SUCH DAMAGE.
 
-## Author: Jason Riedy <ejr@cs.berkeley.edu>
-## Keywords: linear-algebra norm estimation
-## Version: 0.2
-
 function [cest, v] = condest (varargin)
 
   if (nargin < 1 || nargin > 6)
@@ -154,8 +156,8 @@
 
   have_A = false;
   have_t = false;
-  have_apply_normest1 = false;
-  have_solve_normest1 = false;
+  have_Afcn = false;
+  have_Ainvfcn = false;
 
   if (isnumeric (varargin{1}))
     A = varargin{1};
@@ -166,8 +168,8 @@
     n = rows (A);
     if (nargin > 1)
       if (is_function_handle (varargin{2}))
-        solve = varargin{2};
-        have_solve_normest1 = true;
+        Ainvfcn = varargin{2};
+        have_Ainvfcn = true;
         if (nargin > 2)
           t = varargin{3};
           have_t = true;
@@ -175,23 +177,20 @@
       else
         t = varargin{2};
         have_t = true;
-        real_op = isreal (A);
       endif
-    else
-      real_op = isreal (A);
     endif
   elseif (is_function_handle (varargin{1}))
     if (nargin == 1)
-      error("condest: must provide SOLVEFCN when using AFCN");
+      error ("condest: must provide AINVFCN when using AFCN");
     endif
-    apply = varargin{1};
-    have_apply_normest1 = true;
+    Afcn = varargin{1};
+    have_Afcn = true;
     if (! is_function_handle (varargin{2}))
-      error("condest: SOLVEFCN must be a function handle");
+      error ("condest: AINVFCN must be a function handle");
     endif
-    solve = varargin{2};
-    have_solve_normest1 = true;
-    n = apply ("dim", [], varargin{4:end});
+    Ainvfcn = varargin{2};
+    have_Ainvfcn = true;
+    n = Afcn ("dim", [], varargin{4:end});
     if (nargin > 2)
       t = varargin{3};
       have_t = true;
@@ -207,99 +206,131 @@
   ## Disable warnings which may be emitted during calculation process.
   warning ("off", "Octave:nearly-singular-matrix", "local");
 
-  if (! have_solve_normest1)
-    ## prepare solve in normest1 form
+  if (! have_Ainvfcn)
+    ## Prepare Ainvfcn in normest1 form
     if (issparse (A))
-      [L, U, P, Pc] = lu (A);
-      solve = @(flag, x) solve_sparse (flag, x, n, real_op, L, U, P, Pc);
+      [L, U, P, Q] = lu (A);
+      Ainvfcn = @inv_sparse_fcn;
     else
       [L, U, P] = lu (A);
-      solve = @(flag, x) solve_not_sparse (flag, x, n, real_op, L, U, P);
+      Q = [];
+      Ainvfcn = @inv_full_fcn;
     endif
 
-    ## Check for singular matrices before continuing
+    ## Check for singular matrices before continuing (bug #46737)
     if (any (diag (U) == 0))
       cest = Inf;
       v = [];
       return;
     endif
+
+    ## Initialize solver
+    Ainvfcn ("init", A, L, U, P, Q);
+    clear L U P Q;
   endif
 
   if (have_A)
     Anorm = norm (A, 1);
   else
-    Anorm = normest1 (apply, t, [], varargin{4:end});
+    Anorm = normest1 (Afcn, t, [], varargin{4:end});
   endif
-  [Ainv_norm, v, w] = normest1 (solve, t, [], varargin{4:end});
+  [Ainv_norm, v, w] = normest1 (Ainvfcn, t, [], varargin{4:end});
 
   cest = Anorm * Ainv_norm;
   if (isargout (2))
     v = w / norm (w, 1);
   endif
 
+  if (! have_Ainvfcn)
+    Ainvfcn ("clear");  # clear persistent memory in subfunction
+  endif
+
 endfunction
 
-function value = solve_sparse (flag, x, n, real_op, L , U , P , Pc)
-  ## FIXME: Sparse algorithm is less accurate than full matrix version
-  ##        See BIST test for non-orthogonal matrix where relative tolerance
+function retval = inv_sparse_fcn (flag, x, varargin)
+  ## FIXME: Sparse algorithm is less accurate than full matrix version.
+  ##        See BIST test for asymmetric matrix where relative tolerance
   ##        of 1e-12 is used for sparse, but 4e-16 for full matrix.
+  ##        BUT, does it really matter for an "estimate"?
+  persistent Ainv Ainvt n isreal_op;
+
   switch (flag)
     case "dim"
-      value = n;
+      retval = n;
     case "real"
-      value = real_op;
+      retval = isreal_op;
     case "notransp"
-      value = Pc' * (U \ (L \ (P * x)));
+      retval = Ainv * x;
     case "transp"
-      value = P' * (L' \ (U' \ (Pc * x)));
+      retval = Ainvt * x;
+    case "init"
+      n = rows (x);
+      isreal_op = isreal (x);
+      [L, U, P, Q] = deal (varargin{1:4});
+      Ainv = Q * (U \ (L \ P));
+      Ainvt = P' * (L' \ (U' \ Q'));
+    case "clear"  # called to free memory at end of condest function
+      clear Ainv Ainvt n isreal_op;
   endswitch
+
 endfunction
 
-function value = solve_not_sparse (flag, x, n, real_op, L, U, P)
+function retval = inv_full_fcn (flag, x, varargin)
+  persistent Ainv Ainvt n isreal_op;
+
   switch (flag)
     case "dim"
-      value = n;
+      retval = n;
     case "real"
-      value = real_op;
+      retval = isreal_op;
     case "notransp"
-      value = U \ (L \ (P * x));
+      retval = Ainv * x;
     case "transp"
-      value = P' * (L' \ (U' \ x));
+      retval = Ainvt \ x;
+    case "init"
+      n = rows (x);
+      isreal_op = isreal (x);
+      [L, U, P] = deal (varargin{1:3});
+      Ainv = U \ (L \ P);
+      Ainvt = P' * (L' \ U');
+    case "clear"  # called to free memory at end of condest function
+      clear Ainv Ainvt n isreal_op;
   endswitch
+
 endfunction
 
 
 ## Note: These test bounds are very loose.  There is enough randomization to
 ## trigger odd cases with hilb().
 
-%!function value = apply_fun (flag, x, A, m)
+%!function retval = __Afcn__ (flag, x, A, m)
 %!  if (nargin == 3)
 %!    m = 1;
 %!  endif
 %!  switch (flag)
 %!    case "dim"
-%!      value = length (A);
+%!      retval = length (A);
 %!    case "real"
-%!      value = isreal (A);
+%!      retval = isreal (A);
 %!    case "notransp"
-%!      value = x; for i = 1:m, value = A * value;, endfor
+%!      retval = x; for i = 1:m, retval = A * retval;, endfor
 %!    case "transp"
-%!      value = x; for i = 1:m, value = A' * value;, endfor
+%!      retval = x; for i = 1:m, retval = A' * retval;, endfor
 %!  endswitch
 %!endfunction
-%!function value = solve_fun (flag, x, A, m)
+%!function retval = __Ainvfcn__ (flag, x, A, m)
 %!  if (nargin == 3)
 %!    m = 1;
 %!  endif
 %!  switch (flag)
 %!    case "dim"
-%!      value = length (A);
+%!      retval = length (A);
 %!    case "real"
-%!      value = isreal (A);
+%!      retval = isreal (A);
 %!    case "notransp"
-%!      value = x; for i = 1:m, value = A \ value;, endfor
+%!      retval = x; for i = 1:m, retval = A \ retval;, endfor
 %!    case "transp"
-%!      value = x; for i = 1:m, value = A' \ value;, endfor
+%!      retval = x; for i = 1:m, retval = A' \ retval;, endfor
 %!  endswitch
 %!endfunction
 
@@ -320,25 +351,25 @@
 %!test
 %! N = 6;
 %! A = hilb (N);
-%! solve = @(flag, x) solve_fun (flag, x, A);
-%! cA = condest (A, solve);
+%! Ainvfcn = @(flag, x) __Ainvfcn__ (flag, x, A);
+%! cA = condest (A, Ainvfcn);
 %! cA_test = norm (inv (A), 1) * norm (A, 1);
 %! assert (cA, cA_test, -2^-6);
 
 %!test
 %! N = 6;
 %! A = hilb (N);
-%! apply = @(flag, x) apply_fun (flag, x, A);
-%! solve = @(flag, x) solve_fun (flag, x, A);
-%! cA = condest (apply, solve);
+%! Afcn = @(flag, x) __Afcn__ (flag, x, A);
+%! Ainvfcn = @(flag, x) __Ainvfcn__ (flag, x, A);
+%! cA = condest (Afcn, Ainvfcn);
 %! cA_test = norm (inv (A), 1) * norm (A, 1);
 %! assert (cA, cA_test, -2^-6);
 
-%!test # parameters for apply and solve functions
+%!test # parameters for apply and Ainvfcn functions
 %! N = 6;
 %! A = hilb (N);
 %! m = 2;
-%! cA = condest (@apply_fun, @solve_fun, [], A, m);
+%! cA = condest (@__Afcn__, @__Ainvfcn__, [], A, m);
 %! cA_test = norm (inv (A^2), 1) * norm (A^2, 1);
 %! assert (cA, cA_test, -2^-6);
 
@@ -351,7 +382,7 @@
 %! assert (cest, Inf);
 %! assert (v, []);
 
-## Test non-orthogonal matrices
+## Test asymmetric matrices
 %!test <*57968>
 %! A = reshape (sqrt (0:15), 4, 4);
 %! cexp = norm (A, 1) * norm (inv (A), 1);
@@ -365,9 +396,9 @@
 %! assert (cest, cexp, -1e-12);
 
 ## Test input validation
-%!error condest ()
-%!error condest (1,2,3,4,5,6,7)
-%!error <A must be square> condest ([1 2])
-%!error <must provide SOLVEFCN when using AFCN> condest (@sin)
-%!error <SOLVEFCN must be a function handle> condest (@sin, 1)
+%!error <Invalid call> condest ()
+%!error <Invalid call> condest (1,2,3,4,5,6,7)
+%!error <A must be square> condest ([1, 2])
+%!error <must provide AINVFCN when using AFCN> condest (@sin)
+%!error <AINVFCN must be a function handle> condest (@sin, 1)
 %!error <argument must be a square matrix or function handle> condest ({1})
--- a/scripts/linear-algebra/cross.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/cross.m	Sun May 16 09:44:35 2021 +0200
@@ -50,7 +50,7 @@
 
 function z = cross (x, y, dim)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -119,5 +119,8 @@
 %! assert (cross (x, y, 2), r, 2e-8);
 %! assert (cross (x, y, 1), -r, 2e-8);
 
-%!error cross (0,0)
-%!error cross ()
+## Test input validation
+%!error <Invalid call> cross ()
+%!error <Invalid call> cross (1)
+## FIXME: Need tests for other error() conditions and warning() calls.
+%!error <must have at least one dimension with 3 elements> cross (0,0)
--- a/scripts/linear-algebra/duplication_matrix.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/duplication_matrix.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 
 function d = duplication_matrix (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -118,7 +118,7 @@
 %! assert (D * vech (B), vec (B), 1e-6);
 %! assert (D * vech (C), vec (C), 1e-6);
 
-%!error duplication_matrix ()
+%!error <Invalid call> duplication_matrix ()
 %!error duplication_matrix (0.5)
 %!error duplication_matrix (-1)
 %!error duplication_matrix (ones (1,4))
--- a/scripts/linear-algebra/expm.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/expm.m	Sun May 16 09:44:35 2021 +0200
@@ -81,7 +81,7 @@
 
 function r = expm (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -103,7 +103,7 @@
   n = rows (A);
   id = eye (n);
   ## Trace reduction.
-  A(A == -Inf) = -realmax;
+  A(A == -Inf) = -realmax ();
   trshift = trace (A) / n;
   if (trshift > 0)
     A -= trshift * id;
@@ -157,7 +157,6 @@
 %!assert (full (expm (10*eye (3))), expm (full (10*eye (3))), 8*eps)
 
 ## Test input validation
-%!error expm ()
-%!error expm (1, 2)
+%!error <Invalid call> expm ()
 %!error <expm: A must be a square matrix> expm ({1})
 %!error <expm: A must be a square matrix> expm ([1 0;0 1; 2 2])
--- a/scripts/linear-algebra/gls.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/gls.m	Sun May 16 09:44:35 2021 +0200
@@ -155,10 +155,9 @@
 %! assert (gls (y,x,o), [3; 2], 50*eps);
 
 ## Test input validation
-%!error gls ()
-%!error gls (1)
-%!error gls (1, 2)
-%!error gls (1, 2, 3, 4)
+%!error <Invalid call> gls ()
+%!error <Invalid call> gls (1)
+%!error <Invalid call> gls (1, 2)
 %!error gls ([true, true], [1, 2], ones (2))
 %!error gls ([1, 2], [true, true], ones (2))
 %!error gls ([1, 2], [1, 2], true (2))
--- a/scripts/linear-algebra/housh.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/housh.m	Sun May 16 09:44:35 2021 +0200
@@ -133,5 +133,6 @@
 %! assert (r, d, 2e-8);
 %! assert (z, 0, 2e-8);
 
-%!error housh ([0])
-%!error housh ()
+%!error <Invalid call> housh ()
+%!error <Invalid call> housh (1)
+%!error <Invalid call> housh (1,2)
--- a/scripts/linear-algebra/isbanded.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/isbanded.m	Sun May 16 09:44:35 2021 +0200
@@ -69,9 +69,9 @@
 
 %!assert (isbanded ([1, 1],1,1))
 %!assert (isbanded ([1; 1],1,1))
-%!assert (isbanded (eye(10),0,0))
-%!assert (isbanded (eye(10),1,1))
-%!assert (isbanded (i*eye(10),1,1))
+%!assert (isbanded (eye (10),0,0))
+%!assert (isbanded (eye (10),1,1))
+%!assert (isbanded (i*eye (10),1,1))
 %!assert (isbanded (logical (eye (10)),1,1))
 
 %! A = [2 3 0 0 0; 1 2 3 0 0; 0 1 2 3 0; 0 0 1 2 3; 0 0 0 1 2];
@@ -80,10 +80,9 @@
 %! assert (! isbanded (A,1,0));
 
 ## Test input validation
-%!error isbanded ()
-%!error isbanded (1)
-%!error isbanded (1,2)
-%!error isbanded (1,2,3,4)
+%!error <Invalid call> isbanded ()
+%!error <Invalid call> isbanded (1)
+%!error <Invalid call> isbanded (1,2)
 %!error <LOWER and UPPER must be non-negative> isbanded (1, -1, 1)
 %!error <LOWER and UPPER must be non-negative> isbanded (1, 1, -1)
 %!error <LOWER and UPPER must be non-negative> isbanded (1, {1}, 1)
--- a/scripts/linear-algebra/isdefinite.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/isdefinite.m	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 
 function retval = isdefinite (A, tol)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -103,8 +103,7 @@
 
 %!assert (! isdefinite (magic (3)))
 
-%!error isdefinite ()
-%!error isdefinite (1,2,3)
+%!error <Invalid call> isdefinite ()
 %!error <TOL must be a scalar .= 0> isdefinite (1, {1})
 %!error <TOL must be a scalar .= 0> isdefinite (1, [1 1])
 %!error <TOL must be a scalar .= 0> isdefinite (1, -1)
--- a/scripts/linear-algebra/isdiag.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/isdiag.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function retval = isdiag (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -60,5 +60,4 @@
 %!assert (isdiag (diag (1:10)))
 
 ## Test input validation
-%!error isdiag ()
-%!error isdiag (1,2)
+%!error <Invalid call> isdiag ()
--- a/scripts/linear-algebra/ishermitian.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/ishermitian.m	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
 
 function retval = ishermitian (A, skewopt = "nonskew", tol = 0)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -133,8 +133,7 @@
 %! assert (! ishermitian (s));
 
 ## Test input validation
-%!error ishermitian ()
-%!error ishermitian (1,2,3,4)
+%!error <Invalid call> ishermitian ()
 %!error <second argument must be> ishermitian (1, {"skew"})
 %!error <SKEWOPT must be 'skew' or 'nonskew'> ishermitian (1, "foobar")
 %!error <SKEWOPT must be 'skew' or 'nonskew'> ishermitian (1, "foobar")
--- a/scripts/linear-algebra/issymmetric.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/issymmetric.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 
 function retval = issymmetric (A, skewopt = "nonskew", tol = 0)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -66,9 +66,8 @@
   endif
 
   ## Validate inputs
-  retval = (isnumeric (A) || islogical (A)) && issquare (A);
-  if (! retval)
-    return;
+  if (! (isnumeric (A) || islogical (A) || ischar (A)))
+    error ("issymmetric: A must be a numeric, logical, or character matrix");
   endif
 
   if (! (strcmp (skewopt, "skew") || strcmp (skewopt, "nonskew")))
@@ -79,13 +78,18 @@
     error ("issymmetric: TOL must be a scalar >= 0");
   endif
 
+  if (! issquare (A))
+    retval = false;
+    return;
+  endif
+
   ## Calculate symmetry
   if (strcmp (skewopt, "nonskew"))
     if (tol == 0)
       ## check for exact symmetry
       retval = full (! any ((A != A.')(:)));
     else
-      if (islogical (A))
+      if (! isnumeric (A))
         ## Hack to allow norm to work.  Choose single to minimize memory.
         A = single (A);
       endif
@@ -97,7 +101,7 @@
     if (tol == 0)
       retval = full (! any ((A != -A.')(:)));
     else
-      if (islogical (A))
+      if (! isnumeric (A))
         ## Hack to allow norm to work.  Choose single to minimize memory.
         A = single (A);
       endif
@@ -116,26 +120,21 @@
 %!assert (issymmetric ([1, 2.1; 2, 1.1], 0.2))
 %!assert (issymmetric ([1, 2i; 2i, 1]))
 %!assert (issymmetric (speye (100)), true)  # Return full logical value.
-%!assert (issymmetric (logical (eye (2))))
-%!assert (! issymmetric (logical ([1 1; 0 1])))
-%!assert (issymmetric (logical ([1 1; 0 1]), 0.5))
+%!assert (! issymmetric ([0, 2; -2, 0], "nonskew"))
 %!assert (issymmetric ([0, 2; -2, 0], "skew"))
 %!assert (! issymmetric ([0, 2; -2, eps], "skew"))
 %!assert (issymmetric ([0, 2; -2, eps], "skew", eps))
-
-%!assert (! (issymmetric ("test")))
-%!assert (! (issymmetric ("t")))
-%!assert (! (issymmetric (["te"; "et"])))
-%!assert (! issymmetric ({1}))
-%!test
-%! s.a = 1;
-%! assert (! issymmetric (s));
+%!assert (issymmetric (logical (eye (2))))
+%!assert (! issymmetric (logical ([1 1; 0 1])))
+%!assert (issymmetric (logical ([1 1; 0 1]), 0.5))
+%!assert (! issymmetric ("test"))
+%!assert (issymmetric ("t"))
+%!assert (issymmetric (["te"; "et"]))
 
 ## Test input validation
-%!error issymmetric ()
-%!error issymmetric (1,2,3,4)
+%!error <Invalid call> issymmetric ()
 %!error <second argument must be> issymmetric (1, {"skew"})
-%!error <SKEWOPT must be 'skew' or 'nonskew'> issymmetric (1, "foobar")
+%!error <A must be a numeric,.* matrix> issymmetric ({1})
 %!error <SKEWOPT must be 'skew' or 'nonskew'> issymmetric (1, "foobar")
 %!error <TOL must be a scalar .= 0> issymmetric (1, "skew", {1})
 %!error <TOL must be a scalar .= 0> issymmetric (1, "skew", [1 1])
--- a/scripts/linear-algebra/istril.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/istril.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function retval = istril (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -61,5 +61,4 @@
 %!assert (! istril (randn (10)))
 
 ## Test input validation
-%!error istril ()
-%!error istril (1,2)
+%!error <Invalid call> istril ()
--- a/scripts/linear-algebra/istriu.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/istriu.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function retval = istriu (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -61,5 +61,4 @@
 %!assert (! istriu (randn (10)))
 
 ## Test input validation
-%!error istriu ()
-%!error istriu (1,2)
+%!error <Invalid call> istriu ()
--- a/scripts/linear-algebra/krylov.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/krylov.m	Sun May 16 09:44:35 2021 +0200
@@ -71,7 +71,7 @@
     defeps = 1e-12;
   endif
 
-  if (nargin < 3 || nargin > 5)
+  if (nargin < 3)
     print_usage ();
   elseif (nargin < 5)
     ## Default permutation flag.
@@ -187,7 +187,7 @@
     if ((columns (V) > na) && (length (alpha) == na))
       ## Trim to size.
       V = V(:,1:na);
-    elseif (columns(V) > na)
+    elseif (columns (V) > na)
       krylov_V = V;
       krylov_na = na;
       krylov_length_alpha = length (alpha);
@@ -198,7 +198,7 @@
       ## Construct next Q and multiply.
       Q = zeros (size (V));
       for kk = 1:columns (Q)
-        Q(pivot_vec(nu-columns(Q)+kk),kk) = 1;
+        Q(pivot_vec(nu-columns (Q)+kk),kk) = 1;
       endfor
 
       ## Apply Householder reflections.
@@ -218,7 +218,7 @@
       hv = U(:,i);
       av = alpha(i);
       V -= av*hv*(hv'*V);
-      H(i,nu-columns(V)+(1:columns(V))) = V(pivot_vec(i),:);
+      H(i,nu-columns (V)+(1:columns (V))) = V(pivot_vec(i),:);
     endfor
 
   endwhile
--- a/scripts/linear-algebra/linsolve.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/linsolve.m	Sun May 16 09:44:35 2021 +0200
@@ -77,7 +77,7 @@
 
 function [x, R] = linsolve (A, b, opts)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -141,8 +141,8 @@
 %! opts.TRANSA = true;
 %! assert (linsolve (A, b, opts), A' \ b);
 
-%!error linsolve ()
-%!error linsolve (1)
+%!error <Invalid call> linsolve ()
+%!error <Invalid call> linsolve (1)
 %!error linsolve (1,2,3)
 %!error <A and B must be numeric> linsolve ({1},2)
 %!error <A and B must be numeric> linsolve (1,{2})
--- a/scripts/linear-algebra/logm.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/logm.m	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
 
 function [s, iters] = logm (A, opt_iters = 100)
 
-  if (nargin == 0 || nargin > 2)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -95,7 +95,7 @@
       j(2) = find (tau / 2 <= theta, 1);
       if (j(1) - j(2) <= 1 || p == 2)
         m = j(1);
-        break
+        break;
       endif
     endif
     k += 1;
@@ -182,6 +182,5 @@
 %!assert (logm (expm ([0 1i; -1i 0])), [0 1i; -1i 0], 10 * eps)
 
 ## Test input validation
-%!error logm ()
-%!error logm (1, 2, 3)
+%!error <Invalid call> logm ()
 %!error <logm: A must be a square matrix> logm ([1 0;0 1; 2 2])
--- a/scripts/linear-algebra/lscov.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/lscov.m	Sun May 16 09:44:35 2021 +0200
@@ -60,7 +60,7 @@
 
 function [x, stdx, mse, S] = lscov (A, b, V = [], alg)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -167,9 +167,9 @@
 %! y = Z(:,1); X = [ones(rows(Z),1), Z(:,2:end)];
 %! alpha = 0.05;
 %! [b, stdb, mse] = lscov (X, y);
-%! assert(b, V(:,1), 3e-6);
-%! assert(stdb, V(:,2), -1.e-5);
-%! assert(sqrt (mse), rsd, -1E-6);
+%! assert (b, V(:,1), 3e-6);
+%! assert (stdb, V(:,2), -1.e-5);
+%! assert (sqrt (mse), rsd, -1E-6);
 
 %!test
 %! ## Adapted from example in Matlab documentation
@@ -178,41 +178,41 @@
 %! X = [ones(size(x1)) x1 x2];
 %! y = [.17 .26 .28 .23 .27 .34]';
 %! [b, se_b, mse, S] = lscov(X, y);
-%! assert(b, [0.1203 0.3284 -0.1312]', 1E-4);
-%! assert(se_b, [0.0643 0.2267 0.1488]', 1E-4);
-%! assert(mse, 0.0015, 1E-4);
-%! assert(S, [0.0041 -0.0130 0.0075; -0.0130 0.0514 -0.0328; 0.0075 -0.0328 0.0221], 1E-4);
+%! assert (b, [0.1203 0.3284 -0.1312]', 1E-4);
+%! assert (se_b, [0.0643 0.2267 0.1488]', 1E-4);
+%! assert (mse, 0.0015, 1E-4);
+%! assert (S, [0.0041 -0.0130 0.0075; -0.0130 0.0514 -0.0328; 0.0075 -0.0328 0.0221], 1E-4);
 %! w = [1 1 1 1 1 .1]';
 %! [bw, sew_b, msew] = lscov (X, y, w);
-%! assert(bw, [0.1046 0.4614 -0.2621]', 1E-4);
-%! assert(sew_b, [0.0309 0.1152 0.0814]', 1E-4);
-%! assert(msew, 3.4741e-004, -1E-4);
-%! V = .2*ones(length(x1)) + .8*diag(ones(size(x1)));
+%! assert (bw, [0.1046 0.4614 -0.2621]', 1E-4);
+%! assert (sew_b, [0.0309 0.1152 0.0814]', 1E-4);
+%! assert (msew, 3.4741e-004, -1E-4);
+%! V = .2*ones (length (x1)) + .8*diag (ones (size (x1)));
 %! [bg, sew_b, mseg] = lscov (X, y, V);
-%! assert(bg, [0.1203 0.3284 -0.1312]', 1E-4);
-%! assert(sew_b, [0.0672 0.2267 0.1488]', 1E-4);
-%! assert(mseg, 0.0019, 1E-4);
+%! assert (bg, [0.1203 0.3284 -0.1312]', 1E-4);
+%! assert (sew_b, [0.0672 0.2267 0.1488]', 1E-4);
+%! assert (mseg, 0.0019, 1E-4);
 %! y2 = [y 2*y];
 %! [b2, se_b2, mse2, S2] = lscov (X, y2);
-%! assert(b2, [b 2*b], 2*eps);
-%! assert(se_b2, [se_b 2*se_b], 2*eps);
-%! assert(mse2, [mse 4*mse], eps);
-%! assert(S2(:, :, 1), S, eps);
-%! assert(S2(:, :, 2), 4*S, eps);
+%! assert (b2, [b 2*b], 2*eps);
+%! assert (se_b2, [se_b 2*se_b], 2*eps);
+%! assert (mse2, [mse 4*mse], eps);
+%! assert (S2(:, :, 1), S, eps);
+%! assert (S2(:, :, 2), 4*S, 2*eps);
 
 %!test
 %! ## Artificial example with positive semi-definite weight matrix
 %! x = (0:0.2:2)';
-%! y = round(100*sin(x) + 200*cos(x));
+%! y = round (100*sin (x) + 200*cos (x));
 %! X = [ones(size(x)) sin(x) cos(x)];
-%! V = eye(numel(x));
+%! V = eye (numel (x));
 %! V(end, end-1) = V(end-1, end) = 1;
 %! [b, seb, mseb, S] = lscov (X, y, V);
-%! assert(b, [0 100 200]', 0.2);
+%! assert (b, [0 100 200]', 0.2);
 
-%!error lscov ()
-%!error lscov (1)
-%!error lscov (1,2,3,4,5)
+## Test input validation
+%!error <Invalid call> lscov ()
+%!error <Invalid call> lscov (1)
 %!error <A and B must have the same number of rows> lscov (ones (2,2),1)
 %!warning <algorithm selection input ALG is not yet implemented>
 %! lscov (1,1, [], "chol");
--- a/scripts/linear-algebra/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/bandwidth.m \
   %reldir%/commutation_matrix.m \
   %reldir%/cond.m \
--- a/scripts/linear-algebra/normest.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/normest.m	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,7 @@
 
 function [nest, iter] = normest (A, tol = 1e-6)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -96,8 +96,7 @@
 %! assert (normest (A), norm (A), 1e-6);
 
 ## Test input validation
-%!error normest ()
-%!error normest (1, 2, 3)
+%!error <Invalid call> normest ()
 %!error <A must be a numeric .* matrix> normest ([true true])
 %!error <A must be .* 2-D matrix> normest (ones (3,3,3))
 %!error <TOL must be a real scalar> normest (1, [1, 2])
--- a/scripts/linear-algebra/normest1.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/normest1.m	Sun May 16 09:44:35 2021 +0200
@@ -379,7 +379,7 @@
 %! assert (iscolumn (it));
 
 ## Test input validation
-%!error normest1 ()
+%!error <Invalid call> normest1 ()
 %!error <A must be a square matrix or a function handle> normest1 ({1})
 %!error <A must be a square matrix> normest1 ([1 2])
 %!error <X0 must have 2 columns> normest1 (magic (5), :, [1])
--- a/scripts/linear-algebra/null.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/null.m	Sun May 16 09:44:35 2021 +0200
@@ -24,91 +24,106 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {} null (@var{A})
-## @deftypefnx {} {} null (@var{A}, @var{tol})
-## Return an orthonormal basis of the null space of @var{A}.
+## @deftypefn  {} {@var{Z} =} null (@var{A})
+## @deftypefnx {} {@var{Z} =} null (@var{A}, @var{tol})
+## Return an orthonormal basis @var{Z} of the null space of @var{A}.
 ##
-## The dimension of the null space is taken as the number of singular values of
-## @var{A} not greater than @var{tol}.  If the argument @var{tol} is missing,
-## it is computed as
+## The dimension of the null space @var{Z} is taken as the number of singular
+## values of @var{A} not greater than @var{tol}.  If the argument @var{tol}
+## is missing, it is computed as
 ##
 ## @example
-## max (size (@var{A})) * max (svd (@var{A})) * eps
+## max (size (@var{A})) * max (svd (@var{A}, 0)) * eps
 ## @end example
-## @seealso{orth}
+## @seealso{orth, svd}
 ## @end deftypefn
 
-function retval = null (A, tol)
+function Z = null (A, tol)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (nargin == 2 && strcmp (tol, "r"))
     error ("null: option for rational not yet implemented");
   endif
 
+  [~, S, V] = svd (A, 0);  # Use economy-sized svd if possible.
+
+  ## In case of A = [], zeros (0,X), zeros (X,0) Matlab R2020b seems to
+  ## simply return the nullspace "V" of the svd-decomposition (bug #59630).
   if (isempty (A))
-    if (isa (A, "single"))
-      retval = single ([]);
-    else
-      retval = [];
-    endif
+    Z = V;
   else
-    [U, S, V] = svd (A);
     out_cls = class (V);
 
-    s = diag (S);
+    if (rows (A) > 1)
+      s = diag (S);
+    else
+      s = S.';
+    end
     if (nargin == 1)
-      tol = max (size (A)) * s (1) * eps (out_cls);
+      tol = max (size (A)) * s(1) * eps (out_cls);
     endif
     rank = sum (s > tol);
 
     cols = columns (A);
     if (rank < cols)
-      retval = V(:, rank+1:cols);
-      retval(abs (retval) < eps (out_cls)) = 0;
+      Z = V(:, rank+1:cols);
+      Z(abs (Z) < eps (out_cls)) = 0;
     else
-      retval = zeros (cols, 0, out_cls);
+      Z = zeros (cols, 0, out_cls);
     endif
   endif
 
 endfunction
 
 
-## FIXME: Need some tests for 'single' variables as well
-
-%!test
-%! A = 0;
-%! assert (null (A), 1);
-%! assert (null (single (A)), single (1));
-
-%!test
-%! A = 1;
-%! assert (null (A), zeros (1,0));
+## Exact tests
 
 %!test
-%! A = [1 0; 0 1];
-%! assert (null (A), zeros (2,0));
-%! assert (null (single (A)), zeros (2, 0, "single"))
+%! A = { ...
+%!   [], []; ...
+%!   zeros(1,0), []; ...
+%!   zeros(4,0), []; ...
+%!   zeros(0,1), 1; ...
+%!   zeros(0,4), eye(4); ...
+%!   0, 1; ...
+%!   1, zeros(1,0); ...
+%!   [1 0; 0 1], zeros(2,0); ...
+%!   [1 0; 1 0], [0 1]'; ...
+%! };
+%! for i = 1:size (A, 1)
+%!   assert (null (A{i,1}), A{i,2});
+%!   assert (null (single (A{i,1})), single (A{i,2}));
+%! endfor
+
+
+## Inexact tests
 
 %!test
-%! A = [1 0; 1 0];
-%! assert (null (A), [0 1]');
+%! A = { ...
+%!   [1 1; 0 0], [-1/sqrt(2) 1/sqrt(2)]'; ...
+%! };
+%! for i = 1:size (A, 1)
+%!   assert (null (A{i,1}), A{i,2}, eps);
+%!   assert (null (single (A{i,1})), single (A{i,2}), eps);
+%! endfor
 
-%!test
-%! A = [1 1; 0 0];
-%! assert (null (A), [-1/sqrt(2) 1/sqrt(2)]', eps)
-%! assert (null (single (A)), single ([-1/sqrt(2) 1/sqrt(2)]'), eps)
+
+## Tests with tolerance input
 
 %!test
 %! tol = 1e-4;
-%! A = [1 0; 0 tol-eps];
-%! assert (null (A,tol), [0; 1]);
+%! A = { ...
+%!   @(e) [1 0; 0 tol-e], [0 1]'; ...
+%!   @(e) [1 0; 0 tol+e], zeros(2,0); ...
+%! };
+%! for i = 1:size (A, 1)
+%!   assert (null (A{i,1}(eps ("double")), tol), A{i,2});
+%!   assert (null (single (A{i,1}(eps ("single"))), tol), single (A{i,2}));
+%! endfor
 
-%!test
-%! tol = 1e-4;
-%! A = [1 0; 0 tol+eps];
-%! assert (null (A,tol), zeros (2,0));
+
+## Input tests
 
-%!assert (null ([]), [])
-%!assert (null (single ([])), single ([]))
 %!assert (null (uint8 ([])), [])
+
--- a/scripts/linear-algebra/ols.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/ols.m	Sun May 16 09:44:35 2021 +0200
@@ -183,9 +183,8 @@
 %! assert (b, [1.4, 2], 2*eps);
 
 ## Test input validation
-%!error ols ()
-%!error ols (1)
-%!error ols (1, 2, 3)
+%!error <Invalid call> ols ()
+%!error <Invalid call> ols (1)
 %!error ols ([true, true], [1, 2])
 %!error ols ([1, 2], [true, true])
 %!error ols (ones (2,2,2), ones (2,2))
--- a/scripts/linear-algebra/ordeig.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/ordeig.m	Sun May 16 09:44:35 2021 +0200
@@ -35,17 +35,17 @@
 ## appearance of the matrix @code{@var{A}-@var{lambda}*@var{B}}.  The pair
 ## @var{A}, @var{B} is usually the result of a QZ decomposition.
 ##
-## @seealso{ordschur, eig, schur, qz}
+## @seealso{ordschur, ordqz, eig, schur, qz}
 ## @end deftypefn
 
 function lambda = ordeig (A, B)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
   if (! isnumeric (A) || ! issquare (A))
-    error ("ordeig: A must be a square matrix")
+    error ("ordeig: A must be a square matrix");
   endif
 
   n = length (A);
@@ -53,7 +53,7 @@
   if (nargin == 1)
     B = eye (n);
     if (isreal (A))
-      if (! isquasitri (A))
+      if (! is_quasitri (A))
         error ("ordeig: A must be quasi-triangular (i.e., upper block triangular with 1x1 or 2x2 blocks on the diagonal)");
       endif
     else
@@ -68,7 +68,7 @@
       error ("ordeig: A and B must be the same size");
     endif
     if (isreal (A) && isreal (B))
-      if (! isquasitri (A) || ! isquasitri (B))
+      if (! is_quasitri (A) || ! is_quasitri (B))
         error ("ordeig: A and B must be quasi-triangular (i.e., upper block triangular with 1x1 or 2x2 blocks on the diagonal)");
       endif
     else
@@ -106,7 +106,7 @@
 endfunction
 
 ## Check whether a matrix is quasi-triangular
-function retval = isquasitri (A)
+function retval = is_quasitri (A)
   if (length (A) <= 2)
     retval = true;
   else
@@ -140,8 +140,7 @@
 %! assert (lambda, 3);
 
 ## Test input validation
-%!error ordeig ()
-%!error ordeig (1,2,3)
+%!error <Invalid call> ordeig ()
 %!error <A must be a square matrix> ordeig ('a')
 %!error <A must be a square matrix> ordeig ([1, 2, 3])
 %!error <A must be quasi-triangular> ordeig (magic (3))
--- a/scripts/linear-algebra/orth.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/orth.m	Sun May 16 09:44:35 2021 +0200
@@ -40,45 +40,41 @@
 
 function retval = orth (A, tol)
 
-  if (nargin == 1 || nargin == 2)
-
-    if (isempty (A))
-      retval = [];
-      return;
-    endif
-
-    [U, S, V] = svd (A);
+  if (nargin < 1)
+    print_usage ();
+  endif
 
-    [rows, cols] = size (A);
-
-    [S_nr, S_nc] = size (S);
+  if (isempty (A))
+    retval = [];
+    return;
+  endif
 
-    if (S_nr == 1 || S_nc == 1)
-      s = S(1);
-    else
-      s = diag (S);
-    endif
+  [U, S, V] = svd (A);
+
+  [rows, cols] = size (A);
+
+  [S_nr, S_nc] = size (S);
 
-    if (nargin == 1)
-      if (isa (A, "single"))
-        tol = max (size (A)) * s (1) * eps ("single");
-      else
-        tol = max (size (A)) * s (1) * eps;
-      endif
-    endif
-
-    rank = sum (s > tol);
+  if (S_nr == 1 || S_nc == 1)
+    s = S(1);
+  else
+    s = diag (S);
+  endif
 
-    if (rank > 0)
-      retval = -U(:, 1:rank);
+  if (nargin == 1)
+    if (isa (A, "single"))
+      tol = max (size (A)) * s (1) * eps ("single");
     else
-      retval = zeros (rows, 0);
+      tol = max (size (A)) * s (1) * eps;
     endif
+  endif
 
-  else
+  rank = sum (s > tol);
 
-    print_usage ();
-
+  if (rank > 0)
+    retval = -U(:, 1:rank);
+  else
+    retval = zeros (rows, 0);
   endif
 
 endfunction
--- a/scripts/linear-algebra/planerot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/planerot.m	Sun May 16 09:44:35 2021 +0200
@@ -65,7 +65,7 @@
 
 function [G, y] = planerot (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isvector (x) && numel (x) == 2))
     error ("planerot: X must be a 2-element vector");
@@ -83,7 +83,7 @@
 %! assert (g, [x(1) x(2); -x(2) x(1)] / sqrt (x(1)^2 + x(2)^2), 2e-8);
 %! assert (y(2), 0, 2e-8);
 
-%!error planerot ()
-%!error planerot (1,2)
+## Test input validation
+%!error <Invalid call> planerot ()
 %!error <X must be a 2-element vector> planerot (ones (2,2))
 %!error <X must be a 2-element vector> planerot ([0 0 0])
--- a/scripts/linear-algebra/qzhess.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/qzhess.m	Sun May 16 09:44:35 2021 +0200
@@ -153,5 +153,6 @@
 %! assert (q * b * z, bb, 2e-8);
 %! assert (bb .* mask, zeros (5), 2e-8);
 
-%!error qzhess ([0])
-%!error qzhess ()
+## Test input validation
+%!error <Invalid call> qzhess ()
+%!error <Invalid call> qzhess (1)
--- a/scripts/linear-algebra/rank.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/rank.m	Sun May 16 09:44:35 2021 +0200
@@ -81,6 +81,10 @@
 
 function retval = rank (A, tol)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   if (nargin == 1)
     sigma = svd (A);
     if (isempty (sigma))
@@ -92,11 +96,9 @@
         tolerance = max (size (A)) * sigma (1) * eps;
       endif
     endif
-  elseif (nargin == 2)
+  else
     sigma = svd (A);
     tolerance = tol;
-  else
-    print_usage ();
   endif
 
   retval = sum (sigma > tolerance);
--- a/scripts/linear-algebra/rref.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/rref.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function [A, k] = rref (A, tol)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -111,7 +111,7 @@
 %! a = [1 3; 4 5; 7 9];
 %! [r k] = rref (a);
 %! assert (rank (a), rank (r), 2e-8);
-%! assert (r, eye(3)(:,1:2), 2e-8);
+%! assert (r, eye (3)(:,1:2), 2e-8);
 %! assert (k, [1 2], 2e-8);
 
 %!test
@@ -130,4 +130,5 @@
 %! [r k] = rref (a, tol);
 %! assert (rank (a, tol), rank (r, tol), 2e-8);
 
-%!error rref ()
+## Test input validation
+%!error <Invalid call> rref ()
--- a/scripts/linear-algebra/trace.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/trace.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function y = trace (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,6 +58,5 @@
 %!assert (trace (rand (1,0)), 0)
 %!assert (trace ([3:10]), 3)
 
-%!error trace ()
-%!error trace (1, 2)
+%!error <Invalid call> trace ()
 %!error <only valid on 2-D objects> trace (reshape (1:9,[1,3,3]))
--- a/scripts/linear-algebra/vech.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/vech.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function v = vech (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,5 +58,4 @@
 
 %!assert (vech ([1, 2, 3; 4, 5, 6; 7, 8, 9]), [1; 4; 7; 5; 8; 9])
 
-%!error vech ()
-%!error vech (1, 2)
+%!error <Invalid call> vech ()
--- a/scripts/linear-algebra/vecnorm.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/linear-algebra/vecnorm.m	Sun May 16 09:44:35 2021 +0200
@@ -27,7 +27,8 @@
 ## @deftypefn  {} {@var{n} =} vecnorm (@var{A})
 ## @deftypefnx {} {@var{n} =} vecnorm (@var{A}, @var{p})
 ## @deftypefnx {} {@var{n} =} vecnorm (@var{A}, @var{p}, @var{dim})
-## Return the p-norm of the elements of @var{A} along dimension @var{dim}.
+## Return the vector p-norm of the elements of array @var{A} along dimension
+## @var{dim}.
 ##
 ## The p-norm of a vector is defined as
 ##
@@ -41,30 +42,37 @@
 ## @end example
 ##
 ## @end ifnottex
-## If @var{p} is omitted it defaults to 2 (Euclidean norm).  @var{p} can be
-## @code{Inf} (absolute value of largest element).
+## The input @var{p} must be a positive scalar.  If omitted it defaults to 2
+## (Euclidean norm or distance).  Other special values of @var{p} are 1
+## (Manhattan norm, sum of absolute values) and @code{Inf} (absolute value of
+## largest element).
 ##
-## If @var{dim} is omitted the first non-singleton dimension is used.
+## The input @var{dim} specifies the dimension of the array on which the
+## function operates and must be a positive integer.  If omitted the first
+## non-singleton dimension is used.
 ##
 ## @seealso{norm}
 ## @end deftypefn
 
 function n = vecnorm (A, p = 2, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  if (! isscalar (p) || ! isreal (p) || (p <= 0))
+  if (! isnumeric (A))
+    error ("vecnorm: A must be numeric");
+  endif
+
+  if (! (isscalar (p) && isreal (p) && p > 0))
     error ("vecnorm: P must be positive real scalar or Inf");
   endif
 
-  sz = size (A);
-  if (nargin <= 2)
+  if (nargin < 3)
     ## Find the first non-singleton dimension.
-    (dim = find (sz > 1, 1)) || (dim = 1);
-  elseif (! (isscalar (dim) && dim == fix (dim) && dim > 0))
-    error ("vecnorm: DIM must be an integer and a valid dimension");
+    (dim = find (size (A) > 1, 1)) || (dim = 1);
+  elseif (! (isscalar (dim) && isindex (dim)))
+    error ("vecnorm: DIM must be a positive integer");
   endif
 
   ## Calculate norm using the value of p to accelerate special cases
@@ -80,7 +88,13 @@
 
     otherwise
       if (rem (p,2) == 0)
-        n = (sum ((real (A).^2 + imag (A).^2) .^ (p/2), dim)) .^ (1 / p);
+        ## Even index such as 2,4,6 are specifically accelerated in math
+        ## libraries.  Beyond 6, it doesn't matter which method is used.
+        if (iscomplex (A))
+          n = (sum ((real (A).^2 + imag (A).^2) .^ (p/2), dim)) .^ (1 / p);
+        else
+          n = (sum (A.^2 .^ (p/2), dim)) .^ (1 / p);
+        endif
       else
         n = (sum (abs (A) .^ p, dim)) .^ (1 / p);
       endif
@@ -111,13 +125,13 @@
 %! assert (vecnorm (A), ret, 1e-4);
 
 ## Test input validation
-%!error vecnorm ()
-%!error vecnorm (1,2,3,4)
+%!error <Invalid call> vecnorm ()
+%!error <A must be numeric> vecnorm ({1})
 %!error <P must be positive real scalar> vecnorm (1, [1 2])
 %!error <P must be positive real scalar> vecnorm (1, i)
 %!error <P must be positive real scalar> vecnorm (1, -1)
 %!error <P must be positive real scalar> vecnorm (1, 0)
-%!error <DIM must be an integer and a valid dimension> vecnorm (1, 2, [1 2])
-%!error <DIM must be an integer and a valid dimension> vecnorm (1, 2, [1 2])
-%!error <DIM must be an integer and a valid dimension> vecnorm (1, 2, 0)
-%!error <DIM must be an integer and a valid dimension> vecnorm (1, 2, -1)
+%!error <DIM must be a positive integer> vecnorm (1, 2, [1 2])
+%!error <DIM must be a positive integer> vecnorm (1, 2, -1)
+%!error <DIM must be a positive integer> vecnorm (1, 2, 0)
+%!error <DIM must be a positive integer> vecnorm (1, 2, 1.5)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/miscellaneous/bunzip2.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/bunzip2.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 
 function filelist = bunzip2 (bzfile, dir = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/cast.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/cast.m	Sun May 16 09:44:35 2021 +0200
@@ -24,11 +24,19 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {} cast (@var{val}, "@var{type}")
+## @deftypefn  {} {} cast (@var{val}, "@var{type}")
+## @deftypefnx {} {} cast (@var{val}, "@var{like}", @var{var})
 ## Convert @var{val} to data type @var{type}.
 ##
-## Both @var{val} and @var{type} are typically one of the following built-in
-## classes:
+## The input @var{val} may be a scalar, vector, or matrix of a class that is
+## convertible to the target class (see below).
+##
+## If a variable @var{var} is specified after @qcode{"like"}, @var{val} is
+## converted to the same data type and sparsity attribute.  If @var{var} is
+## complex, @var{val} will be complex, too.
+##
+## @var{var} may be and @var{type} may name any of the following built-in
+## numeric classes:
 ##
 ## @example
 ## @group
@@ -66,7 +74,7 @@
 ## necessary to call cast twice in order to reach the desired type.
 ## For example, the conversion to double is nearly always implemented, but
 ## the conversion to uint8 might not be.  In that case, the following code will
-## work
+## work:
 ##
 ## @example
 ## cast (cast (@var{user_defined_val}, "double"), "uint8")
@@ -75,22 +83,51 @@
 ## @seealso{typecast, int8, uint8, int16, uint16, int32, uint32, int64, uint64, double, single, logical, char, class, typeinfo}
 ## @end deftypefn
 
-function retval = cast (val, type)
+function retval = cast (val, type, var)
 
-  if (nargin != 2)
+  if (nargin < 2 || nargin > 3)
     print_usage ();
   endif
 
   if (! ischar (type))
     error ("cast: TYPE must be a string");
-  elseif (! any (strcmp (type, {"int8"; "uint8"; "int16"; "uint16";
-                                "int32"; "uint32"; "int64"; "uint64";
-                                "double"; "single"; "logical"; "char"})))
-    error ("cast: TYPE '%s' is not a built-in type", type);
+  endif
+
+  if (strcmp (type, "like"))
+    is_like = true;
+    type = class (var);
+  else
+    is_like = false;
+  endif
+
+  if ((! is_like && nargin != 2) || (is_like && nargin != 3))
+    print_usage ();
+  endif
+
+  if (! isnumeric (val) && ! islogical (val) && ! ischar (val))
+    error("cast: type conversion from '%s' is not supported", class (val));
+  endif
+
+  if (! any (strcmp (type, {"int8"; "uint8"; "int16"; "uint16"; "int32";
+                            "uint32"; "int64"; "uint64"; "double"; "single";
+                            "logical"; "char"})))
+    error ("cast: type conversion to '%s' is not supported", type);
   endif
 
   retval = feval (type, val);
 
+  if (is_like)
+    if (issparse (var) && ! issparse (retval))
+      ## retval is of the same type as var, so it must be convertible to sparse
+      retval = sparse (retval);
+    elseif (! issparse (var) && issparse (retval))
+      retval = full (retval);
+    endif
+    if (iscomplex (var) || iscomplex (val))
+      retval = complex (retval);
+    endif
+  endif
+
 endfunction
 
 
@@ -106,10 +143,26 @@
 %!assert (cast ([-2.5 1.1 2.5], "uint32"), uint32 ([0 1 3]))
 %!assert (cast ([-2.5 1.1 2.5], "int64"), int64 ([-3 1 3]))
 %!assert (cast ([-2.5 1.1 2.5], "uint64"), uint64 ([0 1 3]))
+%!assert (cast (1, "like", 2), 1)
+%!assert (cast (1, "like", 2i), complex (1))
+%!assert (cast (1, "like", speye(2)), sparse (1))
+%!assert (cast (1, "like", sparse (2i)), complex (sparse (1)))
+%!assert (cast (single (1), "like", speye (2)), sparse (1))
+%!assert (cast (sparse (1), "like", 2), 1)
+%!assert (cast (sparse (1), "like", 2i), complex (1))
+%!assert (cast (complex (1), "like", 2), complex (1))
+%!assert (cast (complex (1), "like", single (2)), complex (single (1)))
+%!assert (cast ("a", "like", "octave"), "a")
+%!assert (cast ("a", "like", 1i), complex (97))
 
 ## Test input validation
-%!error cast ()
-%!error cast (1)
-%!error cast (1,2,3)
-%!error <TYPE 'foobar' is not a built-in type> cast (1, "foobar")
+%!error <Invalid call> cast ()
+%!error <Invalid call> cast (1)
+%!error <Invalid call> cast (1, "double", 2)
 %!error <TYPE must be a string> cast (1, {"foobar"})
+%!error <type conversion from .* not supported> cast ({}, "double");
+%!error <type conversion from .* not supported> cast (struct (), "double")
+%!error <type conversion to .* not supported> cast (1, "foobar")
+%!error <type conversion to .* not supported> cast (1, "cell")
+%!error <type conversion to .* not supported> cast (1, "like", {})
+%!error <type conversion to .* not supported> cast (1, "like", struct ())
--- a/scripts/miscellaneous/citation.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/citation.m	Sun May 16 09:44:35 2021 +0200
@@ -47,16 +47,13 @@
 
 function citation (package = "octave")
 
-  if (nargin > 1)
-    print_usage ();
-  else
-    display_info_file ("citation", package, "CITATION");
-  endif
+  ## function takes care of validating PACKAGE input
+  display_info_file ("citation", package, "CITATION");
 
 endfunction
 
 
 ## Test input validation
-%!error citation (1, 2)
 %!error <citation: PACKAGE must be a string> citation (1)
-%!error <citation: package .* is not installed> citation ("__NOT_A_VALID_PKG_NAME__")
+%!error <citation: package .* is not installed>
+%! citation ("__NOT_A_VALID_PKG_NAME__");
--- a/scripts/miscellaneous/compare_versions.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/compare_versions.m	Sun May 16 09:44:35 2021 +0200
@@ -223,10 +223,9 @@
 %!assert (compare_versions ("0.1", "0.1", "~="), false)
 
 ## Test input validation
-%!error compare_versions ()
-%!error compare_versions (1)
-%!error compare_versions (1,2)
-%!error compare_versions (1,2,3,4)
+%!error <Invalid call> compare_versions ()
+%!error <Invalid call> compare_versions (1)
+%!error <Invalid call> compare_versions (1,2)
 %!error <V1 and V2 must be strings> compare_versions (0.1, "0.1", "==")
 %!error <V1 and V2 must be strings> compare_versions ("0.1", 0.1, "==")
 %!error <V1 and V2 must be a single row> compare_versions (["0";".";"1"], "0.1", "==")
--- a/scripts/miscellaneous/computer.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/computer.m	Sun May 16 09:44:35 2021 +0200
@@ -25,9 +25,9 @@
 
 ## -*- texinfo -*-
 ## @deftypefn  {} {} computer ()
-## @deftypefnx {} {@var{c} =} computer ()
-## @deftypefnx {} {[@var{c}, @var{maxsize}] =} computer ()
-## @deftypefnx {} {[@var{c}, @var{maxsize}, @var{endian}] =} computer ()
+## @deftypefnx {} {@var{comp} =} computer ()
+## @deftypefnx {} {[@var{comp}, @var{maxsize}] =} computer ()
+## @deftypefnx {} {[@var{comp}, @var{maxsize}, @var{endian}] =} computer ()
 ## @deftypefnx {} {@var{arch} =} computer ("arch")
 ## Print or return a string of the form @var{cpu}-@var{vendor}-@var{os} that
 ## identifies the type of computer that Octave is running on.
@@ -55,36 +55,57 @@
 ##
 ## If the argument @qcode{"arch"} is specified, return a string indicating the
 ## architecture of the computer on which Octave is running.
+##
+## Results may be different if Octave was invoked with the --traditional
+## option.
 ## @seealso{isunix, ismac, ispc}
 ## @end deftypefn
 
-function [c, maxsize, endian] = computer (a)
+function [comp, maxsize, endian] = computer (arch)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1 && ! strcmpi (a, "arch"))
+  if (nargin == 1 && ! strcmpi (arch, "arch"))
     error ('computer: "arch" is only valid argument');
   endif
 
+  canonical_host_type = __octave_config_info__ ("canonical_host_type");
+  traditional = __traditional__ ();
+  enable_64 = __octave_config_info__ ("ENABLE_64");
+  host_parts = ostrsplit (canonical_host_type, "-");
+
   if (nargin == 0)
-    msg = __octave_config_info__ ("canonical_host_type");
 
-    if (strcmp (msg, "unknown"))
-      msg = "Hi Dave, I'm a HAL-9000";
+    host = "";
+    if (traditional && enable_64)
+      if (ismac ())
+        host = "MACI64";
+      elseif (ispc ())
+        host = "PCWIN64";
+      elseif (strcmp ([host_parts{3} "-" host_parts{1}], "linux-x86_64"))
+        host = "GLNXA64";
+      endif
+    endif
+    if (isempty (host))
+      host = canonical_host_type;
+    elseif (strcmp (host, "unknown"))
+      host = "Hi Dave, I'm a HAL-9000";
     endif
 
     if (nargout == 0)
-      disp (msg);
+      disp (host);
     else
-      c = msg;
-      if (isargout (2))
-        if (__octave_config_info__ ("ENABLE_64"))
-          maxsize = 2^63-1;
+      comp = host;
+      if (nargout > 1)
+        if (enable_64)
+          if (traditional)
+            maxsize = 2^48-1;
+          else
+            maxsize = 2^63-1;
+          endif
         else
           maxsize = 2^31-1;
         endif
       endif
-      if (isargout (3))
+      if (nargout > 2)
         if (__octave_config_info__ ("words_big_endian"))
           endian = "B";
         elseif (__octave_config_info__ ("words_little_endian"))
@@ -94,13 +115,25 @@
         endif
       endif
     endif
+
   else
-    ## "arch" argument asked for
-    tmp = ostrsplit (__octave_config_info__ ("canonical_host_type"), "-");
-    if (numel (tmp) == 4)
-      c = sprintf ("%s-%s-%s", tmp{4}, tmp{3}, tmp{1});
-    else
-      c = sprintf ("%s-%s", tmp{3}, tmp{1});
+
+    ## "arch" case.
+    comp = "";
+    if (traditional && enable_64)
+      if (ismac ())
+        comp = "maci64";
+      elseif (ispc ())
+        comp = "win64";
+      elseif (strcmp ([host_parts{3} "-" host_parts{1}], "linux-x86_64"))
+        comp = "glnxa64";
+      endif
+    endif
+    if (isempty (comp))
+      comp = [host_parts{3} "-" host_parts{1}];
+      if (numel (host_parts) == 4)
+        comp = [host_parts{4} "-" comp];
+      endif
     endif
 
   endif
--- a/scripts/miscellaneous/copyfile.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/copyfile.m	Sun May 16 09:44:35 2021 +0200
@@ -48,12 +48,12 @@
 
 function [status, msg, msgid] = copyfile (f1, f2, force)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
   max_cmd_line = 1024;
-  status = true;
+  sts = 1;
   msg = "";
   msgid = "";
 
@@ -87,13 +87,31 @@
   ## 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 (ispc ())
+    f1 = __wglob__ (f1);
+  else
+    f1 = glob (f1);
+  endif
   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 +136,7 @@
       ## Copy the files.
       [err, msg] = system (sprintf ('%s %s"%s"', cmd, p1, p2));
       if (err != 0)
-        status = false;
+        sts = 0;
         msgid = "copyfile";
         break;
       endif
@@ -133,20 +151,28 @@
     ## Copy the files.
     [err, msg] = system (sprintf ('%s %s"%s"', cmd, p1, p2));
     if (err != 0)
-      status = false;
+      sts = 0;
       msgid = "copyfile";
     endif
   endif
 
+  if (nargout == 0)
+    if (sts == 0)
+      error ("copyfile: operation failed: %s", msg);
+    endif
+  else
+    status = sts;
+  endif
+
 endfunction
 
 
 %!test
 %! unwind_protect
-%!   f1 = tempname;
+%!   f1 = tempname ();
 %!   tmp_var = pi;
 %!   save (f1, "tmp_var");
-%!   f2 = tempname;
+%!   f2 = tempname ();
 %!   assert (copyfile (f1, f2));
 %!   assert (exist (f2, "file"));
 %!   fid = fopen (f1, "rb");
@@ -166,9 +192,9 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error copyfile ()
-%!error copyfile (1)
-%!error copyfile (1,2,3,4)
+%!error <Invalid call> copyfile ()
+%!error <Invalid call> copyfile (1)
 %!error <F1 must be a string> copyfile (1, "foobar")
 %!error <F2 must be a string> copyfile ("foobar", 1)
 %!error <F2 must be a directory> copyfile ({"a", "b"}, "%_NOT_A_DIR_%")
+%!error <no files to move> copyfile ("%_NOT_A_FILENAME1_%", "%_NOT_A_FILENAME2_%")
--- a/scripts/miscellaneous/delete.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/delete.m	Sun May 16 09:44:35 2021 +0200
@@ -47,15 +47,21 @@
 
   if (iscellstr (varargin))
     for arg = varargin
-      files = glob (arg{1});
+      if (ispc ())
+        files = __wglob__ (arg{1});
+      else
+        files = glob (arg{1});
+      endif
       if (isempty (files))
-        warning ("delete: no such file: %s", arg{1});
+        warning ("Octave:delete:no-such-file", ...
+                 "delete: no such file: %s", arg{1});
       endif
       for i = 1:length (files)
         file = files{i};
         [err, msg] = unlink (file);
         if (err)
-          warning ("delete: %s: %s", file, msg);
+          warning ("Octave:delete:unlink-error", ...
+                   "delete: %s: %s", file, msg);
         endif
       endfor
     endfor
@@ -65,7 +71,8 @@
     __go_delete__ (varargin{1});
 
   else
-    error ("delete: first argument must be a filename or graphics handle");
+    error ("Octave:delete:unsupported-object", ...
+           "delete: first argument must be a filename or graphics handle");
   endif
 
 endfunction
@@ -73,14 +80,14 @@
 
 %!test
 %! unwind_protect
-%!   file = tempname;
+%!   file = tempname ();
 %!   tmp_var = pi;
 %!   save (file, "tmp_var");
 %!   assert (exist (file, "file"));
 %!   delete (file);
 %!   assert (! exist (file, "file"));
 %! unwind_protect_cleanup
-%!   unlink (file);
+%!   sts = unlink (file);
 %! end_unwind_protect
 
 %!test
@@ -95,5 +102,5 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error delete ()
+%!error <Invalid call> delete ()
 %!error <first argument must be a filename> delete (struct ())
--- a/scripts/miscellaneous/dir.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/dir.m	Sun May 16 09:44:35 2021 +0200
@@ -75,13 +75,7 @@
 ## FIXME: This is quite slow for large directories.
 ##        Perhaps it should be converted to C++?
 
-function retval = dir (directory)
-
-  if (nargin == 0)
-    directory = ".";
-  elseif (nargin > 1)
-    print_usage ();
-  endif
+function retval = dir (directory = ".")
 
   if (! ischar (directory))
     error ("dir: DIRECTORY argument must be a string");
@@ -97,9 +91,11 @@
   if (strcmp (directory, "."))
     flst = {"."};
     nf = 1;
+    dir_has_wildcard = false;
   else
     flst = __wglob__ (directory);
     nf = numel (flst);
+    dir_has_wildcard = any (directory == '*');  # See Bug #58976.
   endif
 
   ## Determine the file list for the case where a single directory is specified.
@@ -109,7 +105,7 @@
     if (err < 0)
       warning ("dir: 'stat (%s)' failed: %s", fn, msg);
       nf = 0;
-    elseif (S_ISDIR (st.mode))
+    elseif (S_ISDIR (st.mode) && ! dir_has_wildcard)
       flst = readdir (flst{1});
       nf = numel (flst);
       flst = strcat ([fn filesep], flst);
@@ -224,11 +220,44 @@
 %!   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
 
-%!testif ; isunix () <*57666>
+%!test <*58976>
+%! orig_dir = pwd ();
+%! tmp_dir = tempname ();
+%! unwind_protect
+%!   assert (mkdir (tmp_dir));
+%!   assert (mkdir (fullfile (tmp_dir, "dir1")));
+%!   assert (mkdir (fullfile (tmp_dir, "dir2")));
+%!   chdir (fullfile (tmp_dir, "dir1"));
+%!   fclose (fopen ("f1", "w"));
+%!   chdir (tmp_dir);
+%!
+%!   ## Wildcard with multiple matches lists directories
+%!   list = dir (fullfile (tmp_dir, "dir*"));
+%!   assert (numel (list) == 2);
+%!   assert ({list.name}, {"dir1", "dir2"});
+%!
+%!   ## Wildcard with single match lists directories
+%!   assert (rmdir (fullfile (tmp_dir, "dir2")));
+%!   list = dir (fullfile (tmp_dir, "dir*"));
+%!   assert (numel (list) == 1);
+%!   assert ({list.name}, {"dir1"});
+%!
+%!   ## No wildcard returns listing of directory contents
+%!   list = dir (fullfile (tmp_dir, "dir1"));
+%!   assert (any (strcmp ({list.name}, "f1")));
+%! unwind_protect_cleanup
+%!   chdir (orig_dir);
+%!   confirm_recursive_rmdir (false, "local");
+%!   if (exist (tmp_dir))
+%!     sts = rmdir (tmp_dir, "s");
+%!   endif
+%! end_unwind_protect
+
+%!test <*57666>
 %! orig_dir = pwd ();
 %! tmp_dir = tempname ();
 %! unwind_protect
@@ -238,7 +267,7 @@
 %!   assert (list(1).folder, canonicalize_file_name (tmp_dir));
 %! unwind_protect_cleanup
 %!   if (exist (tmp_dir))
-%!     rmdir (tmp_dir);
+%!     sts = rmdir (tmp_dir);
 %!   endif
 %! end_unwind_protect
 
--- a/scripts/miscellaneous/dos.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/dos.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function [status, text] = dos (command, echo_arg)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,5 +73,6 @@
 %!   assert (output, "");
 %! endif
 
-%!error dos ()
+## Test input validation
+%!error <Invalid call> dos ()
 %!error dos (1, 2, 3)
--- a/scripts/miscellaneous/edit.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/edit.m	Sun May 16 09:44:35 2021 +0200
@@ -109,7 +109,7 @@
 ## (editor is started in the background and Octave continues) or sync mode
 ## (Octave waits until the editor exits).  Set it to @qcode{"sync"} to start
 ## the editor in sync mode.  The default is @qcode{"async"}
-## (@pxref{XREFsystem,,system}).
+## (@pxref{XREFsystem,,@code{system}}).
 ##
 ## @item editinplace
 ## Determines whether files should be edited in place, without regard to
@@ -143,7 +143,7 @@
                                 "MODE", "async",
                                 "EDITINPLACE", true);
   ## Make sure the stateval variables survive "clear functions".
-  mlock;
+  mlock ();
 
   ## Get default editor every time in case the user has changed it
   FUNCTION.EDITOR = [EDITOR() " %s"];
@@ -219,7 +219,7 @@
     if (iscellstr (varargin))
       editfilelist = varargin;
     else
-      error ("edit: if supplying more than one input all inputs must be strings containing field names to open.");
+      error ("edit: if supplying more than one input all inputs must be strings containing field names to open");
     endif
   endif
 
--- a/scripts/miscellaneous/fieldnames.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/fieldnames.m	Sun May 16 09:44:35 2021 +0200
@@ -28,30 +28,35 @@
 ## @deftypefnx {} {@var{names} =} fieldnames (@var{obj})
 ## @deftypefnx {} {@var{names} =} fieldnames (@var{javaobj})
 ## @deftypefnx {} {@var{names} =} fieldnames ("@var{javaclassname}")
-## Return a cell array of strings with the names of the fields in the
-## specified input.
+## Return a cell array of strings with the names of the fields in the specified
+## input.
 ##
-## When the input is a structure @var{struct}, the names are the elements of
-## the structure.
+## When the input is a structure @var{struct}, the @var{names} are the elements
+## of the structure.
 ##
-## When the input is an Octave object @var{obj}, the names are the public
+## When the input is an Octave object @var{obj}, the @var{names} are the public
 ## properties of the object.
 ##
 ## When the input is a Java object @var{javaobj} or a string containing the
-## name of a Java class @var{javaclassname}, the names are the public fields
-## (data members) of the object or class.
-## @seealso{numfields, isfield, orderfields, struct, methods}
+## name of a Java class @var{javaclassname}, the @var{names} are the public
+## fields (data members) of the object or class.
+## @seealso{numfields, isfield, orderfields, struct, properties}
 ## @end deftypefn
 
 function names = fieldnames (obj)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  if (isstruct (obj) || isobject (obj))
-    ## Call internal C++ function for structs or Octave objects
+  if (isstruct (obj))
     names = __fieldnames__ (obj);
+  elseif (isobject (obj))
+    try
+      names = properties (obj);      # classdef object
+    catch
+      names = __fieldnames__ (obj);  # @class object
+    end_try_catch
   elseif (isjava (obj) || ischar (obj))
     ## FIXME: Function prototype that accepts java obj exists, but doesn't
     ##        work if obj is java.lang.String.  Convert obj to classname.
@@ -70,22 +75,34 @@
 endfunction
 
 
-## test preservation of fieldname order
+## Test preservation of fieldname order
 %!test
 %! x(3).d=1;  x(2).a=2;  x(1).b=3;  x(2).c=3;
 %! assert (fieldnames (x), {"d"; "a"; "b"; "c"});
 
-## test empty structure
+## Test empty structure
 %!test
 %! s = struct ();
 %! assert (fieldnames (s), cell (0, 1));
 
-## test Java classname by passing classname
+## Test classdef object
+%!test
+%! m = containers.Map ();
+%! f = fieldnames (m);
+%! assert (f, {"Count"; "KeyType"; "ValueType"; "map"; "numeric_keys"});
+
+## Test old-style @class object
+%!test
+%! obj = ftp ();
+%! f = fieldnames (obj);
+%! assert (f, {"host"; "username"; "password"; "curlhandle"});
+
+## Test Java classname by passing classname
 %!testif HAVE_JAVA; usejava ("jvm")
 %! names = fieldnames ("java.lang.Double");
 %! assert (any (strcmp (names, "MAX_VALUE")));
 
-## test Java classname by passing java object
+## Test Java classname by passing java object
 %!testif HAVE_JAVA; usejava ("jvm")
 %! names = fieldnames (javaObject ("java.lang.Double", 10));
 %! assert (any (strcmp (names, "MAX_VALUE")));
--- a/scripts/miscellaneous/fileattrib.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/fileattrib.m	Sun May 16 09:44:35 2021 +0200
@@ -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,34 +67,37 @@
 ## True if the user (group; other users) has execute permission for @var{file}.
 ## @end table
 ##
-## If an attribute does not apply (i.e., archive on a Unix system) then the
+## If an attribute does not apply (e.g., archive on a Unix system) then the
 ## field is set to NaN.
 ##
-## If @code{attrib} fails, @var{msg} is a non-empty string containing an
-## error message and @var{msg_id} is the non-empty string @qcode{"fileattrib"}.
+## If @var{file} contains globbing characters, information about all matching
+## files is returned in a structure array.
 ##
-## With no input arguments, return information about the current directory.
-##
-## If @var{file} contains globbing characters, return information about all
-## the matching files.
-## @seealso{glob}
+## If outputs are requested, the first is @var{status} which takes the value 1
+## when the operation was successful, and 0 otherwise.  The second output
+## contains the structure described above (@var{attrib}) if the operation was
+## successful; otherwise, the second output is a system-dependent error message
+## (@var{msg}).  The third output is an empty string ("") when the operation
+## was successful, or a unique message identifier (@var{msgid}) in the case of
+## failure.
+## @seealso{stat, glob}
 ## @end deftypefn
 
 function [status, msg, msgid] = fileattrib (file = ".")
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (! ischar (file))
     error ("fileattrib: FILE must be a string");
   endif
 
-  status = true;
+  sts = 1;
   msg = "";
   msgid = "";
 
-  files = glob (file);
+  if (ispc ())
+    files = __wglob__ (file);
+  else
+    files = glob (file);
+  endif
   if (isempty (files))
     files = {file};
   endif
@@ -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/fileparts.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/fileparts.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function [dir, name, ext] = fileparts (filename)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -111,7 +111,6 @@
 %! assert (strcmp (d, "") && strcmp (n, "") && strcmp (e, ".ext"));
 
 ## Test input validation
-%!error fileparts ()
-%!error fileparts (1,2)
+%!error <Invalid call> fileparts ()
 %!error <FILENAME must be a single string> fileparts (1)
 %!error <FILENAME must be a single string> fileparts (["a"; "b"])
--- a/scripts/miscellaneous/fullfile.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/fullfile.m	Sun May 16 09:44:35 2021 +0200
@@ -24,17 +24,18 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {@var{filename} =} fullfile (@var{dir1}, @var{dir2}, @dots{}, @var{file})
-## @deftypefnx {} {@var{filenames} =} fullfile (@dots{}, @var{files})
+## @deftypefn {} {@var{filename} =} fullfile (@var{dir1}, @var{dir2}, @dots{}, @var{file})
 ## Build complete filename from separate parts.
 ##
-## Joins any number of path components intelligently.  The return value is
-## the concatenation of each component with exactly one file separator
-## between each non empty part and at most one leading and/or trailing file
+## The function joins any number of path components intelligently.  The return
+## value is the concatenation of each component with exactly one file separator
+## between each part of the path and at most one leading and/or trailing file
 ## separator.
 ##
-## If the last component part is a cell array, returns a cell array of
-## filepaths, one for each element in the last component, e.g.:
+## The input arguments might be strings or cell strings.  Any input arguments
+## that are cell strings must contain one single string or must be equal in
+## size.  In that case, the function returns a cell string of filepaths of the
+## same dimensions as the input cell strings, e.g.:
 ##
 ## @example
 ## @group
@@ -49,7 +50,7 @@
 ## @end example
 ##
 ## On Windows systems, while forward slash file separators do work, they are
-## replaced by backslashes; in addition drive letters are stripped of leading
+## replaced by backslashes.  In addition, drive letters are stripped of leading
 ## file separators to obtain a valid file path.
 ##
 ## Note: @code{fullfile} does not perform any validation of the resulting full
@@ -59,19 +60,58 @@
 
 function filename = fullfile (varargin)
 
-  if (nargin && iscell (varargin{end}))
-    filename = cellfun (@(x) fullfile (varargin{1:end-1}, x), varargin{end},
-                                       "UniformOutput", false);
-  else
-    non_empty = cellfun ("isempty", varargin);
-    unc = 0;
-    if (ispc && ! isempty (varargin))
-      varargin = strrep (varargin, '/', filesep);
-      unc = strncmp (varargin{1}, '\\', 2);
-      varargin(1) = regexprep (varargin{1}, '[\\/]*([a-zA-Z]:[\\/]*)', "$1");
-    endif
-    filename = strjoin (varargin(! non_empty), filesep);
-    filename(unc + strfind (filename(1+unc : end), [filesep filesep])) = "";
+  ## remove empty arguments
+  varargin(cellfun (@isempty, varargin)) = [];
+
+  if (isempty (varargin))
+    ## return early for all empty or no input
+    filename = "";
+    return;
+  endif
+
+  ## check input type
+  is_cellstr = cellfun (@iscellstr, varargin);
+  if (! all (is_cellstr | cellfun (@ischar, varargin)))
+    error ("fullfile: input must either be strings or cell strings");
+  endif
+
+  ## convert regular strings to cell strings
+  varargin(! is_cellstr) = num2cell (varargin(! is_cellstr));
+
+  ## check if input size matches
+  if (numel (varargin) > 1 && common_size (varargin{:}) != 0)
+    error ("fullfile: cell string input must be scalar or of the same size");
+  endif
+
+  fs = filesep ();
+
+  if (ispc ())
+    ## replace forward slashes with backslashes
+    varargin = cellfun (@(x) strrep (x, "/", fs), varargin,
+                        "UniformOutput", false);
+
+    ## Strip fileseps preceeding drive letters
+    varargin{1} = regexprep (varargin{1}, '\\*([a-zA-Z]:\\*)', "$1");
+
+    unc = strncmp (varargin{1}, '\\', 2);
+  endif
+
+  ## insert file separator between elements
+  varargin(2,:) = {fs};
+  varargin{end} = "";
+
+  filename = strcat (varargin{:});
+
+  ## remove multiplicate file separators
+  filename = regexprep (filename, [undo_string_escapes(fs), "*"], fs);
+
+  if (ispc ())
+    ## prepend removed file separator for UNC paths
+    filename(unc) = strcat (fs, filename(unc));
+  endif
+
+  if (! any (is_cellstr))
+    filename = filename{1};
   endif
 
 endfunction
@@ -79,13 +119,14 @@
 
 %!shared fs, fsx, xfs, fsxfs, xfsy, xfsyfs
 %! fs = filesep ();
-%! fsx = [fs "x"];
-%! xfs = ["x" fs];
-%! fsxfs = [fs "x" fs];
-%! xfsy = ["x" fs "y"];
-%! xfsyfs = ["x" fs "y" fs];
+%! fsx = [fs, "x"];
+%! xfs = ["x", fs];
+%! fsxfs = [fs, "x", fs];
+%! xfsy = ["x", fs, "y"];
+%! xfsyfs = ["x", fs, "y", fs];
 
 %!assert (fullfile (""), "")
+%!assert (fullfile ("", ""), "")
 %!assert (fullfile (fs), fs)
 %!assert (fullfile ("", fs), fs)
 %!assert (fullfile (fs, ""), fs)
@@ -105,32 +146,39 @@
 %!assert (fullfile (fs, "x", fs), fsxfs)
 
 %!assert (fullfile ("x/", "/", "/", "y", "/", "/"), xfsyfs)
-%!assert (fullfile ("/", "x/", "/", "/", "y", "/", "/"), [fs xfsyfs])
-%!assert (fullfile ("/x/", "/", "/", "y", "/", "/"), [fs xfsyfs])
+%!assert (fullfile ("/", "x/", "/", "/", "y", "/", "/"), [fs, xfsyfs])
+%!assert (fullfile ("/x/", "/", "/", "y", "/", "/"), [fs, xfsyfs])
 
 ## different on purpose so that "fullfile (c{:})" works for empty c
 %!assert (fullfile (), "")
 
-%!assert (fullfile ("x", "y", {"c", "d"}), {[xfsyfs "c"], [xfsyfs "d"]})
+%!assert (fullfile ("x", "y", {"c", "d"}), {[xfsyfs, "c"], [xfsyfs, "d"]})
+%!assert (fullfile ({"folder1", "folder2"}, "sub", {"f1.m", "f2.m"}), ...
+%!        {["folder1", fs, "sub", fs, "f1.m"], ...
+%!         ["folder2", fs, "sub", fs, "f2.m"]});
 
 ## Windows specific - drive letters and file sep type
-%!test
-%! if (ispc)
-%!   assert (fullfile ('\/\/\//A:/\/\', "x/", "/", "/", "y", "/", "/"), ...
-%!           ['A:\' xfsyfs]);
-%! endif
+%!testif ; ispc ()
+%! assert (fullfile ('\/\/\//A:/\/\', "x/", "/", "/", "y", "/", "/"), ...
+%!         ['A:\' xfsyfs]);
 
 ## *nix specific - double backslash
-%!test
-%! if (isunix || ismac)
-%!   assert (fullfile (fs, fs), fs);
-%! endif
+%!testif ; ! ispc ()
+%! assert (fullfile (fs, fs), fs);
+
+## Windows specific - UNC path
+%!testif ; ispc ()
+%! assert (fullfile ({'\/\//server1', 'C:', '\\server2\/'}, ...
+%!                   "x/", "/", "/", "y", "/", "/"), ...
+%!         {['\\server1\', xfsyfs], ['C:\', xfsyfs], ['\\server2\', xfsyfs]});
 
 ## Windows specific - drive letters and file sep type, cell array
-%!test
-%! if (ispc)
-%!  tmp = fullfile ({"\\\/B:\//", "A://c", "\\\C:/g/h/i/j\/"});
-%!  assert (tmp{1}, 'B:\');
-%!  assert (tmp{2}, 'A:\c');
-%!  assert (tmp{3}, 'C:\g\h\i\j\');
-%! endif
+%!testif ; ispc ()
+%! tmp = fullfile ({'\\\/B:\//', 'A://c', '\\\C:/g/h/i/j\/'});
+%! assert (tmp{1}, 'B:\');
+%! assert (tmp{2}, 'A:\c');
+%! assert (tmp{3}, 'C:\g\h\i\j\');
+
+%!error <strings or cell strings> fullfile (1)
+%!error <strings or cell strings> fullfile ({1})
+%!error <same size> fullfile ({"a", "b"}, {"a", "b", "c"})
--- a/scripts/miscellaneous/getfield.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/getfield.m	Sun May 16 09:44:35 2021 +0200
@@ -32,8 +32,8 @@
 ## If @var{s} is a structure array then @var{sidx} selects an element of the
 ## structure array, @var{field} specifies the field name of the selected
 ## element, and @var{fidx} selects which element of the field (in the case of
-## an array or cell array).  See @code{setfield} for a more complete
-## description of the syntax.
+## an array or cell array).  For a more complete description of the syntax,
+## @pxref{XREFsetfield,,@code{setfield}}.
 ##
 ## @seealso{setfield, rmfield, orderfields, isfield, fieldnames, isstruct, struct}
 ## @end deftypefn
@@ -65,6 +65,6 @@
 %! assert (getfield (ss,{1,2},"fd",{3},"b", {1,4}), 5);
 
 ## Test input validation
-%!error getfield ()
-%!error getfield (1)
+%!error <Invalid call> getfield ()
+%!error <Invalid call> getfield (1)
 %!error <invalid index> getfield (1,2)
--- a/scripts/miscellaneous/grabcode.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/grabcode.m	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
 
 function code_str = grabcode (url)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -100,5 +100,4 @@
 
 
 ## Test input validation
-%!error grabcode ()
-%!error grabcode (1,2)
+%!error <Invalid call> grabcode ()
--- a/scripts/miscellaneous/gunzip.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/gunzip.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function filelist = gunzip (gzfile, dir = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/inputParser.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/inputParser.m	Sun May 16 09:44:35 2021 +0200
@@ -190,10 +190,11 @@
 
   properties (Access = protected, Constant = true)
     ## Default validator, always returns scalar true.
-    def_val = @() true;
+    def_val = @(~) true;
   endproperties
 
   methods
+
     function set.PartialMatching (this, val)
       if (val)
         error ("inputParser: PartialMatching is not yet implemented");
@@ -225,7 +226,7 @@
       ##
       ## @end deftypefn
 
-      if (nargin < 2 || nargin > 3)
+      if (nargin < 2)
         print_usage ();
       elseif (numel (this.Optional) || numfields (this.Parameter)
               || numfields (this.Switch))
@@ -264,7 +265,7 @@
       ##
       ## @end deftypefn
 
-      if (nargin < 3 || nargin > 4)
+      if (nargin < 3)
         print_usage ();
       elseif (numfields (this.Parameter) || numfields (this.Switch))
         error (["inputParser.Optional: can't have Optional arguments " ...
@@ -287,7 +288,7 @@
       ##
       ## @end deftypefn
 
-      if (nargin < 3 || nargin > 4)
+      if (nargin < 3)
         print_usage ();
       endif
       this.addParameter (name, def, val);
@@ -420,7 +421,7 @@
           ## keys.  See bug #50752.
           idx -= 1;
           vidx -= 1;
-          break
+          break;
         endif
         try
           valid_option = opt.val (in);
@@ -437,11 +438,11 @@
                               && isscalar (in)))
             idx -= 1;
             vidx -= 1;
-            break
+            break;
           else
             this.error (sprintf (["failed validation of %s\n", ...
                                   "Validation function: %s"],
-                                 toupper (opt.name), disp(opt.val)));
+                                 toupper (opt.name), disp (opt.val)));
           endif
         endif
         this.Results.(opt.name) = in;
@@ -514,9 +515,11 @@
       printf ("Defined parameters:\n\n   {%s}\n",
               strjoin (this.Parameters, ", "));
     endfunction
+
   endmethods
 
   methods (Access = private)
+
     function validate_name (this, type, name)
       if (! isvarname (name))
         error ("inputParser.add%s: NAME is an invalid identifier", method);
@@ -572,10 +575,12 @@
       endif
       error ("%s%s", where, msg);
     endfunction
+
   endmethods
 
 endclassdef
 
+
 %!function p = create_p ()
 %!  p = inputParser ();
 %!  p.CaseSensitive = true;
@@ -650,7 +655,7 @@
 
 ## check alternative method (obj, ...) API
 %!function p2 = create_p2 ();
-%!  p2 = inputParser;
+%!  p2 = inputParser ();
 %!  addRequired (p2, "req1", @(x) ischar (x));
 %!  addOptional (p2, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
 %!  addOptional (p2, "op2", 78, @(x) x > 50);
@@ -677,13 +682,13 @@
 
 ## We must not perform validation of default values
 %!test <*45837>
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("Dir", [], @ischar);
 %! p.parse ();
 %! assert (p.Results.Dir, []);
 
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("positive", -1, @(x) x > 5);
 %! p.parse ();
 %! assert (p.Results.positive, -1);
@@ -695,13 +700,12 @@
 %! p.addOptional ("err", "foo", @error);
 %! p.addParameter ("not_err", "bar", @ischar);
 %! p.parse ("not_err", "qux");
-%! assert (p.Results.err, "foo")
-%! assert (p.Results.not_err, "qux")
-
+%! assert (p.Results.err, "foo");
+%! assert (p.Results.not_err, "qux");
 
 ## With more Parameters to test StructExpand
 %!function p3 = create_p3 ();
-%!  p3 = inputParser;
+%!  p3 = inputParser ();
 %!  addOptional (p3, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
 %!  addOptional (p3, "op2", 78, @(x) x > 50);
 %!  addSwitch (p3, "verbose");
@@ -721,43 +725,43 @@
 %!test
 %! p3 = create_p3 ();
 %! p3.parse (struct ("line", "circle", "color", "green"), "line", "tree");
-%! assert (p3.Results.line, "tree")
+%! assert (p3.Results.line, "tree");
 %! p3.parse ("line", "tree", struct ("line", "circle", "color", "green"));
-%! assert (p3.Results.line, "circle")
+%! assert (p3.Results.line, "circle");
 
 %!test # unmatched parameters with StructExpand
 %! p3 = create_p3 ();
 %! p3.KeepUnmatched = true;
 %! p3.parse (struct ("line", "circle", "color", "green", "bar", "baz"));
-%! assert (p3.Unmatched.bar, "baz")
+%! assert (p3.Unmatched.bar, "baz");
 
 ## The validation for the second optional argument throws an error with
 ## a struct so check that we can handle it.
 %!test
 %! p3 = create_p3 ();
 %! p3.parse ("foo", struct ("color", "green"), "line", "tree");
-%! assert (p3.Results.op1, "foo")
-%! assert (p3.Results.line, "tree")
-%! assert (p3.Results.color, "green")
-%! assert (p3.Results.verbose, false)
+%! assert (p3.Results.op1, "foo");
+%! assert (p3.Results.line, "tree");
+%! assert (p3.Results.color, "green");
+%! assert (p3.Results.verbose, false);
 
 
 ## Some simple tests for addParamValue since all the other ones use add
 ## addParameter but they use the same codepath.
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! addParameter (p, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
 %! addParameter (p, "color", "red", @(x) any (strcmp (x, {"red", "green"})));
 %! p.parse ("line", "circle");
-%! assert ({p.Results.line, p.Results.color}, {"circle", "red"})
+%! assert ({p.Results.line, p.Results.color}, {"circle", "red"});
 
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("foo", "bar", @ischar);
 %! p.parse ();
-%! assert (p.Results, struct ("foo", "bar"))
+%! assert (p.Results, struct ("foo", "bar"));
 %! p.parse ("foo", "qux");
-%! assert (p.Results, struct ("foo", "qux"))
+%! assert (p.Results, struct ("foo", "qux"));
 
 ## This behaviour means that a positional option can never be a string
 ## that is the name of a parameter key.  This is required for Matlab
@@ -767,16 +771,16 @@
 %! p.addOptional ("op1", "val");
 %! p.addParameter ("line", "tree");
 %! p.parse ("line", "circle");
-%! assert (p.Results, struct ("op1", "val", "line", "circle"))
+%! assert (p.Results, struct ("op1", "val", "line", "circle"));
 %!
 %! p = inputParser ();
 %! p.addOptional ("op1", "val1");
 %! p.addOptional ("op2", "val2");
 %! p.addParameter ("line", "tree");
 %! p.parse ("line", "circle");
-%! assert (p.Results.op1, "val1")
-%! assert (p.Results.op2, "val2")
-%! assert (p.Results.line, "circle")
+%! assert (p.Results.op1, "val1");
+%! assert (p.Results.op2, "val2");
+%! assert (p.Results.line, "circle");
 %!
 %! ## If there's enough arguments to fill the positional options and
 %! ## param/key, it still skips positional options.
@@ -809,18 +813,18 @@
 %! p.addOptional ("op1", "val1");
 %! p.addParameter ("line", "circle");
 %! p.parse ("line");
-%! assert (p.Results, struct ("op1", "line", "line", "circle"))
+%! assert (p.Results, struct ("op1", "line", "line", "circle"));
 
 %!test <*50752>
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addOptional ("op1", "val1");
 %! p.addSwitch ("line");
 %! p.parse ("line");
-%! assert (p.Results.op1, "val1")
-%! assert (p.Results.line, true)
+%! assert (p.Results.op1, "val1");
+%! assert (p.Results.line, true);
 
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("a", []);
 %! p.addParameter ("b", []);
 %! p.parse ("a", 1);
@@ -829,7 +833,7 @@
 %! assert (p.UsingDefaults, {"a"});
 
 %!test
-%! p = inputParser;
+%! p = inputParser ();
 %! p.addParameter ("b", []);
 %! p.KeepUnmatched = true;
 %! p.parse ("a", 1);
@@ -838,8 +842,8 @@
 %! assert (p.Unmatched, struct ());
 
 ## Test for patch #9241
-%!error<failed validation of A with ischar>
-%! p = inputParser;
+%!error <failed validation of A with ischar>
+%! p = inputParser ();
 %! p.addParameter ("a", [], @ischar);
 %! p.parse ("a", 1);
 
--- a/scripts/miscellaneous/inputname.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/inputname.m	Sun May 16 09:44:35 2021 +0200
@@ -31,76 +31,133 @@
 ## @deftypefnx {} {} inputname (@var{n}, @var{ids_only})
 ## Return the name of the @var{n}-th argument to the calling function.
 ##
-## If the argument is not a simple variable name, return an empty string.  As
-## an example, a reference to a field in a structure such as @code{s.field} is
-## not a simple name and will return @qcode{""}.
+## If the argument is not a simple variable name, return an empty string.
+## Examples which will return @qcode{""} are numbers (@code{5.1}),
+## expressions (@code{@var{y}/2}), and cell or structure indexing
+## (@code{@var{c}@{1@}} or @code{@var{s}.@var{field}}).
 ##
 ## @code{inputname} is only useful within a function.  When used at the command
-## line it always returns an empty string.
+## line or within a script it always returns an empty string.
+##
+## By default, return an empty string if the @var{n}-th argument is not a valid
+## variable name.  If the optional argument @var{ids_only} is false, return the
+## text of the argument even if it is not a valid variable name.  This is an
+## Octave extension that allows the programmer to view exactly how the function
+## was invoked even when the inputs are complex expressions.
+## @seealso{nargin, narginchk}
+## @end deftypefn
+
+## FIXME: Actually, it probably *isn't* worth fixing, but there are small
+## differences between Octave and Matlab.
+##
+## 1) When called from the top-level or a script, Matlab throws an error
+##
+##   inputname (1)   % at command prompt
+##   % Octave returns "", Matlab throws an error
 ##
-## By default, return an empty string if the @var{n}-th argument is not
-## a valid variable name.  If the optional argument @var{ids_only} is
-## false, return the text of the argument even if it is not a valid
-## variable name.
-## @seealso{nargin, nthargout}
-## @end deftypefn
+## 2) cell or struct indexing causes all further names to be returned as ""
+##
+##   c = {'a', 'b'}
+##   y = 1; z = 2;
+##   func (c, y, z)
+##   % inputname() would return 'c', 'y', 'z' for the inputs.
+##   func (c{1}, y, z)
+##   % inputname() would return '', '', '' for the inputs.
+##
+## 3) If inputname is not called from a function, Matlab walks up the stack
+##    until it finds some valid code and then works from there.  This could
+##    be relevant for mex files or anonymous functions.
+##
+##   f = @(x) inputname (x);
+##   a = 1:4;
+##   arrayfun (fn, a, 'uniformoutput', false)
+##   % output is {'fn', 'a', '', ''}
 
 function name = inputname (n, ids_only = true)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
-  name = "";
+  if (! isscalar (n) || ! isindex (n))
+    error ("inputname: N must be a scalar index");
+  endif
+
   try
-    name = evalin ("caller", sprintf ("__varval__ ('.argn.'){%d}", fix (n)));
+    name = evalin ("caller", sprintf ("__varval__ ('.argn.'){%d}", n));
   catch
+    name = "";
     return;
   end_try_catch
 
-  ## For compatibility with Matlab,
-  ## return empty string if argument name is not a valid identifier.
+  ## For compatibility with Matlab, return empty string if argument name is
+  ## not a valid identifier.
   if (ids_only && ! isvarname (name))
     name = "";
+  elseif (ids_only)
+    ## More complicated checking is required to verify name (bug #59103).
+    ## NAME may be text, like "Inf", which is an acceptable variable name
+    ## that passes isvarname(), but that does not mean it is an actual
+    ## variable name, rather than a function or IEEE number.
+    try
+      v = evalin ("caller",
+                  sprintf ("evalin ('caller', '__varval__ (\"%s\")')", name));
+    catch
+      name = "";
+    end_try_catch
   endif
 
 endfunction
 
 
-## Warning: heap big magic in the following tests!!!
-## The test function builds a private context for each test, with only the
-## specified values shared between them.  It does this using the following
-## template:
-##
-##     function [<shared>] = testfn (<shared>)
-##        <test>
-##     endfunction
-##
-## To test inputname, I need a function context invoked with known parameter
-## names.  So define a couple of shared parameters, et voila!, the test is
-## trivial.
+%!function name = __iname1__ (arg1, arg2, arg3)
+%!  name = inputname (1);
+%!endfunction
+
+%!function name = __iname1_ID__ (arg1, arg2, arg3)
+%!  name = inputname (1, false);
+%!endfunction
+
+%!function name = __iname2__ (arg1, arg2, arg3)
+%!  name = inputname (2);
+%!endfunction
 
-%!shared hello, worldly
-%!assert (inputname (1), "hello")
-%!assert (inputname (2), "worldly")
-%!assert (inputname (3), "")
+%!function names = __iname3__ (arg1, arg2, arg3)
+%!  names = cell (1, 3);
+%!  for i = 1:3
+%!    names{i} = inputname (i);
+%!  endfor
+%!endfunction
+
+%!test
+%! assert (__iname1__ ('xvar'), "");
+%! xvar = 1;
+%! assert (__iname1__ (xvar), "xvar");
 
-## Clear parameter list so that testfn is created with zero inputs/outputs
-%!shared
-%!assert (inputname (-1), "")
-%!assert (inputname (1), "")
+%!test
+%! xvar = 1;  yvar = 2;
+%! assert (__iname2__ (xvar), "");
+%! assert (__iname2__ (xvar, yvar), "yvar");
+
+%!test
+%! xvar = 1;  yvar = 2;
+%! assert (__iname3__ (xvar), {"xvar", "", ""});
+%! assert (__iname3__ (xvar, yvar), {"xvar", "yvar", ""});
+%! assert (__iname3__ (xvar, 3, yvar), {"xvar", "", "yvar"});
 
-%!function r = __foo1__ (x, y)
-%!  r = inputname (2);
-%!endfunction
-%!assert (__foo1__ (pi, e), "e")
-%!assert (feval (@__foo1__, pi, e), "e")
+## Test numbers, expressions, indexing operations
+%!test
+%! assert (__iname1__ (1.0), "");
+%! x = 1;
+%! assert (__iname1__ (x / 2), "");
+%! assert (__iname1__ (Inf), "");
 
-%!function r = __foo2__ (x, y)
-%!  r = inputname (2, false);
-%!endfunction
-%!assert (__foo2__ (pi+1, 2+2), "2 + 2")
-%!assert (feval (@__foo2__, pi, pi/2), "pi / 2")
+%!test
+%! assert (__iname1_ID__ (1.0), "1.0");
+%! x = 1;
+%! assert (__iname1_ID__ (x / 2), "x / 2");
+%! assert (__iname1_ID__ (Inf), "Inf");
 
-%!error inputname ()
-%!error inputname (1,2,3)
+%!error <Invalid call> inputname ()
+%!error <N must be a scalar> inputname (ones (2,2))
+%!error <N must be a scalar index> inputname (-1)
--- a/scripts/miscellaneous/isfile.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/isfile.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function retval = isfile (f)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -75,6 +75,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error isfile ()
+%!error <Invalid call> isfile ()
 %!error isfile ("a", "b")
 %!error <F must be a string> isfile (1.0)
--- a/scripts/miscellaneous/isfolder.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/isfolder.m	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
 
 function retval = isfolder (f)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -70,11 +70,11 @@
 %!   addpath (d);
 %!   assert (! isfolder (n));
 %! unwind_protect_cleanup
-%!   try, rmdir (tmp); end_try_catch
-%!   try, rmpath (d); end_try_catch
+%!   sts = rmdir (tmp);
+%!   rmpath (d);
 %! end_unwind_protect
 
 ## Test input validation
-%!error isfolder ()
+%!error <Invalid call> isfolder ()
 %!error isfolder ("a", "b")
 %!error <F must be a string> isfolder (1.0)
--- a/scripts/miscellaneous/ismac.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/ismac.m	Sun May 16 09:44:35 2021 +0200
@@ -31,15 +31,9 @@
 
 function retval = ismac ()
 
-  if (nargin == 0)
-    retval = __octave_config_info__ ("mac");
-  else
-    print_usage ();
-  endif
+  retval = __octave_config_info__ ("mac");
 
 endfunction
 
 
 %!assert (islogical (ismac ()))
-
-%!error ismac (1)
--- a/scripts/miscellaneous/ismethod.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/ismethod.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
   endif
 
   if (! ischar (method))
-    error ("ismethod: second argument must be a method name");
+    error ("ismethod: METHOD must be a string");
   endif
 
   method_list = methods (obj);
@@ -51,6 +51,7 @@
 
 endfunction
 
+
 %!testif HAVE_JAVA; usejava ("jvm")
 %! assert (ismethod (javaObject ("java.lang.String", "Yo"), "hashCode"));
 
--- a/scripts/miscellaneous/ispc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/ispc.m	Sun May 16 09:44:35 2021 +0200
@@ -31,15 +31,9 @@
 
 function retval = ispc ()
 
-  if (nargin == 0)
-    retval = __octave_config_info__ ("windows");
-  else
-    print_usage ();
-  endif
+  retval = __octave_config_info__ ("windows");
 
 endfunction
 
 
 %!assert (islogical (ispc ()))
-
-%!error ispc (1)
--- a/scripts/miscellaneous/isunix.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/isunix.m	Sun May 16 09:44:35 2021 +0200
@@ -31,15 +31,9 @@
 
 function retval = isunix ()
 
-  if (nargin == 0)
-    retval = __octave_config_info__ ("unix");
-  else
-    print_usage ();
-  endif
+  retval = __octave_config_info__ ("unix");
 
 endfunction
 
 
 %!assert (islogical (isunix ()))
-
-%!error isunix (1)
--- a/scripts/miscellaneous/license.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/license.m	Sun May 16 09:44:35 2021 +0200
@@ -68,12 +68,8 @@
 
 function [retval, errmsg] = license (cmd, feature, toggle)
 
-  if (nargin > 3)
-    print_usage ();
-  endif
-
-  ## Then only give information about Octave core
   if (nargin == 0)
+    ## then only give information about Octave core
     retval = "GNU General Public License";
     return;
   endif
@@ -82,10 +78,6 @@
 
   switch (tolower (cmd))
     case "inuse"
-      if (nargin > 2)
-        print_usage ();
-      endif
-
       features = features(loaded);
 
       if (nargin > 1)
--- a/scripts/miscellaneous/list_primes.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/list_primes.m	Sun May 16 09:44:35 2021 +0200
@@ -34,9 +34,7 @@
 
 function retval = list_primes (n = 25)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (! isreal (n) || ! isscalar (n))
+  if (! isreal (n) || ! isscalar (n))
     error ("list_primes: N must be a real scalar");
   endif
 
@@ -69,6 +67,5 @@
 %!assert (list_primes (1), [2])
 
 ## Test input validation
-%!error list_primes (1, 2)
 %!error <N must be a real scalar> list_primes (i)
 %!error <N must be a real scalar> list_primes ([1 2])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/memory.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,273 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {} memory ()
+## @deftypefnx {} {[@var{userdata}, @var{systemdata}] =} memory ()
+## Display or return information about the memory usage of Octave.
+##
+## If the function is called without output arguments, a table with an overview
+## of the current memory consumption is displayed.
+##
+## The output argument @var{userdata} is a structure with the following fields
+## containing data for the Octave process:
+##
+## @table @code
+## @item @var{MaxPossibleArrayBytes}
+## Maximum size for an array to be allocated.  Be aware that this includes
+## @emph{all} physical memory and swap space.  Allocating that amount of memory
+## might result in system instability, data corruption, and/or file system
+## corruption.  Note that depending on the platform (32-bit systems), the
+## largest contiguous memory block might further limit the maximum possible
+## allocatable array.  This check is not currently implemented.
+##
+## @item @var{MemAvailableAllArrays}
+## The total size of available memory in bytes.
+##
+## @item @var{ram_available_all_arrays}
+## The maximum size for an array that can be allocated in physical memory
+## (excluding swap space).  Note that depending on the platform (32-bit
+## systems), the largest contiguous memory block might further limit the
+## maximum possible allocatable array.  This check is not currently
+## implemented.
+##
+## @item  @var{MemUsedMATLAB}
+## @itemx @var{mem_used_octave}
+## The memory (including swap space) currently used by Octave in bytes.
+##
+## @item @var{ram_used_octave}
+## The physical memory (excluding swap space) currently used by Octave in
+## bytes.
+##
+## @end table
+##
+## The output argument @var{systemdata} is a nested structure with the
+## following fields containing information about the system's memory:
+##
+## @table @code
+## @item @var{PhysicalMemory.Available}
+## The currently available physical memory in bytes.
+##
+## @item @var{PhysicalMemory.Total}
+## The total physical memory in bytes.
+##
+## @item @var{SystemMemory.Available}
+## The currently available memory (including swap space) in bytes.
+##
+## @item @var{SystemMemory.Total}
+## The total memory (including swap space) in bytes.
+##
+## @item @var{VirtualAddressSpace.Available}
+## The currently available virtual address space in bytes.
+##
+## @item @var{VirtualAddressSpace.Total}
+## The total virtual address space in bytes.
+##
+## @end table
+##
+## @example
+## @group
+## memory ()
+##    @result{} System    RAM: 3934008 KiB,  swap: 4087804 KiB
+##       Octave    RAM:  170596 KiB,  virt: 1347944 KiB
+##       Free      RAM: 1954940 KiB,  swap: 4087804 KiB
+##       Available RAM: 2451948 KiB, total: 6042744 KiB
+## @end group
+##
+## @group
+## [userdata, systemdata] = memory ()
+##    @result{} userdata =
+##      scalar structure containing the fields:
+##      MaxPossibleArrayBytes = 6.1622e+09
+##      MemAvailableAllArrays = 6.1622e+09
+##      ram_available_all_arrays = 2.4883e+09
+##      MemUsedMATLAB = 1.3825e+09
+##      mem_used_octave = 1.3825e+09
+##      ram_used_octave = 1.7824e+08
+##
+##    systemdata =
+##      scalar structure containing the fields:
+##      PhysicalMemory =
+##        scalar structure containing the fields:
+##          Available = 2.4954e+09
+##          Total = 4.0284e+09
+##      SystemMemory =
+##        scalar structure containing the fields:
+##          Available = 6.6813e+09
+##          Total = 8.2143e+09
+##      VirtualAddressSpace =
+##        scalar structure containing the fields:
+##          Available = 2.8147e+14
+##          Total = 2.8147e+14
+## @end group
+## @end example
+##
+## This function is implemented for Linux and Windows only.
+##
+## @seealso{computer, getpid, getrusage, nproc, uname}
+## @end deftypefn
+
+function [userdata, systemdata] = memory ()
+
+  if ((! isunix () || ismac ()) && ! ispc ())
+    if (nargout > 0)
+      error ("memory: function not yet implemented for this architecture");
+    else
+      warning ("memory: function not yet implemented for this architecture");
+    endif
+    return;
+  endif
+
+  kiB = 1024;
+  [architecture, bits] = computer ();
+
+  if (isunix () && ! ismac ())
+    ## Read values from pseudofiles
+    [status, meminfo] = lmemory ();
+
+    ## FIXME: Query the actual size of the user address space,
+    ##        e.g., with getrlimit (RLIMIT_AS, rlp)
+    if (log2 (bits) > 32)
+      ## 64-bit platform
+      address_space = 2^48;  # 256 TiB
+    else
+      ## 32-bit platform
+      address_space = 3 * 2^30;  # 3 GiB
+    endif
+
+    total_ram = meminfo.MemTotal * kiB;
+    total_swap = meminfo.SwapTotal * kiB;
+    free_ram = meminfo.MemFree * kiB;
+    if (isfield (meminfo, "MemAvailable"))
+      available_ram = meminfo.MemAvailable * kiB;
+    else
+      ## On kernels from before 2014 MemAvailable is not present.
+      ## This is a rough estimate that can be used instead.
+      available_ram = (meminfo.MemFree + meminfo.Cached) * kiB;
+    endif
+    free_swap = meminfo.SwapFree * kiB;
+    used_ram = status.VmRSS * kiB;
+    used_virtual = status.VmSize * kiB;
+    avail_virtual = address_space - used_virtual;
+
+  elseif (ispc ())
+    [proc, sys] = __wmemory__ ();
+
+    total_ram = sys.TotalPhys;
+    total_swap = sys.TotalPageFile;
+    available_ram = sys.AvailPhys;
+    free_swap = sys.AvailPageFile;
+    used_ram = proc.WorkingSetSize;
+    used_virtual = proc.WorkingSetSize + proc.PagefileUsage;
+    avail_virtual = sys.AvailVirtual;
+    address_space = sys.TotalVirtual;
+
+  endif
+
+  available = min (available_ram + free_swap, avail_virtual);
+  ram_available = min (available_ram, avail_virtual);
+
+  ## FIXME: On 32-bit systems, the largest possible array is limited by the
+  ##        largest contiguous block in memory.
+  user.MaxPossibleArrayBytes = available;
+  user.MemAvailableAllArrays = available;
+  user.ram_available_all_arrays = ram_available;
+  user.MemUsedMATLAB = used_virtual;  # For compatibility
+  user.mem_used_octave = used_virtual;
+  user.ram_used_octave = used_ram;
+
+  syst.PhysicalMemory.Available = available_ram;
+  syst.PhysicalMemory.Total = total_ram;
+  syst.SystemMemory.Available = available_ram + free_swap;
+  syst.SystemMemory.Total = total_ram + total_swap;
+  syst.VirtualAddressSpace.Available = avail_virtual;
+  syst.VirtualAddressSpace.Total = address_space;
+
+  if (nargout)
+    userdata = user;
+    systemdata = syst;
+  else
+    unitsize = kiB;
+    unitname = 'kiB';
+    disp (sprintf ("Octave is running on %s", architecture))
+    disp (sprintf ("System    RAM: %9.0f %s,  swap: %9.0f %s",
+                   round (syst.PhysicalMemory.Total / unitsize), unitname,
+                   round (total_swap / unitsize), unitname ))
+    disp (sprintf ("Octave    RAM: %9.0f %s,  virt: %9.0f %s",
+                   round (user.ram_used_octave / unitsize), unitname,
+                   round (user.mem_used_octave / unitsize), unitname))
+    if (isunix ())
+      ## The concept of free vs. available RAM doesn't seem to exist on Windows
+      disp (sprintf ("Free      RAM: %9.0f %s,  swap: %9.0f %s",
+                     round (free_ram / unitsize), unitname,
+                     round (free_swap / unitsize), unitname))
+    endif
+    disp (sprintf ("Available RAM: %9.0f %s, total: %9.0f %s",
+                   round (user.ram_available_all_arrays / unitsize), unitname,
+                   round (user.MemAvailableAllArrays / unitsize), unitname))
+  endif
+
+endfunction
+
+function [status, meminfo] = lmemory ()
+  ## Read pseudo files to gather memory information on Linux
+
+  ## Read the proc/self/status pseudofile.
+  ## See https://linuxwiki.de/proc/pid#A.2Fproc.2Fpid.2Fstatus.
+  ## It contains a variable number of lines with name-value pairs.
+
+  f = fopen ("/proc/self/status");
+  buffer = textscan (f, "%s %s", "delimiter", ':\n');
+  fclose (f);
+  for i = 1:rows (buffer{1})
+    status.(buffer{1}{i}) = textscan (buffer{2}{i}){1};
+  endfor
+
+  ## Read the /proc/meminfo pseudofile
+  ## see https://linuxwiki.de/proc/meminfo
+  ## It contains a variable number of lines with name-value pairs.
+
+  f = fopen ("/proc/meminfo");
+  buffer = textscan (f, "%s %s", "delimiter", ':\n');
+  fclose (f);
+  for i = 1:rows (buffer{1})
+    meminfo.(buffer{1}{i}) = textscan (buffer{2}{i}){1};
+  endfor
+
+endfunction
+
+
+%!testif ; (isunix () && ! ismac ()) || ispc ()
+%! [user, syst] = memory ();
+%! assert (user.mem_used_octave > 0);
+%! assert (user.ram_used_octave <= user.mem_used_octave);
+%! assert (user.mem_used_octave < syst.SystemMemory.Total);
+%! assert (user.MemAvailableAllArrays <= syst.SystemMemory.Available);
+
+%!testif ; (! isunix () || ismac ()) && ! ispc ()
+%! fail ("[user] = memory ()",
+%!       "function not yet implemented for this architecture");
+%! fail ("memory ()", "warning",
+%!       "function not yet implemented for this architecture");
--- a/scripts/miscellaneous/menu.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/menu.m	Sun May 16 09:44:35 2021 +0200
@@ -100,8 +100,9 @@
 endfunction
 
 
-%!error menu ()
-%!error menu ("title")
+## Test input validation
+%!error <Invalid call> menu ()
+%!error <Invalid call> menu ("title")
 %!error <TITLE must be a string> menu (1, "opt1")
 %!error <All OPTIONS must be strings> menu ("title", "opt1", 1)
 %!error <OPTIONS must be string or cell array of strings> menu ("title", 1)
--- a/scripts/miscellaneous/methods.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/methods.m	Sun May 16 09:44:35 2021 +0200
@@ -46,7 +46,7 @@
 
 function mtds = methods (obj, opt)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -145,7 +145,7 @@
 %!         "validate_name"});
 
 ## Test input validation
-%!error methods ()
+%!error <Invalid call> methods ()
 %!error methods ("a", "b", "c")
 %!error <invalid option> methods ("ftp", "option1")
 %!error <invalid input argument> methods (1)
--- a/scripts/miscellaneous/mkdir.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mkdir.m	Sun May 16 09:44:35 2021 +0200
@@ -50,7 +50,7 @@
 
 function [status, msg, msgid] = mkdir (parent, dirname)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -112,7 +112,7 @@
 %!   assert (isfolder (dir));
 %! unwind_protect_cleanup
 %!   confirm_recursive_rmdir (false, "local");
-%!   rmdir (dir1, "s");
+%!   sts = rmdir (dir1, "s");
 %! end_unwind_protect
 
 %!test <*53031>
@@ -125,8 +125,8 @@
 %!   assert (status);
 %!   assert (isfolder (fullfile (tmp_dir, "subdir")));
 %! unwind_protect_cleanup
-%!   rmdir (fullfile (tmp_dir, "subdir"));
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (fullfile (tmp_dir, "subdir"));
+%!   sts = rmdir (tmp_dir);
 %!   if (isempty (HOME))
 %!     unsetenv ("HOME");
 %!   else
@@ -138,5 +138,4 @@
 %! fail ('mkdir ("__%hello%__", "world")', "invalid PARENT");
 
 ## Test input validation
-%!error mkdir ()
-%!error mkdir ("a", "b", "c")
+%!error <Invalid call> mkdir ()
--- a/scripts/miscellaneous/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -10,6 +10,7 @@
   %reldir%/private/tar_is_bsd.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/bug_report.m \
   %reldir%/bunzip2.m \
   %reldir%/cast.m \
@@ -44,6 +45,7 @@
   %reldir%/loadobj.m \
   %reldir%/ls.m \
   %reldir%/ls_command.m \
+  %reldir%/memory.m \
   %reldir%/menu.m \
   %reldir%/methods.m \
   %reldir%/mex.m \
--- a/scripts/miscellaneous/movefile.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/movefile.m	Sun May 16 09:44:35 2021 +0200
@@ -54,12 +54,12 @@
 
 function [status, msg, msgid] = movefile (f1, f2, force)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
   max_cmd_line = 1024;
-  status = true;
+  sts = 1;
   msg = "";
   msgid = "";
 
@@ -96,13 +96,31 @@
   ## 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 (ispc ())
+    f1 = __wglob__ (f1);
+  else
+    f1 = glob (f1);
+  endif
   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 +147,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 +165,19 @@
     ## Move the file(s).
     [err, msg] = system (sprintf ('%s %s "%s"', cmd, p1, p2));
     if (err != 0)
-      status = false;
+      sts = 0;
       msgid = "movefile";
     endif
     ## Load new file(s) in editor
-    __event_manager_file_renamed__ (status);
+    __event_manager_file_renamed__ (sts);
+  endif
+
+  if (nargout == 0)
+    if (sts == 0)
+      error ("movefile: operation failed: %s", msg);
+    endif
+  else
+    status = sts;
   endif
 
 endfunction
@@ -159,14 +185,14 @@
 
 %!test
 %! unwind_protect
-%!   f1 = tempname;
+%!   f1 = tempname ();
 %!   tmp_var = pi;
 %!   save (f1, "tmp_var");
 %!   fid = fopen (f1, "rb");
 %!   assert (fid >= 0);
 %!   orig_data = fread (fid);
 %!   fclose (fid);
-%!   f2 = tempname;
+%!   f2 = tempname ();
 %!   assert (movefile (f1, f2));
 %!   assert (! exist (f1, "file"));
 %!   assert (exist (f2, "file"));
@@ -182,8 +208,8 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error movefile ()
-%!error movefile (1,2,3,4)
+%!error <Invalid call> movefile ()
 %!error <F1 must be a string> movefile (1, "foobar")
 %!error <F2 must be a string> movefile ("foobar", 1)
 %!error <F2 must be a directory> movefile ({"a", "b"}, "%_NOT_A_DIR_%")
+%!error <no files to move> movefile ("%_NOT_A_FILENAME1_%", "%_NOT_A_FILENAME2_%")
--- a/scripts/miscellaneous/mustBeFinite.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeFinite.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeFinite (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeGreaterThan.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeGreaterThan.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 
 %!error <Invalid call> mustBeGreaterThan ()
 %!error <Invalid call> mustBeGreaterThan (1)
-%!error <Invalid call> mustBeGreaterThan (1,2,3)
+%!error <called with too many inputs> mustBeGreaterThan (1, 2, 3)
 %!error <input must be greater than 42> mustBeGreaterThan (42, 42)
 %!error <found 1 elements that were not> mustBeGreaterThan (Inf, Inf)
 %!error <must be greater than 0> mustBeGreaterThan (NaN, 0)
--- a/scripts/miscellaneous/mustBeGreaterThanOrEqual.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeGreaterThanOrEqual.m	Sun May 16 09:44:35 2021 +0200
@@ -69,6 +69,6 @@
 
 %!error <Invalid call> mustBeGreaterThanOrEqual ()
 %!error <Invalid call> mustBeGreaterThanOrEqual (1)
-%!error <Invalid call> mustBeGreaterThanOrEqual (1,2,3)
+%!error <called with too many inputs> mustBeGreaterThanOrEqual (1, 2, 3)
 %!error <must be greater than or equal to 2> mustBeGreaterThanOrEqual (1, 2)
 %!error <must be greater than or equal to 0> mustBeGreaterThanOrEqual (NaN, 0)
--- a/scripts/miscellaneous/mustBeInteger.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeInteger.m	Sun May 16 09:44:35 2021 +0200
@@ -37,7 +37,7 @@
 
 function mustBeInteger (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -54,7 +54,7 @@
     but = "there were non-finite values";
   elseif (any (x != fix (x)))
     but = "it had fractional values in some elements";
-  end
+  endif
 
   if (! isempty (but))
     label = inputname (1);
--- a/scripts/miscellaneous/mustBeLessThan.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeLessThan.m	Sun May 16 09:44:35 2021 +0200
@@ -69,7 +69,7 @@
 
 %!error <Invalid call> mustBeLessThan ()
 %!error <Invalid call> mustBeLessThan (1)
-%!error <Invalid call> mustBeLessThan (1,2,3)
+%!error <called with too many inputs> mustBeLessThan (1, 2, 3)
 %!error <must be less than 0> mustBeLessThan (1, 0)
 %!error <must be less than 1> mustBeLessThan (1, 1)
 %!error <must be less than Inf> mustBeLessThan (Inf, Inf)
--- a/scripts/miscellaneous/mustBeLessThanOrEqual.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeLessThanOrEqual.m	Sun May 16 09:44:35 2021 +0200
@@ -72,5 +72,5 @@
 
 %!error <Invalid call> mustBeLessThanOrEqual ()
 %!error <Invalid call> mustBeLessThanOrEqual (1)
-%!error <Invalid call> mustBeLessThanOrEqual (1,2,3)
+%!error <called with too many inputs> mustBeLessThanOrEqual (1, 2, 3)
 %!error <must be less than or equal to 0> mustBeLessThanOrEqual (1, 0)
--- a/scripts/miscellaneous/mustBeMember.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeMember.m	Sun May 16 09:44:35 2021 +0200
@@ -53,8 +53,8 @@
       label = "input";
     endif
     n_bad = numel (find (tf));
-    # FIXME: Fancy inclusion of bad_val & valid values in the error message.
-    #        Probably use mat2str() in a try/catch for that.
+    ## FIXME: Fancy inclusion of bad_val & valid values in the error message.
+    ##        Probably use mat2str() in a try/catch for that.
     error ("%s must be one of the specified valid values; found %d elements that were not", ...
            label, n_bad);
   endif
@@ -70,6 +70,6 @@
 
 %!error <Invalid call> mustBeMember ()
 %!error <Invalid call> mustBeMember (1)
-%!error <Invalid call> mustBeMember (1,2,3)
+%!error <called with too many inputs> mustBeMember (1, 2, 3)
 %!error <found 1 elements> mustBeMember ([1, 42], 1:5)
 %!error <found 1 elements> mustBeMember ("nope", {"foo", "bar", "baz"})
--- a/scripts/miscellaneous/mustBeNegative.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNegative.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNegative (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonNan.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNonNan.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNonNan (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonempty.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNonempty.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNonempty (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonnegative.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNonnegative.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNonnegative (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonpositive.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNonpositive.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNonpositive (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonsparse.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNonsparse.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNonsparse (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNonzero.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNonzero.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNonzero (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNumeric.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNumeric.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNumeric (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeNumericOrLogical.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeNumericOrLogical.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeNumericOrLogical (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBePositive.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBePositive.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBePositive (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/mustBeReal.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/mustBeReal.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function mustBeReal (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/namedargs2cell.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/namedargs2cell.m	Sun May 16 09:44:35 2021 +0200
@@ -46,10 +46,9 @@
 
 function c = namedargs2cell (s)
 
-  if (nargin != 1 || nargout > 1)
+  if (nargin < 1)
     print_usage ();
-  endif
-  if (! isstruct (s) || ! isscalar (s))
+  elseif (! isstruct (s) || ! isscalar (s))
     error ("namedargs2cell: S must be a scalar structure");
   endif
 
@@ -66,6 +65,6 @@
 
 ## Test input validation
 %!error <Invalid call> namedargs2cell ()
-%!error <Invalid call> namedargs2cell (1, 2)
+%!error <called with too many inputs> namedargs2cell (1, 2)
 %!error <S must be a scalar structure> namedargs2cell (true)
 %!error <S must be a scalar structure> namedargs2cell (struct ("name", {1, 2}))
--- a/scripts/miscellaneous/nargchk.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/nargchk.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function msg = nargchk (minargs, maxargs, nargs, outtype = "string")
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   elseif (minargs > maxargs)
     error ("nargchk: MINARGS must be <= MAXARGS");
--- a/scripts/miscellaneous/narginchk.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/narginchk.m	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,7 @@
 function narginchk (minargs, maxargs)
 
   if (nargin != 2)
-    print_usage;
+    print_usage ();
   elseif (! isnumeric (minargs) || ! isscalar (minargs))
     error ("narginchk: MINARGS must be a numeric scalar");
   elseif (! isnumeric (maxargs) || ! isscalar (maxargs))
--- a/scripts/miscellaneous/nargoutchk.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/nargoutchk.m	Sun May 16 09:44:35 2021 +0200
@@ -97,13 +97,13 @@
     args = evalin ("caller", "nargout;");
 
     if (args < minargs)
-      error ("nargoutchk: Not enough output arguments.");
+      error ("nargoutchk: Not enough output arguments");
     elseif (args > maxargs)
-      error ("nargoutchk: Too many output arguments.");
+      error ("nargoutchk: Too many output arguments");
     endif
 
   else
-    print_usage;
+    print_usage ();
   endif
 
 endfunction
--- a/scripts/miscellaneous/news.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/news.m	Sun May 16 09:44:35 2021 +0200
@@ -37,15 +37,11 @@
 
 function news (package = "octave")
 
-  if (nargin > 1)
-    print_usage ();
-  else
-    display_info_file ("news", package, "NEWS");
-  endif
+  ## function takes care of validating PACKAGE input
+  display_info_file ("news", package, "NEWS");
 
 endfunction
 
 
-%!error news (1, 2)
 %!error <news: PACKAGE must be a string> news (1)
 %!error <news: package .* is not installed> news ("__NOT_A_VALID_PKG_NAME__")
--- a/scripts/miscellaneous/open.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/open.m	Sun May 16 09:44:35 2021 +0200
@@ -73,7 +73,7 @@
 
 function output = open (file)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -131,6 +131,6 @@
 
 
 ## Test input validation
-%!error open ()
+%!error <Invalid call> open ()
 %!error open ("abc", "def")
 %!error <FILE must be a string> open (1)
--- a/scripts/miscellaneous/orderfields.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/orderfields.m	Sun May 16 09:44:35 2021 +0200
@@ -104,7 +104,7 @@
 
 function [sout, p] = orderfields (s1, s2)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -213,8 +213,7 @@
 %! assert (size_equal (s, s2));
 
 ## Test input validation
-%!error orderfields ()
-%!error orderfields (1,2,3)
+%!error <Invalid call> orderfields ()
 %!error <S1 must be a struct> orderfields (1)
 %!error <S1 and S2 do not have the same fields>
 %! s1.a = 1;
--- a/scripts/miscellaneous/private/display_info_file.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/private/display_info_file.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
     names     = cellfun (@(x) x.name, installed, "UniformOutput", false);
     pos       = strcmpi (names, package);
     if (! any (pos))
-      error ("%s: package '%s' is not installed.", func, package);
+      error ("%s: package '%s' is not installed", func, package);
     endif
     filepath = fullfile (installed{pos}.dir, "packinfo", file);
   endif
--- a/scripts/miscellaneous/private/tar_is_bsd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/private/tar_is_bsd.m	Sun May 16 09:44:35 2021 +0200
@@ -36,9 +36,10 @@
 ## @end deftypefn
 
 function out = tar_is_bsd ()
+
   ## BSD tar needs to be handled differently from GNU tar
   persistent cache
-  if isempty (cache)
+  if (isempty (cache))
     [status, tar_ver_str] = system ("tar --version");
     if (status)
       error ("tar: Failed executing tar --version (status = %d)", status);
@@ -46,4 +47,5 @@
     cache = ! isempty (regexp (tar_ver_str, "bsdtar"));
   endif
   out = cache;
+
 endfunction
--- a/scripts/miscellaneous/publish.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/publish.m	Sun May 16 09:44:35 2021 +0200
@@ -209,7 +209,7 @@
   ## Check file to be in Octave's load path
   [file_path, file_name, file_ext] = fileparts (file);
   if (isempty (file_path))
-    file_path = pwd;
+    file_path = pwd ();
   endif
   if (exist ([file_name, file_ext]) != 2)
     error (["publish: " file " is not in the load path"]);
@@ -611,7 +611,7 @@
   ## Extract <html> and <latex> blocks recursively.
   content_str = strjoin (content, "\n");
   tags = {"html", "latex"};
-  for i = 1:length(tags)
+  for i = 1:length (tags)
     tok = regexp (content_str, ...
       ['(.*?)(^|\n\n)(<', tags{i}, '>)\n(.*?)\n(<\/', ...
         tags{i}, '>)($|\n\n)(.*)'], "tokens", "once");
@@ -709,6 +709,7 @@
     p_content{end+1}.type = "text";
     p_content{end}.content = strjoin (block, "\n");
   endfor
+
 endfunction
 
 
@@ -722,6 +723,7 @@
   until (! ischar (m_source{i}))
   fclose (fid);
   m_source = m_source(1:end-1);  # No EOL
+
 endfunction
 
 
@@ -770,6 +772,7 @@
       endfor
     endif
   endif
+
 endfunction
 
 
@@ -783,6 +786,7 @@
       toc_cstr{end+1} = format_text (cstr{i}.content, formatter);
     endif
   endfor
+
 endfunction
 
 
@@ -1067,6 +1071,7 @@
   ## Split string by lines and preserve blank lines.
   cstr = strsplit (strrep (cstr, "\n\n", "\n \n"), "\n");
   eval_context ("save");
+
 endfunction
 
 
@@ -1088,7 +1093,7 @@
       for i = 1:length (var_names)
         if (! any (strcmp (var_names{i}, forbidden_var_names)))
           ctext(var_names{i}) = evalin ("caller", var_names{i});
-        end
+        endif
       endfor
 
     case "load"
@@ -1107,13 +1112,14 @@
       ## Do nothing
 
   endswitch
+
 endfunction
 
 
 ## Note: Functional BIST tests are located in the 'test/publish' directory.
 
 ## Test input validation
-%!error publish ()
+%!error <Invalid call> publish ()
 %!error publish (1)
 %!error <FILE does not exist> publish ("%%_non_existent_file_%%.m")
 %!error <only script files can be published> publish ("publish.m")
--- a/scripts/miscellaneous/recycle.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/recycle.m	Sun May 16 09:44:35 2021 +0200
@@ -42,10 +42,6 @@
 
   persistent current_state = "off";
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0 || nargout > 0)
     val = current_state;
   endif
--- a/scripts/miscellaneous/run.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/run.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 
 function run (script)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -114,7 +114,7 @@
 %!   assert (_5yVNhWVJWJn47RKnzxPsyb_, 1337);
 %! unwind_protect_cleanup
 %!   unlink (test_script);
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %! end_unwind_protect
 
 ## Test function file execution
@@ -140,11 +140,11 @@
 %!   assert (tstval2, true);
 %! unwind_protect_cleanup
 %!   unlink (test_function);
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %!   path (path_orig);
 %! end_unwind_protect
 
 ## Test input validation
-%!error run ()
+%!error <Invalid call> run ()
 %!error run ("a", "b")
 %!error <SCRIPT must exist> run ("__A_very_#unlikely#_file_name__")
--- a/scripts/miscellaneous/setfield.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/setfield.m	Sun May 16 09:44:35 2021 +0200
@@ -52,7 +52,7 @@
 ## the space character.  Using arbitrary strings for field names is
 ## incompatible with @sc{matlab}, and this usage will emit a warning if the
 ## warning ID @code{Octave:language-extension} is enabled.
-## @xref{XREFwarning_ids,,warning_ids}.
+## @xref{XREFwarning_ids,,@code{warning_ids}}.
 ##
 ## With the second calling form, set a field of a structure array.  The
 ## input @var{sidx} selects an element of the structure array, @var{field}
@@ -146,7 +146,7 @@
 %! assert (oo(1,2).fd(3).b(1,4), 6);
 
 ## Test input validation
-%!error setfield ()
-%!error setfield (1)
-%!error setfield (1,2)
+%!error <Invalid call> setfield ()
+%!error <Invalid call> setfield (1)
+%!error <Invalid call> setfield (1,2)
 %!error <invalid index> setfield (1,2,3)
--- a/scripts/miscellaneous/substruct.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/substruct.m	Sun May 16 09:44:35 2021 +0200
@@ -69,7 +69,7 @@
       error ("substruct: for TYPE == ., SUBS must be a character string");
     endif
   else
-    error ('substruct: TYPE must be one of "()", "{}", or "."');
+    error ('substruct: TYPE must be one of "()", "{}", or ""');
   endif
 
   retval = struct ("type", typ, "subs", sub);
@@ -87,8 +87,10 @@
 %! y = substruct ("()", {1,2,3}, "{}", {":"}, ".", "foo");
 %! assert (x,y);
 
-%!error substruct ()
-%!error substruct (1, 2, 3)
+## Test input validation
+%!error <Invalid call> substruct ()
+%!error <Invalid call> substruct (1)
+%!error <Invalid call> substruct (1, 2, 3)
 %!error substruct ("x", 1)
 %!error substruct ("()", [1,2,3])
 %!error substruct (".", {1,2,3})
--- a/scripts/miscellaneous/swapbytes.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/swapbytes.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
 
 function y = swapbytes (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -74,6 +74,5 @@
 %! assert (swapbytes (swapbytes (single (pi))), single (pi));
 
 ## Test input validation
-%!error swapbytes ()
-%!error swapbytes (1, 2)
+%!error <Invalid call> swapbytes ()
 %!error <invalid object of class 'cell'> swapbytes ({1})
--- a/scripts/miscellaneous/symvar.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/symvar.m	Sun May 16 09:44:35 2021 +0200
@@ -48,6 +48,7 @@
 
 function vars = symvar (str)
 
+  warning ("off", "Octave:legacy-function", "local");  # using inline below.
   vars = argnames (inline (str));
   ## Correct for auto-generated 'x' variable when no symvar was found.
   if (numel (vars) == 1 && strcmp (vars{1}, "x") && ! any (str == "x"))
@@ -58,5 +59,5 @@
 
 
 %!assert (symvar ("3*x + 4*y + 5*cos (z)"), {"x"; "y"; "z"})
-%!assert (symvar ("sin()^2 + cos()^2 == 1"), {})
+%!assert (symvar ("sin ()^2 + cos ()^2 == 1"), {})
 %!assert (symvar ("1./x"), {"x"})
--- a/scripts/miscellaneous/tar.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/tar.m	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
 
 function filelist = tar (tarfile, files, rootdir = ".")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -72,7 +72,7 @@
   else
     cmd = sprintf ("tar cvf %s -C %s %s",
                             tarfile, rootdir, sprintf (" %s", files{:}));
-  end
+  endif
 
   ## Save and restore the TAR_OPTIONS environment variable used by GNU tar.
   tar_options_env = getenv ("TAR_OPTIONS");
@@ -133,7 +133,7 @@
 %!   if (! exist (tarname, "file"))
 %!     error ("tar archive file cannot be found!");
 %!   endif
-%!   outdir = tempname;
+%!   outdir = tempname ();
 %!   untar (tarname, outdir);
 %!   fid = fopen (fullfile (outdir, fname1), "rt");
 %!   assert (fid >= 0);
@@ -149,17 +149,12 @@
 %!   chdir (orig_dir);
 %!   unlink (tarname);
 %!   confirm_recursive_rmdir (false, "local");
-%!   if (exist (dirname))
-%!     rmdir (dirname, "s");
-%!   endif
-%!   if (exist (outdir))
-%!     rmdir (outdir, "s");
-%!   endif
+%!   sts = rmdir (dirname, "s");
+%!   sts = rmdir (outdir, "s");
 %! end_unwind_protect
 
 ## Test input validation
-%!error tar ()
-%!error tar (1)
-%!error tar (1,2,3,4)
+%!error <Invalid call> tar ()
+%!error <Invalid call> tar (1)
 %!error <TARFILE must be a string> tar (1, "foobar")
 %!error <FILES must be a character array or cellstr> tar ("foobar", 1)
--- a/scripts/miscellaneous/tempdir.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/tempdir.m	Sun May 16 09:44:35 2021 +0200
@@ -37,7 +37,7 @@
 
   dirname = getenv ("TMPDIR");
   if (isempty (dirname))
-    dirname = P_tmpdir;
+    dirname = P_tmpdir ();
   endif
 
   if (! strcmp (dirname(end), filesep))
--- a/scripts/miscellaneous/unix.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/unix.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function [status, text] = unix (command, echo_arg)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -71,5 +71,5 @@
 %!   assert (output, "");
 %! endif
 
-%!error unix ()
-%!error unix (1, 2, 3)
+## Test input validation
+%!error <Invalid call> unix ()
--- a/scripts/miscellaneous/unpack.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/unpack.m	Sun May 16 09:44:35 2021 +0200
@@ -78,7 +78,7 @@
 
 function filelist = unpack (file, dir = [], filetype = "")
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -93,7 +93,11 @@
   if (numel (file) == 1)
     ## FIXME: The code below is not a perfect test for a URL
     if (isempty (strfind (file{1}, "://")))
-      gfile = glob (file);
+      if (ispc ())
+        gfile = __wglob__ (file);
+      else
+        gfile = glob (file);
+      endif
       if (isempty (gfile))
         error ('unpack: FILE "%s" not found', file{1});
       else
@@ -372,7 +376,7 @@
 %!     unlink (filename);
 %!     unlink ([filename ".orig"]);
 %!     confirm_recursive_rmdir (false, "local");
-%!     rmdir (dirname, "s");
+%!     sts = rmdir (dirname, "s");
 %!   end_unwind_protect
 %! unwind_protect_cleanup
 %!   ## Restore environment variables TMPDIR, TMP
@@ -386,8 +390,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error unpack ()
-%!error unpack (1,2,3,4)
+%!error <Invalid call> unpack ()
 %!error <FILE must be a string or cell array of strings> unpack (1)
 %!error <FILE "_%NOT_A_FILENAME%_" not found> unpack ("_%NOT_A_FILENAME%_")
 %!error <FILE "_%NOT_A_FILENAME%_" not found> unpack ({"_%NOT_A_FILENAME%_"})
--- a/scripts/miscellaneous/untar.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/untar.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 
 function filelist = untar (tarfile, dir = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/unzip.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/unzip.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 
 function filelist = unzip (zipfile, dir = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/miscellaneous/validateattributes.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/validateattributes.m	Sun May 16 09:44:35 2021 +0200
@@ -424,7 +424,7 @@
   num_pos = strcmpi (cls, name);
   if (any (num_pos))
     cls(num_pos) = [];
-    cls(end+1:end+numel(group)) = group;
+    cls(end+1:end+numel (group)) = group;
   endif
 endfunction
 
--- a/scripts/miscellaneous/ver.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/ver.m	Sun May 16 09:44:35 2021 +0200
@@ -58,10 +58,6 @@
 
 function retval = ver (package = "")
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargout == 0)
     hg_id = __octave_config_info__ ("hg_id");
 
--- a/scripts/miscellaneous/verLessThan.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/verLessThan.m	Sun May 16 09:44:35 2021 +0200
@@ -83,7 +83,7 @@
 %!assert (verLessThan ("Octave", "99.9.9"))
 
 ## Test input validation
-%!error verLessThan ()
+%!error <Invalid call> verLessThan ()
 %!error verLessThan ("a")
 %!error verLessThan ("a", "1", "b")
 %!error <package "no-such-package" is not installed>
--- a/scripts/miscellaneous/version.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/version.m	Sun May 16 09:44:35 2021 +0200
@@ -72,7 +72,7 @@
 
 function [v, d] = version (feature)
 
-  if (nargin > 1 || ((nargin != 0) && ((nargout > 1) || ! ischar (feature))))
+  if (nargin == 1 && (nargout > 1 || ! ischar (feature)))
     print_usage ();
   endif
 
@@ -81,7 +81,7 @@
 
     if (nargout > 1)
       d = __octave_config_info__ ("release_date");
-    end
+    endif
   else
     switch (lower (feature))
       case "-date"
--- a/scripts/miscellaneous/what.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/what.m	Sun May 16 09:44:35 2021 +0200
@@ -73,10 +73,6 @@
 
 function retval = what (dir)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     dir = { pwd() };
   else
@@ -109,7 +105,7 @@
    if (numel (dir) == 0)
      w = __what__ ("");
      w = resize (w, [0, 1]);  # Matlab compatibility, return 0x1 empty array
-   end
+   endif
 
   if (nargout == 0)
     for i = 1 : numel (w)
--- a/scripts/miscellaneous/zip.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/miscellaneous/zip.m	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
 
 function filelist = zip (zipfile, files, rootdir = ".")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -126,16 +126,15 @@
 %!     error ("unzipped file not equal to original file!");
 %!   endif
 %! unwind_protect_cleanup
-%!   unlink (filename);
-%!   unlink ([dirname, filesep, basename, ext]);
-%!   unlink (zipfile);
-%!   unlink ([zipfile ".zip"]);
-%!   rmdir (dirname);
+%!   sts = unlink (filename);
+%!   sts = unlink ([dirname, filesep, basename, ext]);
+%!   sts = unlink (zipfile);
+%!   sts = unlink ([zipfile ".zip"]);
+%!   sts = rmdir (dirname);
 %! end_unwind_protect
 
 ## Test input validation
-%!error zip ()
-%!error zip (1)
-%!error zip (1,2,3,4)
+%!error <Invalid call> zip ()
+%!error <Invalid call> zip (1)
 %!error <ZIPFILE must be a string> zip (1, "foobar")
 %!error <FILES must be a character array or cellstr> zip ("foobar", 1)
--- a/scripts/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -6,6 +6,7 @@
 
 include %reldir%/+containers/module.mk
 include %reldir%/+matlab/+lang/module.mk
+include %reldir%/+matlab/+net/module.mk
 include %reldir%/audio/module.mk
 include %reldir%/deprecated/module.mk
 include %reldir%/elfun/module.mk
@@ -49,6 +50,9 @@
 ######################## include %reldir%/@ftp/module.mk ########################
 FCN_FILE_DIRS += %reldir%/@ftp
 
+%canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config
+
 %canon_reldir%_@ftp_FCN_FILES = \
   %reldir%/@ftp/ascii.m \
   %reldir%/@ftp/binary.m  \
@@ -70,7 +74,9 @@
 
 %canon_reldir%_@ftp_DATA = $(%canon_reldir%_@ftp_FCN_FILES)
 
-FCN_FILES += $(%canon_reldir%_@ftp_FCN_FILES)
+FCN_FILES += \
+  $(%canon_reldir%_FCN_FILES) \
+  $(%canon_reldir%_@ftp_FCN_FILES)
 
 PKG_ADD_FILES += %reldir%/@ftp/PKG_ADD
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/ode/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/ode/decic.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/decic.m	Sun May 16 09:44:35 2021 +0200
@@ -97,7 +97,7 @@
                                              y0, fixed_y0, yp0, fixed_yp0,
                                              options)
 
-  if (nargin < 6 || nargin > 7)
+  if (nargin < 6)
     print_usage ();
   endif
 
@@ -215,13 +215,12 @@
 %! assert ([ynew(1:end), ypnew(1:end)], [ref1(1:end), ref2(1:end)], 1e-5);
 
 ## Test input validation
-%!error decic ()
-%!error decic (1)
-%!error decic (1,2)
-%!error decic (1,2,3)
-%!error decic (1,2,3,4)
-%!error decic (1,2,3,4,5)
-%!error decic (1,2,3,4,5,6,7,8)
+%!error <Invalid call> decic ()
+%!error <Invalid call> decic (1)
+%!error <Invalid call> decic (1,2)
+%!error <Invalid call> decic (1,2,3)
+%!error <Invalid call> decic (1,2,3,4)
+%!error <Invalid call> decic (1,2,3,4,5)
 %!error <FUN must be a valid function handle>
 %! decic (1, 0, [1; 0; 0], [1; 1; 0], [-1e-4; 1; 0], [0; 0; 0]);
 %!error <T0 must be a numeric scalar>
--- a/scripts/ode/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -17,6 +17,7 @@
   %reldir%/private/starting_stepsize.m
 
 %canon_reldir%_FCN_FILES =  \
+  %reldir%/.oct-config \
   %reldir%/decic.m \
   %reldir%/ode15i.m \
   %reldir%/ode15s.m \
--- a/scripts/ode/ode15i.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/ode15i.m	Sun May 16 09:44:35 2021 +0200
@@ -255,19 +255,20 @@
   ## Events
   options.haveeventfunction = ! isempty (options.Events);
 
-  [t, y, te, ye, ie] = __ode15__ (fun, trange, y0, yp0, options);
+  ## 3 arguments in the event callback of ode15i
+  [t, y, te, ye, ie] = __ode15__ (fun, trange, y0, yp0, options, 3);
 
   if (nargout == 2)
     varargout{1} = t;
     varargout{2} = y;
   elseif (nargout == 1)
-    varargout{1}.x = t;  # Time stamps are saved in field x
-    varargout{1}.y = y;  # Results are saved in field y
+    varargout{1}.x = t.';  # Time stamps saved in field x (row vector)
+    varargout{1}.y = y.';  # Results are saved in field y (row vector)
     varargout{1}.solver = solver;
     if (options.haveeventfunction)
-      varargout{1}.xe = te;  # Time info when an event occurred
-      varargout{1}.ye = ye;  # Results when an event occurred
-      varargout{1}.ie = ie;  # Index info which event occurred
+      varargout{1}.xe = te.';  # Time info when an event occurred
+      varargout{1}.ye = ye.';  # Results when an event occurred
+      varargout{1}.ie = ie.';  # Index info which event occurred
     endif
   elseif (nargout > 2)
     varargout = cell (1,5);
@@ -388,11 +389,11 @@
 
 ## With empty options
 %!testif HAVE_SUNDIALS
-%! opt = odeset();
+%! opt = odeset ();
 %! [t, y] = ode15i (@rob, [0, 1e6, 2e6, 3e6, 4e6], [1; 0; 0],
 %!                  [-1e-4; 1e-4; 0], opt);
 %! assert ([t(end), y(end,:)], fref2, 1e-3);
-%! opt = odeset();
+%! opt = odeset ();
 
 ## Without options
 %!testif HAVE_SUNDIALS
@@ -504,7 +505,7 @@
 %! opt = odeset ("Events", @ff);
 %! sol = ode15i (@rob, [0, 100], [1; 0; 0], [-1e-4; 1e-4; 0], opt);
 %! assert (isfield (sol, "ie"));
-%! assert (sol.ie, [0;1]);
+%! assert (sol.ie, [1, 2]);
 %! assert (isfield (sol, "xe"));
 %! assert (isfield (sol, "ye"));
 %! assert (sol.x(end), 10, 1);
@@ -514,20 +515,22 @@
 %! opt = odeset ("Events", @ff);
 %! [t, y, te, ye, ie] = ode15i (@rob, [0, 100], [1; 0; 0],
 %!                              [-1e-4; 1e-4; 0], opt);
-%! assert ([t(end), te', ie'], [10, 10, 10, 0, 1], [1, 0.2, 0.2, 0, 0]);
+%! assert (t(end), 10, 1);
+%! assert (te, [10; 10], 0.2);
+%! assert (ie, [1; 2]);
 
 ## Initial solutions as row vectors
 %!testif HAVE_SUNDIALS
 %! A = eye (2);
 %! [tout, yout] = ode15i (@(t, y, yp) A * y - A * yp, ...
 %! [0, 1], [1, 1], [1, 1]);
-%! assert (size (yout), [20, 2])
+%! assert (size (yout), [20, 2]);
 
 %!testif HAVE_SUNDIALS
 %! A = eye (2);
 %! [tout, yout] = ode15i (@(t, y, yp) A * y - A * yp, ...
 %! [0, 1], [1, 1], [1; 1]);
-%! assert (size (yout), [20, 2])
+%! assert (size (yout), [20, 2]);
 
 ## Jacobian fun wrong dimension
 %!testif HAVE_SUNDIALS
--- a/scripts/ode/ode15s.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/ode15s.m	Sun May 16 09:44:35 2021 +0200
@@ -257,7 +257,7 @@
   endif
 
   ## Use sparse methods only if all matrices are sparse
-  if (! options.havemasssparse)
+  if (! isempty (options.Mass)) && (! options.havemasssparse)
     options.havejacsparse = false;
   endif
 
@@ -270,8 +270,16 @@
                                                   options.havetimedep,
                                                   options.havejacfun);
       options.havejacfun = true;
-    else   ## All matrices are constant
-      options.Jacobian = {[- options.Jacobian], [options.Mass]};
+    else   # All matrices are constant
+      if (! isempty (options.Mass))
+        options.Jacobian = {[- options.Jacobian], [options.Mass]};
+      else
+        if (options.havejacsparse)
+          options.Jacobian = {[- options.Jacobian], speye(n)};
+        else
+          options.Jacobian = {[- options.Jacobian], eye(n)};
+        endif
+      endif
 
     endif
   endif
@@ -312,23 +320,24 @@
 
   yp0 = options.InitialSlope;
 
+  ## 2 arguments in the event callback of ode15s
   [t, y, te, ye, ie] = __ode15__ (@ (t, y, yp) wrap (t, y, yp, options.Mass,
                                                      options.havetimedep,
                                                      options.havestatedep,
                                                      fun),
-                                  trange, y0, yp0, options);
+                                  trange, y0, yp0, options, 2);
 
   if (nargout == 2)
     varargout{1} = t;
     varargout{2} = y;
   elseif (nargout == 1)
-    varargout{1}.x = t;  # Time stamps are saved in field x
-    varargout{1}.y = y;  # Results are saved in field y
+    varargout{1}.x = t.';  # Time stamps saved in field x (row vector)
+    varargout{1}.y = y.';  # Results are saved in field y (row vector)
     varargout{1}.solver = solver;
     if (options.haveeventfunction)
-      varargout{1}.xe = te;  # Time info when an event occurred
-      varargout{1}.ye = ye;  # Results when an event occurred
-      varargout{1}.ie = ie;  # Index info which event occurred
+      varargout{1}.xe = te.';  # Time info when an event occurred
+      varargout{1}.ye = ye.';  # Results when an event occurred
+      varargout{1}.ie = ie.';  # Index info which event occurred
     endif
   elseif (nargout > 2)
     varargout = cell (1,5);
@@ -467,9 +476,9 @@
 %!endfunction
 %!
 %!function jac = jacfunsparse (t, y)
-%!  jac = sparse([-0.04,           1e4*y(3),  1e4*y(2);
-%!                 0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
-%!                    1,                  1,         1]);
+%!  jac = sparse ([-0.04,           1e4*y(3),  1e4*y(2);
+%!                  0.04, -1e4*y(3)-6e7*y(2), -1e4*y(2);
+%!                     1,                  1,         1]);
 %!endfunction
 
 %!testif HAVE_SUNDIALS
@@ -588,6 +597,16 @@
 %! [t, y] = ode15s (@rob, [0, 100], [1; 0; 0], opt);
 %! assert ([t(end), y(end,:)], frefrob, 1e-3);
 
+## Jacobian as const matrix
+%!testif HAVE_SUNDIALS
+%! opt = odeset ("RelTol", 1e-4, "AbsTol", 1e-5,
+%!               "Jacobian", [98, 198; -99, -199]);
+%! [t, y] = ode15s (@(t, y)[98, 198; -99, -199] * (y - [1; 0]),
+%!                 [0, 5], [2; 0], opt);
+%! y1xct = @(t) 2 * exp (-t) - exp (-100 * t) + 1;
+%! y2xct = @(t) - exp (-t) + exp (-100 * t);
+%! assert ([y1xct(t), y2xct(t)], y, 1e-3);
+
 ## two output arguments
 %!testif HAVE_SUNDIALS
 %! [t, y] = ode15s (@fpol, [0, 2], [2, 0]);
@@ -619,77 +638,77 @@
 
 ## Solve in backward direction starting at t=0
 %!testif HAVE_SUNDIALS
-%! ref = [-1.205364552835178, 0.951542399860817];
+%! ref = [-1.205364552835178; 0.951542399860817];
 %! sol = ode15s (@fpol, [0 -2], [2, 0]);
-%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 5e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [-2; ref], 5e-3);
 
 ## Solve in backward direction starting at t=2
 %!testif HAVE_SUNDIALS
-%! ref = [-1.205364552835178, 0.951542399860817];
+%! ref = [-1.205364552835178; 0.951542399860817];
 %! sol = ode15s (@fpol, [2, 0 -2], fref);
-%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 3e-2);
+%! assert ([sol.x(end); sol.y(:,end)], [-2; ref], 3e-2);
 
 ## Solve another anonymous function in backward direction
 %!testif HAVE_SUNDIALS
-%! ref = [-1, 0.367879437558975];
+%! ref = [-1; 0.367879437558975];
 %! sol = ode15s (@(t,y) y, [0 -1], 1);
-%! assert ([sol.x(end), sol.y(end,:)], ref, 1e-2);
+%! assert ([sol.x(end); sol.y(:,end)], ref, 1e-2);
 
 ## Solve another anonymous function below zero
 %!testif HAVE_SUNDIALS
-%! ref = [0, 14.77810590694212];
+%! ref = [0; 14.77810590694212];
 %! sol = ode15s (@(t,y) y, [-2, 0], 2);
-%! assert ([sol.x(end), sol.y(end,:)], ref, 5e-2);
+%! assert ([sol.x(end); sol.y(:,end)], ref, 5e-2);
 
 ## Solve in backward direction starting at t=0 with MaxStep option
 %!testif HAVE_SUNDIALS
-%! ref = [-1.205364552835178, 0.951542399860817];
+%! ref = [-1.205364552835178; 0.951542399860817];
 %! opt = odeset ("MaxStep", 1e-3);
 %! sol = ode15s (@fpol, [0 -2], [2, 0], opt);
 %! assert (abs (sol.x(8)-sol.x(7)), 1e-3, 1e-3);
-%! assert ([sol.x(end), sol.y(end,:)], [-2, ref], 1e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [-2; ref], 1e-3);
 
 ## AbsTol option
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("AbsTol", 1e-5);
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 4e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 4e-3);
 
 ## AbsTol and RelTol option
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("AbsTol", 1e-8, "RelTol", 1e-8);
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 1e-3);
 
 ## RelTol option -- higher accuracy
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("RelTol", 1e-8);
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 1e-4);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 1e-4);
 
 ## Mass option as function
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("Mass", @fmas, "MStateDependence", "none");
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 3e-3);
 
 ## Mass option as matrix
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("Mass", eye (2,2), "MStateDependence", "none");
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 3e-3);
 
 ## Mass option as sparse matrix
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("Mass", speye (2), "MStateDependence", "none");
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 3e-3);
 
 ## Mass option as function and sparse matrix
 %!testif HAVE_SUNDIALS
 %! opt = odeset ("Mass", "fmsa", "MStateDependence", "none");
 %! sol = ode15s (@fpol, [0, 2], [2, 0], opt);
-%! assert ([sol.x(end), sol.y(end,:)], [2, fref], 3e-3);
+%! assert ([sol.x(end); sol.y(:,end)], [2, fref].', 3e-3);
 
 ## Refine
 %!testif HAVE_SUNDIALS
@@ -715,7 +734,7 @@
 %!               "MStateDependence", "none");
 %! sol = ode15s (@rob, [0, 100], [1; 0; 0], opt);
 %! assert (isfield (sol, "ie"));
-%! assert (sol.ie, [0;1]);
+%! assert (sol.ie, [1, 2]);
 %! assert (isfield (sol, "xe"));
 %! assert (isfield (sol, "ye"));
 %! assert (sol.x(end), 10, 1);
@@ -725,13 +744,15 @@
 %! opt = odeset ("Events", @feve, "Mass", @massdensefunstate,
 %!               "MStateDependence", "none");
 %! [t, y, te, ye, ie] = ode15s (@rob, [0, 100], [1; 0; 0], opt);
-%! assert ([t(end), te', ie'], [10, 10, 10, 0, 1], [1, 0.5, 0.5, 0, 0]);
+%! assert (t(end), 10, 1);
+%! assert (te, [10; 10], 0.5);
+%! assert (ie, [1; 2]);
 
 ## Initial solution as row vector
 %!testif HAVE_SUNDIALS
 %! A = zeros (2);
 %! [tout, yout] = ode15s (@(t, y) A * y, [0, 1], [1, 1]);
-%! assert (yout, ones (18, 2))
+%! assert (yout, ones (18, 2));
 
 %!testif HAVE_SUNDIALS
 %! A = zeros (2);
--- a/scripts/ode/ode23.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/ode23.m	Sun May 16 09:44:35 2021 +0200
@@ -326,19 +326,19 @@
 
 ## We are using the Van der Pol equation for all tests.
 ## Further tests also define a reference solution (computed at high accuracy)
-%!function ydot = fpol (t, y)  # The Van der Pol ODE
+%!function ydot = fpol (t, y, varargin)  # The Van der Pol ODE
 %!  ydot = [y(2); (1 - y(1)^2) * y(2) - y(1)];
 %!endfunction
 %!function ref = fref ()       # The computed reference sol
 %!  ref = [0.32331666704577, -1.83297456798624];
 %!endfunction
 %!function [val, trm, dir] = feve (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = zeros (2,1);            # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
 %!function [val, trm, dir] = fevn (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = ones (2,1);             # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
@@ -378,7 +378,7 @@
 %! [t, y] = ode23 (@fpol, [0 2], [2 0], 12, 13, "KL");
 %! assert ([t(end), y(end,:)], [2, fref], 1e-3);
 %!test  # empty OdePkg structure *but* extra input arguments
-%! opt = odeset;
+%! opt = odeset ();
 %! [t, y] = ode23 (@fpol, [0 2], [2 0], opt, 12, 13, "KL");
 %! assert ([t(end), y(end,:)], [2, fref], 1e-2);
 %!test  # Solve another anonymous function below zero
@@ -426,7 +426,7 @@
 %!test # hermite_cubic_interpolation
 %! opt = odeset ("RelTol", 1e-8, "NormControl", "on");
 %! [t,sol] = ode23(@(t,x)[x(2);x(1)],linspace(0,1),[1;0],opt);
-%! assert(max(abs(sol(:,1)-cosh(t))),0,1e-6)
+%! assert (max (abs (sol(:,1)-cosh (t))),0,1e-6);
 %!test  # RelTol and NormControl option -- higher accuracy
 %! opt = odeset ("RelTol", 1e-8, "NormControl", "on");
 %! sol = ode23 (@fpol, [0 2], [2 0], opt);
@@ -497,14 +497,14 @@
 
 %!test # Check that imaginary part of solution does not get inverted
 %! sol = ode23 (@(x,y) 1, [0 1], 1i);
-%! assert (imag (sol.y), ones (size (sol.y)))
+%! assert (imag (sol.y), ones (size (sol.y)));
 %! [x, y] = ode23 (@(x,y) 1, [0 1], 1i);
-%! assert (imag (y), ones (size (y)))
+%! assert (imag (y), ones (size (y)));
 
 ## Test input validation
-%!error ode23 ()
-%!error ode23 (1)
-%!error ode23 (1,2)
+%!error <Invalid call> ode23 ()
+%!error <Invalid call> ode23 (1)
+%!error <Invalid call> ode23 (1,2)
 %!error <TRANGE must be a numeric> ode23 (@fpol, {[0 25]}, [3 15 1])
 %!error <TRANGE must be a .* vector> ode23 (@fpol, [0 25; 25 0], [3 15 1])
 %!error <TRANGE must contain at least 2 elements> ode23 (@fpol, [1], [3 15 1])
--- a/scripts/ode/ode23s.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/ode23s.m	Sun May 16 09:44:35 2021 +0200
@@ -283,7 +283,7 @@
 %! [vt, vy] = ode23s (fun, [0 20], [2 0]);
 %! toc ()
 %! ## Plotting the result
-%! plot(vt,vy(:,1),'-o');
+%! plot (vt,vy(:,1),'-o');
 
 %!demo
 %! ## Demo function: stiff Van Der Pol equation
@@ -295,7 +295,7 @@
 %! [vt, vy] = ode23s (fun, [0 20], [2 0], odeopts);
 %! toc ()
 %! ## Plotting the result
-%! plot(vt,vy(:,1),'-o');
+%! plot (vt,vy(:,1),'-o');
 
 %!demo
 %! ## Demo function: stiff Van Der Pol equation
@@ -306,7 +306,7 @@
 %! [vt, vy] = ode23s (fun, [0 200], [2 0]);
 %! toc ()
 %! ## Plotting the result
-%! plot(vt,vy(:,1),'-o');
+%! plot (vt,vy(:,1),'-o');
 
 %!demo
 %! ## Demo function: stiff Van Der Pol equation
@@ -318,7 +318,7 @@
 %! [vt, vy] = ode23s (fun, [0 200], [2 0], odeopts);
 %! toc ()
 %! ## Plotting the result
-%! plot(vt,vy(:,1),'-o');
+%! plot (vt,vy(:,1),'-o');
 
 %!demo
 %! ## Demonstrate convergence order for ode23s
@@ -357,7 +357,7 @@
 ## We are using the "Van der Pol" implementation for all tests that are done
 ## for this function.  For further tests we also define a reference solution
 ## (computed at high accuracy).
-%!function ydot = fpol (t, y)  # The Van der Pol ODE
+%!function ydot = fpol (t, y, varargin)  # The Van der Pol ODE
 %!  ydot = [y(2); 10 * (1 - y(1)^2) * y(2) - y(1)];
 %!endfunction
 %!function ydot = jac (t, y)   # The Van der Pol ODE
@@ -367,12 +367,12 @@
 %!  ref = [1.8610687248524305  -0.0753216319179125];
 %!endfunction
 %!function [val, trm, dir] = feve (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = zeros (2,1);            # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
 %!function [val, trm, dir] = fevn (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = ones (2,1);             # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
@@ -412,7 +412,7 @@
 %! [t, y] = ode23s (@fpol, [0 2], [2 0], 12, 13, "KL");
 %! assert ([t(end), y(end,:)], [2, fref], 1e-3);
 %!test  # empty OdePkg structure *but* extra input arguments
-%! opt = odeset;
+%! opt = odeset ();
 %! [t, y] = ode23s (@fpol, [0 2], [2 0], opt, 12, 13, "KL");
 %! assert ([t(end), y(end,:)], [2, fref], 1e-2);
 %!test  # InitialStep option
@@ -495,14 +495,14 @@
 
 %!test # Check that imaginary part of solution does not get inverted
 %! sol = ode23s (@(x,y) 1, [0 1], 1i);
-%! assert (imag (sol.y), ones (size (sol.y)))
+%! assert (imag (sol.y), ones (size (sol.y)));
 %! [x, y] = ode23s (@(x,y) 1, [0 1], 1i);
-%! assert (imag (y), ones (size (y)))
+%! assert (imag (y), ones (size (y)));
 
 ## Test input validation
-%!error ode23s ()
-%!error ode23s (1)
-%!error ode23s (1,2)
+%!error <Invalid call> ode23s ()
+%!error <Invalid call> ode23s (1)
+%!error <Invalid call> ode23s (1,2)
 %!error <TRANGE must be a numeric> ode23s (@fpol, {[0 25]}, [3 15 1])
 %!error <TRANGE must be a .* vector> ode23s (@fpol, [0 25; 25 0], [3 15 1])
 %!error <TRANGE must contain at least 2 elements> ode23s (@fpol, [1], [3 15 1])
--- a/scripts/ode/ode45.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/ode45.m	Sun May 16 09:44:35 2021 +0200
@@ -326,19 +326,19 @@
 
 ## We are using the Van der Pol equation for all tests.
 ## Further tests also define a reference solution (computed at high accuracy)
-%!function ydot = fpol (t, y)  # The Van der Pol ODE
+%!function ydot = fpol (t, y, varargin)  # The Van der Pol ODE
 %!  ydot = [y(2); (1 - y(1)^2) * y(2) - y(1)];
 %!endfunction
 %!function ref = fref ()       # The computed reference solution
 %!  ref = [0.32331666704577, -1.83297456798624];
 %!endfunction
 %!function [val, trm, dir] = feve (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = zeros (2,1);            # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
 %!function [val, trm, dir] = fevn (t, y, varargin)
-%!  val = fpol (t, y, varargin);  # We use the derivatives
+%!  val = fpol (t, y, varargin{:});  # We use the derivatives
 %!  trm = ones (2,1);             # that's why component 2
 %!  dir = ones (2,1);             # does not seem to be exact
 %!endfunction
@@ -401,7 +401,7 @@
 %! assert ([sol.x(5)-sol.x(4)], [1e-3], 1e-3);
 %!test  # Solve with intermediate step
 %! [t, y] = ode45 (@fpol, [0 1 2], [2 0]);
-%! assert (any((t-1) == 0));
+%! assert (any ((t-1) == 0));
 %! assert ([t(end), y(end,:)], [2, fref], 1e-3);
 %!test  # Solve in backward direction starting at t=0
 %! vref = [-1.205364552835178, 0.951542399860817];
@@ -414,7 +414,7 @@
 %!test  # Solve in backward direction starting at t=2, with intermediate step
 %! vref = [-1.205364552835178, 0.951542399860817];
 %! [t, y] = ode45 (@fpol, [2 0 -2], fref);
-%! idx = find(y < 0, 1, "first") - 1;
+%! idx = find (y < 0, 1, "first") - 1;
 %! assert ([t(idx), y(idx,:)], [0,2,0], 1e-2);
 %! assert ([t(end), y(end,:)], [-2, vref], 1e-2);
 %!test  # Solve another anonymous function in backward direction
@@ -510,13 +510,13 @@
 
 %!test # Check that imaginary part of solution does not get inverted
 %! sol = ode45 (@(x,y) 1, [0 1], 1i);
-%! assert (imag (sol.y), ones (size (sol.y)))
+%! assert (imag (sol.y), ones (size (sol.y)));
 %! [x, y] = ode45 (@(x,y) 1, [0 1], 1i);
-%! assert (imag (y), ones (size (y)))
+%! assert (imag (y), ones (size (y)));
 
-%!error ode45 ()
-%!error ode45 (1)
-%!error ode45 (1,2)
+%!error <Invalid call> ode45 ()
+%!error <Invalid call> ode45 (1)
+%!error <Invalid call> ode45 (1,2)
 %!error <TRANGE must be a numeric> ode45 (@fpol, {[0 25]}, [3 15 1])
 %!error <TRANGE must be a .* vector> ode45 (@fpol, [0 25; 25 0], [3 15 1])
 %!error <TRANGE must contain at least 2 elements> ode45 (@fpol, [1], [3 15 1])
--- a/scripts/ode/odeget.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/odeget.m	Sun May 16 09:44:35 2021 +0200
@@ -43,6 +43,10 @@
 
 function val = odeget (ode_opt, field, default = [])
 
+  if (nargin < 2)
+    print_usage ();
+  endif
+
   validateattributes (ode_opt, {"struct"}, {"nonempty"});
   validateattributes (field, {"char"}, {"nonempty"});
 
@@ -79,9 +83,9 @@
 %! warning ("off", "Octave:invalid-input-arg", "local");
 %! assert (odeget (odeset ("foo", 42), "foo"), 42);
 
-%!error odeget ()
-%!error odeget (1)
-%!error odeget (1,2,3,4,5)
+## Test input validation
+%!error <Invalid call> odeget ()
+%!error <Invalid call> odeget (1)
 %!error odeget (1, "opt1")
 %!error odeget (struct ("opt1", 1), 1)
 %!error odeget (struct ("opt1", 1), "foo")
--- a/scripts/ode/odeplot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/odeplot.m	Sun May 16 09:44:35 2021 +0200
@@ -91,7 +91,7 @@
     for i = 1:num_lines
       set (hlines(i), "xdata", told, "ydata", yold(i,:));
     endfor
-    drawnow;
+    drawnow ();
 
     retval = false;
 
--- a/scripts/ode/odeset.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/odeset.m	Sun May 16 09:44:35 2021 +0200
@@ -119,7 +119,7 @@
 ##
 ## @item @code{OutputFcn}: function_handle
 ## Function to monitor the state during the simulation.  For the form of
-## the function to use see @code{odeplot}.
+## the function to use @pxref{XREFodeplot,,@code{odeplot}}.
 ##
 ## @item @code{OutputSel}: scalar | vector
 ## Indices of elements of the state vector to be passed to the output
--- a/scripts/ode/private/check_default_input.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/private/check_default_input.m	Sun May 16 09:44:35 2021 +0200
@@ -23,7 +23,11 @@
 ##
 ########################################################################
 
-function [fun] = check_default_input (fun, trange, solver, varargin);
+function fun = check_default_input (fun, trange, solver, y0, yp0);
+
+  if (nargin < 4)
+    print_usage ();
+  endif
 
   ## Check fun
   validateattributes (fun, {"function_handle", "char"}, {}, solver, "fun");
@@ -57,7 +61,6 @@
   endif
 
   ## Check y0 and yp0
-  y0 = varargin{1};
   if (! isnumeric (y0) || ! isvector (y0))
     error ("Octave:invalid-input-arg",
            [solver ": Y0 must be a numeric vector"]);
@@ -65,7 +68,6 @@
   y0 = y0(:);
 
   if (nargin == 5)
-    yp0 = varargin{2};
     if (! isnumeric (yp0) || ! isvector (yp0))
       error ("Octave:invalid-input-arg",
              [solver ": YP0 must be a numeric vector"]);
--- a/scripts/ode/private/odemergeopts.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/private/odemergeopts.m	Sun May 16 09:44:35 2021 +0200
@@ -23,8 +23,12 @@
 ##
 ########################################################################
 
+## FIXME: there are some calls to odemergeopts with a "solver" argument
+## but we don't use that here.  Should the calls be fixed or should we
+## do something with the solver argument here?
+
 function options = odemergeopts (caller, useroptions, options, classes,
-                                 attributes);
+                                 attributes, solver);
 
   for [value, key] = options
 
--- a/scripts/ode/private/runge_kutta_23s.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/private/runge_kutta_23s.m	Sun May 16 09:44:35 2021 +0200
@@ -128,7 +128,7 @@
   endif
   W = M - dt*d*J;
 
-  if issparse (W)
+  if (issparse (W))
     [Lw, Uw, Pw, Qw, Rw] = lu  (W);
   else
     [Lw, Uw, Pw] = lu (W);
@@ -136,13 +136,13 @@
 
   ## compute the slopes
   F(:,1) = feval (fun, t, x, args{:});
-  if issparse (W)
+  if (issparse (W))
     k(:,1) = Qw * (Uw \ (Lw \ (Pw * (Rw \ (F(:,1) + dt*d*T)))));
   else
     k(:,1) = Uw \ (Lw \ (Pw * (F(:,1) + dt*d*T)));
   endif
   F(:,2) = feval (fun, t+a*dt, x+a*dt*k(:,1), args{:});
-  if issparse (W)
+  if (issparse (W))
     k(:,2) = Uw * (Uw \ (Lw \ (Pw * (Rw \ (F(:,2) - M*k(:,1)))))) + k(:,1);
   else
     k(:,2) = Uw \ (Lw \ (Pw * (F(:,2) - M*k(:,1)))) + k(:,1);
@@ -154,7 +154,7 @@
   if (nargout >= 3)
     ## 3rd order, needed in error formula
     F(:,3) = feval (fun, t+dt, x_next, args{:});
-    if issparse (W)
+    if (issparse (W))
       k(:,3) = Qw * (Uw \ (Lw \ (Pw * (Rw \ (F(:,3) - e32 * (M*k(:,2) - F(:,2)) - 2 * (M*k(:,1) - F(:,1)) + dt*d*T)))));
     else
       k(:,3) = Uw \ (Lw \ (Pw * (F(:,3) - e32 * (M*k(:,2) - F(:,2)) - 2 * (M*k(:,1) - F(:,1)) + dt*d*T)));
--- a/scripts/ode/private/runge_kutta_interpolate.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/ode/private/runge_kutta_interpolate.m	Sun May 16 09:44:35 2021 +0200
@@ -60,12 +60,12 @@
 ## at the time t_out using 2nd order Hermite interpolation.
 function x_out = quadratic_interpolation (t, x, der, t_out)
 
-  # coefficients of the parabola
+  ## coefficients of the parabola
   a = -(x(:,1) - x(:,2) - der(:).*(t(1)-t(2))) / (t(1) - t(2))^2;
   b = der(:) - 2*t(1).*a;
   c = x(:,1) - a*t(1)^2 - b*t(1);
 
-  # evaluate in t_out
+  ## evaluate in t_out
   x_out = a*t_out.^2 + b*t_out + c;
 
 endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/optimization/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/optimization/fminbnd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/fminbnd.m	Sun May 16 09:44:35 2021 +0200
@@ -97,7 +97,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -288,15 +288,15 @@
 function print_formatted_table (table)
   printf ("\n Func-count     x          f(x)         Procedure\n");
   for row=table
-    printf("%5.5s        %7.7s    %8.8s\t%s\n",
-           int2str (row.funccount), num2str (row.x,"%.5f"),
-           num2str (row.fx,"%.6f"), row.procedure);
+    printf ("%5.5s        %7.7s    %8.8s\t%s\n",
+            int2str (row.funccount), num2str (row.x,"%.5f"),
+            num2str (row.fx,"%.6f"), row.procedure);
   endfor
   printf ("\n");
 endfunction
 
 ## Print either a success termination message or bad news
-function print_exit_msg (info, opt=struct())
+function print_exit_msg (info, opt=struct ())
   printf ("");
   switch (info)
     case 1
--- a/scripts/optimization/fminsearch.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/fminsearch.m	Sun May 16 09:44:35 2021 +0200
@@ -55,8 +55,9 @@
 ## @code{200 * number_of_variables}, i.e., @code{200 * length (@var{x0})}.
 ## The value must be a positive integer.
 ##
-## For a description of the other options, see @code{optimset}.  To initialize
-## an options structure with default values for @code{fminsearch} use
+## For a description of the other options,
+## @pxref{XREFoptimset,,@code{optimset}}.  To initialize an options structure
+## with default values for @code{fminsearch} use
 ## @code{options = optimset ("fminsearch")}.
 ##
 ## @code{fminsearch} may also be called with a single structure argument
@@ -311,7 +312,7 @@
     endfor
   else
     ## Right-angled simplex based on co-ordinate axes.
-    alpha = scale * ones(n+1,1);
+    alpha = scale * ones (n+1,1);
     for j = 2:n+1
       V(:,j) = x0 + alpha(j)*V(:,j);
       x(:) = V(:,j);
@@ -362,7 +363,7 @@
       printf ("Iter. %2.0f,", k);
       printf ("  how = %-11s", [how ","]);
       printf ("nf = %3.0f,  f = %9.4e  (%2.1f%%)\n", nf, dirn * fmax, ...
-              100*(fmax-fmax_old)/(abs(fmax_old)+eps));
+              100*(fmax-fmax_old)/(abs (fmax_old)+eps));
     endif
     fmax_old = fmax;
 
@@ -578,5 +579,5 @@
 %! fminsearch (@(x) (Inf), 0, optimset ("FunValCheck", "on"));
 
 ## Test input validation
-%!error fminsearch ()
+%!error <Invalid call> fminsearch ()
 %!error fminsearch (1)
--- a/scripts/optimization/fminunc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/fminunc.m	Sun May 16 09:44:35 2021 +0200
@@ -70,7 +70,8 @@
 ## @var{x}, while @qcode{"TolFun"} is a tolerance for the objective function
 ## value @var{fval}.  The default is @code{1e-6} for both options.
 ##
-## For a description of the other options, see @code{optimset}.
+## For a description of the other options,
+## @pxref{XREFoptimset,,@code{optimset}}.
 ##
 ## On return, @var{x} is the location of the minimum and @var{fval} contains
 ## the value of the objective function at @var{x}.
@@ -128,7 +129,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 3 || ! isnumeric (x0))
+  if (nargin < 2 || ! isnumeric (x0))
     print_usage ();
   endif
 
--- a/scripts/optimization/fsolve.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/fsolve.m	Sun May 16 09:44:35 2021 +0200
@@ -78,8 +78,9 @@
 ## while @qcode{"TolFun"} is a tolerance for equations.  Default is @code{1e-6}
 ## for both @qcode{"TolX"} and @qcode{"TolFun"}.
 ##
-## For a description of the other options, see @code{optimset}.  To initialize
-## an options structure with default values for @code{fsolve} use
+## For a description of the other options,
+## @pxref{XREFoptimset,,@code{optimset}}.  To initialize an options structure
+## with default values for @code{fsolve} use
 ## @code{options = optimset ("fsolve")}.
 ##
 ## The first output @var{x} is the solution while the second output @var{fval}
@@ -186,7 +187,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 3 || ! isnumeric (x0))
+  if (nargin < 2 || ! isnumeric (x0))
     print_usage ();
   endif
 
--- a/scripts/optimization/fzero.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/fzero.m	Sun May 16 09:44:35 2021 +0200
@@ -134,7 +134,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/optimization/glpk.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/glpk.m	Sun May 16 09:44:35 2021 +0200
@@ -485,7 +485,7 @@
 function [xopt, fmin, errnum, extra] = glpk (c, A, b, lb, ub, ctype, vartype, sense, param)
 
   ## If there is no input output the version and syntax
-  if (nargin < 3 || nargin > 9)
+  if (nargin < 3)
     print_usage ();
   endif
 
@@ -667,9 +667,9 @@
 %! assert (fmin, c' * xmin);
 %! assert (A * xmin, b);
 
-%!error<C .* finite values> glpk(NaN, 2, 3)
-%!error<A must be finite> glpk(1, NaN, 3)
-%!error<B must be finite> glpk(1, 2, NaN)
-%!error<LB must be a real-valued> glpk(1, 2, 3, NaN)
-%!error<UB must be a real-valued> glpk(1, 2, 3, 4, NaN)
-%!error<SENSE must be .* integer> glpk(1, 2, 3, 4, 5, "F", "C", NaN)
+%!error <C .* finite values> glpk (NaN, 2, 3)
+%!error <A must be finite> glpk (1, NaN, 3)
+%!error <B must be finite> glpk (1, 2, NaN)
+%!error <LB must be a real-valued> glpk (1, 2, 3, NaN)
+%!error <UB must be a real-valued> glpk (1, 2, 3, 4, NaN)
+%!error <SENSE must be .* integer> glpk (1, 2, 3, 4, 5, "F", "C", NaN)
--- a/scripts/optimization/humps.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/humps.m	Sun May 16 09:44:35 2021 +0200
@@ -63,10 +63,6 @@
 
 function [x, y] = humps (x = [0:0.05:1])
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   y = - 4*( 300*x.^4 - 720*x.^3 + 509*x.^2 - 87*x - 22) ./ ...
           ((10*x.^2 - 6*x + 1).*(20*x.^2 - 36*x + 17));
 
--- a/scripts/optimization/lsqnonneg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/lsqnonneg.m	Sun May 16 09:44:35 2021 +0200
@@ -41,8 +41,8 @@
 ## @var{x0} is an optional initial guess for the solution @var{x}.
 ##
 ## @var{options} is an options structure to change the behavior of the
-## algorithm (@pxref{XREFoptimset,,optimset}).  @code{lsqnonneg} recognizes
-## these options: @qcode{"MaxIter"}, @qcode{"TolX"}.
+## algorithm (@pxref{XREFoptimset,,@code{optimset}}).  @code{lsqnonneg}
+## recognizes these options: @qcode{"MaxIter"}, @qcode{"TolX"}.
 ##
 ## Outputs:
 ##
@@ -91,7 +91,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -237,10 +237,9 @@
 %! xnew = [0;0.6929];
 %! assert (lsqnonneg (C, d), xnew, 0.0001);
 
-# Test input validation
-%!error lsqnonneg ()
-%!error lsqnonneg (1)
-%!error lsqnonneg (1,2,3,4,5)
+## Test input validation
+%!error <Invalid call> lsqnonneg ()
+%!error <Invalid call> lsqnonneg (1)
 %!error <C .* must be numeric matrices> lsqnonneg ({1},2)
 %!error <C .* must be numeric matrices> lsqnonneg (ones (2,2,2),2)
 %!error <D must be numeric matrices> lsqnonneg (1,{2})
--- a/scripts/optimization/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -6,6 +6,7 @@
   %reldir%/private/__fdjac__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__all_opts__.m \
   %reldir%/fminbnd.m \
   %reldir%/fminsearch.m \
--- a/scripts/optimization/optimget.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/optimget.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function retval = optimget (options, parname, default)
 
-  if (nargin < 2 || nargin > 4 || ! isstruct (options) || ! ischar (parname))
+  if (nargin < 2 || ! isstruct (options) || ! ischar (parname))
     print_usage ();
   endif
 
@@ -75,9 +75,8 @@
 %!assert (optimget (opts, "TolFun", 1e-3), 1e-3)
 
 ## Test input validation
-%!error optimget ()
-%!error optimget (1)
-%!error optimget (1,2,3,4,5)
+%!error <Invalid call> optimget ()
+%!error <Invalid call> optimget (1)
 %!error optimget (1, "name")
 %!error optimget (struct (), 2)
 %!warning <unrecognized option: foobar> (optimget (opts, "foobar"));
--- a/scripts/optimization/optimset.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/optimset.m	Sun May 16 09:44:35 2021 +0200
@@ -199,6 +199,7 @@
 
 endfunction
 
+
 %!assert (isfield (optimset (), "TolFun"))
 %!assert (isfield (optimset ("tolFun", 1e-3), "TolFun"))
 %!assert (optimget (optimset ("tolx", 1e-2), "tOLx"), 1e-2)
--- a/scripts/optimization/pqpnonneg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/pqpnonneg.m	Sun May 16 09:44:35 2021 +0200
@@ -41,8 +41,8 @@
 ## @var{x0} is an optional initial guess for the solution @var{x}.
 ##
 ## @var{options} is an options structure to change the behavior of the
-## algorithm (@pxref{XREFoptimset,,optimset}).  @code{pqpnonneg} recognizes
-## one option: @qcode{"MaxIter"}.
+## algorithm (@pxref{XREFoptimset,,@code{optimset}}).  @code{pqpnonneg}
+## recognizes one option: @qcode{"MaxIter"}.
 ##
 ## Outputs:
 ##
@@ -93,7 +93,7 @@
     return;
   endif
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -239,10 +239,9 @@
 %! d = rand (20, 1);
 %! assert (pqpnonneg (C'*C, -C'*d), lsqnonneg (C, d), 100*eps);
 
-# Test input validation
-%!error pqpnonneg ()
-%!error pqpnonneg (1)
-%!error pqpnonneg (1,2,3,4,5)
+## Test input validation
+%!error <Invalid call> pqpnonneg ()
+%!error <Invalid call> pqpnonneg (1)
 %!error <C .* must be numeric matrices> pqpnonneg ({1},2)
 %!error <C .* must be numeric matrices> pqpnonneg (ones (2,2,2),2)
 %!error <D must be numeric matrices> pqpnonneg (1,{2})
--- a/scripts/optimization/qp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/qp.m	Sun May 16 09:44:35 2021 +0200
@@ -273,8 +273,8 @@
   endif
 
   ## Validate inequality constraints.
-  if (nargs > 7 && isempty (A_in) && ! (isempty(A_lb) || isempty(A_ub)))
-    warning("qp: empty inequality constraint matrix but non-empty bound vectors");
+  if (nargs > 7 && isempty (A_in) && ! (isempty (A_lb) || isempty (A_ub)))
+    warning ("qp: empty inequality constraint matrix but non-empty bound vectors");
   endif
 
   if (nargs > 7 && ! isempty (A_in))
--- a/scripts/optimization/sqp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/optimization/sqp.m	Sun May 16 09:44:35 2021 +0200
@@ -29,7 +29,7 @@
 ## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h})
 ## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h}, @var{lb}, @var{ub})
 ## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h}, @var{lb}, @var{ub}, @var{maxiter})
-## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h}, @var{lb}, @var{ub}, @var{maxiter}, @var{tol})
+## @deftypefnx {} {[@dots{}] =} sqp (@var{x0}, @var{phi}, @var{g}, @var{h}, @var{lb}, @var{ub}, @var{maxiter}, @var{tolerance})
 ## Minimize an objective function using sequential quadratic programming (SQP).
 ##
 ## Solve the nonlinear program
@@ -127,7 +127,7 @@
 ## The seventh argument @var{maxiter} specifies the maximum number of
 ## iterations.  The default value is 100.
 ##
-## The eighth argument @var{tol} specifies the tolerance for the stopping
+## The eighth argument @var{tolerance} specifies the tolerance for the stopping
 ## criteria.  The default value is @code{sqrt (eps)}.
 ##
 ## The value returned in @var{info} may be one of the following:
@@ -197,7 +197,7 @@
 
   globals = struct (); # data and handles, needed and changed by subfunctions
 
-  if (nargin < 2 || nargin > 8 || nargin == 5)
+  if (nargin < 2 || nargin == 5)
     print_usage ();
   endif
 
@@ -297,7 +297,7 @@
         if (isa (x0, "single"))
           globals.lb = tmp_lb = -realmax ("single");
         else
-          globals.lb = tmp_lb = -realmax;
+          globals.lb = tmp_lb = -realmax ();
         endif
       else
         error ("sqp: invalid lower bound");
@@ -312,7 +312,7 @@
         if (isa (x0, "single"))
           globals.ub = tmp_ub = realmax ("single");
         else
-          globals.ub = tmp_ub = realmax;
+          globals.ub = tmp_ub = realmax ();
         endif
       else
         error ("sqp: invalid upper bound");
@@ -390,8 +390,8 @@
 
   info = 0;
   iter = 0;
-  # report ();  # Called with no arguments to initialize reporting
-  # report (iter, qp_iter, alpha, __sqp_nfun__, obj);
+  ## report ();  # Called with no arguments to initialize reporting
+  ## report (iter, qp_iter, alpha, __sqp_nfun__, obj);
 
   while (++iter < iter_max)
 
@@ -533,7 +533,7 @@
 
     A = A_new;
 
-    # report (iter, qp_iter, alpha, __sqp_nfun__, obj);
+    ## report (iter, qp_iter, alpha, __sqp_nfun__, obj);
 
   endwhile
 
@@ -776,10 +776,9 @@
 %! assert (obj, obj_opt, sqrt (eps));
 
 ## Test input validation
-%!error sqp ()
-%!error sqp (1)
-%!error sqp (1,2,3,4,5,6,7,8,9)
-%!error sqp (1,2,3,4,5)
+%!error <Invalid call> sqp ()
+%!error <Invalid call> sqp (1)
+%!error <Invalid call> sqp (1,2,3,4,5)
 %!error sqp (ones (2,2))
 %!error sqp (1, cell (4,1))
 %!error sqp (1, cell (3,1), cell (3,1))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/path/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/path/import.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/path/import.m	Sun May 16 09:44:35 2021 +0200
@@ -65,4 +65,4 @@
 endfunction
 
 
-%!error <not yet implemented> import ("foobar");
+%!error <not yet implemented> import ("foobar")
--- a/scripts/path/matlabroot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/path/matlabroot.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function retval = matlabroot ()
 
-  retval = OCTAVE_HOME;
+  retval = OCTAVE_HOME ();
 
 endfunction
 
--- a/scripts/path/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/path/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -6,6 +6,7 @@
   %reldir%/private/getsavepath.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/import.m \
   %reldir%/matlabroot.m \
   %reldir%/pathdef.m \
--- a/scripts/path/pathdef.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/path/pathdef.m	Sun May 16 09:44:35 2021 +0200
@@ -44,10 +44,6 @@
 
 function val = pathdef ()
 
-  if (nargin > 0)
-    print_usage ();
-  endif
-
   ## Locate any project-specific .octaverc file.
   proj_octaverc = fullfile (pwd, ".octaverc");
   if (exist (proj_octaverc, "file"))
@@ -112,10 +108,10 @@
 %!   addpath (tmp_dir);
 %!   p1 = path ();
 %!   p2 = pathdef ();
-%!   assert (! isempty (strfind (p1, tmp_dir)))
-%!   assert (isempty (strfind (p2, tmp_dir)))
+%!   assert (! isempty (strfind (p1, tmp_dir)));
+%!   assert (isempty (strfind (p2, tmp_dir)));
 %! unwind_protect_cleanup
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %!   path (path_orig);
 %! end_unwind_protect
 
@@ -130,9 +126,9 @@
 %!   path_1 = path ();
 %!   p = pathdef ();
 %!   path_2 = path ();
-%!   assert (path_1, path_2)
+%!   assert (path_1, path_2);
 %! unwind_protect_cleanup
-%!   rmdir (tmp_dir);
+%!   sts = rmdir (tmp_dir);
 %!   path (path_orig);
 %! end_unwind_protect
 
--- a/scripts/path/savepath.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/path/savepath.m	Sun May 16 09:44:35 2021 +0200
@@ -201,7 +201,7 @@
 %!   endif
 %!   status = savepath (fname);
 %!   assert (status == 0);
-%!   old_dir = pwd;
+%!   old_dir = pwd ();
 %!   unwind_protect
 %!     cd (test_dir);
 %!     if (exist (fullfile (pwd, ".octaverc")))
@@ -230,6 +230,6 @@
 %!   end_unwind_protect
 %! unwind_protect_cleanup
 %!   confirm_recursive_rmdir (false, "local");
-%!   rmdir (test_dir, "s");
+%!   sts = rmdir (test_dir, "s");
 %!   unlink (fname);
 %! end_unwind_protect
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/pkg/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/pkg/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -28,7 +28,9 @@
   %reldir%/private/uninstall.m \
   %reldir%/private/unload_packages.m
 
-%canon_reldir%_FCN_FILES = %reldir%/pkg.m
+%canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
+  %reldir%/pkg.m
 
 %canon_reldir%dir = $(fcnfiledir)/pkg
 
--- a/scripts/pkg/pkg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/pkg.m	Sun May 16 09:44:35 2021 +0200
@@ -384,8 +384,10 @@
   persistent user_prefix = false;
   persistent prefix = false;
   persistent archprefix = -1;
-  persistent local_list = tilde_expand (fullfile ("~", ".octave_packages"));
-  persistent global_list = fullfile (OCTAVE_HOME (), "share", "octave",
+  persistent local_list = fullfile (user_config_dir (), "octave", ...
+                                    __octave_config_info__ ("major_version"), ...
+                                    "octave_packages");
+  persistent global_list = fullfile (OCTAVE_HOME (), "share", "octave", ...
                                      "octave_packages");
 
   ## If user is superuser (posix) or the process has elevated rights (Windows),
@@ -406,7 +408,7 @@
 
   confirm_recursive_rmdir (false, "local");
 
-  # valid actions in alphabetical order
+  ## valid actions in alphabetical order
   available_actions = {"build", "describe", "global_list",  "install", ...
                        "list", "load", "local_list", "prefix", "rebuild", ...
                        "test", "uninstall", "unload", "update"};
@@ -569,9 +571,9 @@
                  global_list, global_install);
 
       unwind_protect_cleanup
-        cellfun ("unlink", local_files);
+        [~] = cellfun ("unlink", local_files);
         if (exist (tmp_dir, "file"))
-          rmdir (tmp_dir, "s");
+          [~] = rmdir (tmp_dir, "s");
         endif
       end_unwind_protect
 
--- a/scripts/pkg/private/build.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/build.m	Sun May 16 09:44:35 2021 +0200
@@ -91,11 +91,11 @@
 
     tar (tar_path, package_root, builddir);
     gzip (tar_path, builddir);
-    rmdir (build_root, "s");
+    [~] = rmdir (build_root, "s");
 
     ## Currently does nothing because gzip() removes the original tar
     ## file but that should change in the future (bug #43431).
-    unlink (tar_path);
+    [~] = unlink (tar_path);
   endfor
 
 endfunction
--- a/scripts/pkg/private/configure_make.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/configure_make.m	Sun May 16 09:44:35 2021 +0200
@@ -88,9 +88,9 @@
       cmd = ["cd '" src "'; " scenv " ./configure " flags];
       [status, output] = shell (cmd, verbose);
       if (status != 0)
-        rmdir (desc.dir, "s");
+        sts = rmdir (desc.dir, "s");
         disp (output);
-        error ("pkg: error running the configure script for %s.", desc.name);
+        error ("pkg: error running the configure script for %s", desc.name);
       endif
     endif
 
@@ -105,9 +105,9 @@
       [status, output] = shell (sprintf ("%s make --jobs %i --directory '%s'",
                                          scenv, jobs, src), verbose);
       if (status != 0)
-        rmdir (desc.dir, "s");
+        sts = rmdir (desc.dir, "s");
         disp (output);
-        error ("pkg: error running 'make' for the %s package.", desc.name);
+        error ("pkg: error running 'make' for the %s package", desc.name);
       endif
     endif
 
@@ -169,7 +169,7 @@
     if (have_sh)
       cmd = ['sh.exe -c "' cmd '"'];
     else
-      error ("pkg: unable to find the command shell.");
+      error ("pkg: unable to find the command shell");
     endif
   endif
   ## if verbose, we want to display the output in real time.  To do this, we
--- a/scripts/pkg/private/default_prefix.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/default_prefix.m	Sun May 16 09:44:35 2021 +0200
@@ -24,10 +24,11 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {[@var{prefix}, @var{archprefix} =} default_prefix (@var{global_install})
+## @deftypefn {} {[@var{prefix}, @var{archprefix} =} default_prefix (@var{global_install}, @var{desc})
 ## Undocumented internal function.
 ## @end deftypefn
 
+## FIXME: second input "desc" does not appear to be used.
 function [prefix, archprefix] = default_prefix (global_install, desc)
 
   if (global_install)
@@ -40,7 +41,8 @@
                              "packages");
     endif
   else
-    prefix = tilde_expand (fullfile ("~", "octave"));
+    prefix = fullfile (user_data_dir (), "octave", ...
+                       __octave_config_info__ ("major_version"), "packages");
     archprefix = prefix;
   endif
 
--- a/scripts/pkg/private/expand_rel_paths.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/expand_rel_paths.m	Sun May 16 09:44:35 2021 +0200
@@ -5,18 +5,23 @@
 ## See the file COPYRIGHT.md in the top-level directory of this
 ## distribution or <https://octave.org/copyright/>.
 ##
-## This program is free software: you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
 ## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
 ##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ## GNU General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
-## along with this program.  If not, see <https://www.gnu.org/licenses/>.
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
 
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{pkg_list} =} expand_rel_paths (@var{pkg_list})
@@ -26,7 +31,7 @@
 function pkg_list = expand_rel_paths (pkg_list)
 
   ## Prepend location of OCTAVE_HOME to install directories
-  loc = OCTAVE_HOME;
+  loc = OCTAVE_HOME ();
   for i = 1:numel (pkg_list)
     ## Be sure to only prepend OCTAVE_HOME to pertinent package paths
     if (strncmpi (pkg_list{i}.dir, "__OH__", 6))
--- a/scripts/pkg/private/get_forge_pkg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/get_forge_pkg.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
                                    name));
   if (succ)
     ## Remove blanks for simpler matching.
-    html(isspace(html)) = [];
+    html(isspace (html)) = [];
     ## Good.  Let's grep for the version.
     pat = "<tdclass=""package_table"">PackageVersion:</td><td>([\\d.]*)</td>";
     t = regexp (html, pat, "tokens");
--- a/scripts/pkg/private/install.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/install.m	Sun May 16 09:44:35 2021 +0200
@@ -52,18 +52,24 @@
     packages = local_packages;
   endif
 
+  if (ispc ())
+    oct_glob = @__wglob__;
+  else
+    oct_glob = @glob;
+  endif
+
   ## Uncompress the packages and read the DESCRIPTION files.
   tmpdirs = packdirs = descriptions = {};
   try
     ## Warn about non existent files.
     for i = 1:length (files)
-      if (isempty (glob (files{i})))
+      if (isempty (oct_glob (files{i})))
         warning ("file %s does not exist", files{i});
       endif
     endfor
 
     ## Unpack the package files and read the DESCRIPTION files.
-    files = glob (files);
+    files = oct_glob (files);
     packages_to_uninstall = [];
     for i = 1:length (files)
       tgz = files{i};
@@ -145,7 +151,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 +205,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 +224,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 +243,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 +258,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
@@ -276,16 +282,21 @@
       if (ispc)
         local_packages = standardize_paths (local_packages);
       endif
+      if (! exist (fileparts (local_list), "dir")
+          && ! mkdir (fileparts (local_list)))
+        error ("Octave:pkg:install:local-dir", ...
+               "pkg: Could not create directory for local package configuration");
+      endif
       save (local_list, "local_packages");
       installed_pkgs_lst = {local_packages{:}, global_packages{:}};
     endif
   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 +387,7 @@
   if (! isfolder (inst_dir))
     [status, msg] = mkdir (inst_dir);
     if (status != 1)
-      rmdir (desc.dir, "s");
+      sts = rmdir (desc.dir, "s");
       error ("the 'inst' directory did not exist and could not be created: %s",
              msg);
     endif
@@ -389,7 +400,7 @@
 
   src = fullfile (packdir, "src");
   if (! isfolder (src))
-    return
+    return;
   endif
 
   ## Copy files to "inst" and "inst/arch" (this is instead of 'make install').
@@ -451,7 +462,7 @@
         endif
         [status, output] = copyfile (archindependent, instdir);
         if (status != 1)
-          rmdir (desc.dir, "s");
+          sts = rmdir (desc.dir, "s");
           error ("Couldn't copy files from 'src' to 'inst': %s", output);
         endif
       endif
@@ -466,7 +477,7 @@
         endif
         [status, output] = copyfile (archdependent, archdir);
         if (status != 1)
-          rmdir (desc.dir, "s");
+          sts = rmdir (desc.dir, "s");
           error ("Couldn't copy files from 'src' to 'inst': %s", output);
         endif
       endif
@@ -509,7 +520,7 @@
     [status, output] = mkdir (desc.dir);
     if (status != 1)
       error ("couldn't create installation directory %s : %s",
-      desc.dir, output);
+             desc.dir, output);
     endif
   endif
 
@@ -520,7 +531,7 @@
   if (! dirempty (instdir))
     [status, output] = copyfile (fullfile (instdir, "*"), desc.dir);
     if (status != 1)
-      rmdir (desc.dir, "s");
+      sts = rmdir (desc.dir, "s");
       error ("couldn't copy files to the installation directory");
     endif
     if (isfolder (fullfile (desc.dir, getarch ()))
@@ -535,39 +546,39 @@
             if (! isfolder (octm3))
               [status, output] = mkdir (octm3);
               if (status != 1)
-                rmdir (desc.dir, "s");
+                sts = rmdir (desc.dir, "s");
                 error ("couldn't create installation directory %s : %s",
                        octm3, output);
               endif
             endif
             [status, output] = mkdir (octm2);
             if (status != 1)
-              rmdir (desc.dir, "s");
+              sts = rmdir (desc.dir, "s");
               error ("couldn't create installation directory %s : %s",
                      octm2, output);
             endif
           endif
           [status, output] = mkdir (octm1);
           if (status != 1)
-            rmdir (desc.dir, "s");
+            sts = rmdir (desc.dir, "s");
             error ("couldn't create installation directory %s : %s",
                    octm1, output);
           endif
         endif
         [status, output] = mkdir (octfiledir);
         if (status != 1)
-          rmdir (desc.dir, "s");
+          sts = rmdir (desc.dir, "s");
           error ("couldn't create installation directory %s : %s",
-          octfiledir, output);
+                 octfiledir, output);
         endif
       endif
       [status, output] = movefile (fullfile (desc.dir, getarch (), "*"),
                                    octfiledir);
-      rmdir (fullfile (desc.dir, getarch ()), "s");
+      sts = rmdir (fullfile (desc.dir, getarch ()), "s");
 
       if (status != 1)
-        rmdir (desc.dir, "s");
-        rmdir (octfiledir, "s");
+        sts = rmdir (desc.dir, "s");
+        sts = rmdir (octfiledir, "s");
         error ("couldn't copy files to the installation directory");
       endif
     endif
@@ -578,8 +589,8 @@
   packinfo = fullfile (desc.dir, "packinfo");
   [status, msg] = mkdir (packinfo);
   if (status != 1)
-    rmdir (desc.dir, "s");
-    rmdir (octfiledir, "s");
+    sts = rmdir (desc.dir, "s");
+    sts = rmdir (octfiledir, "s");
     error ("couldn't create packinfo directory: %s", msg);
   endif
 
@@ -599,8 +610,8 @@
       write_index (desc, fullfile (packdir, "inst"),
                    fullfile (packinfo, "INDEX"), global_install);
     catch
-      rmdir (desc.dir, "s");
-      rmdir (octfiledir, "s");
+      sts = rmdir (desc.dir, "s");
+      sts = rmdir (octfiledir, "s");
       rethrow (lasterror ());
     end_try_catch
   endif
@@ -632,8 +643,8 @@
   else
     [status, output] = copyfile (filepath, packinfo);
     if (status != 1)
-      rmdir (desc.dir, "s");
-      rmdir (octfiledir, "s");
+      sts = rmdir (desc.dir, "s");
+      sts = rmdir (octfiledir, "s");
       error ("Couldn't copy %s file: %s", filename, output);
     endif
   endif
@@ -721,8 +732,8 @@
   ## part in the main directory.
   archdir = fullfile (getarchprefix (desc, global_install),
                       [desc.name "-" desc.version], getarch ());
-  if (isfolder (getarchdir (desc, global_install)))
-    archpkg = fullfile (getarchdir (desc, global_install), nm);
+  if (isfolder (getarchdir (desc)))
+    archpkg = fullfile (getarchdir (desc), nm);
     archfid = fopen (archpkg, "at");
   else
     archpkg = instpkg;
@@ -730,17 +741,23 @@
   endif
 
   if (archfid >= 0 && instfid >= 0)
+    if (ispc ())
+      oct_glob = @__wglob__;
+    else
+      oct_glob = @glob;
+    endif
+
     ## Search all dot-m files for PKG commands.
-    lst = glob (fullfile (packdir, "inst", "*.m"));
+    lst = oct_glob (fullfile (packdir, "inst", "*.m"));
     for i = 1:length (lst)
       nam = lst{i};
       fwrite (instfid, extract_pkg (nam, ['^[#%][#%]* *' nm ': *(.*)$']));
     endfor
 
     ## Search all C++ source files for PKG commands.
-    cc_lst = glob (fullfile (packdir, "src", "*.cc"));
-    cpp_lst = glob (fullfile (packdir, "src", "*.cpp"));
-    cxx_lst = glob (fullfile (packdir, "src", "*.cxx"));
+    cc_lst = oct_glob (fullfile (packdir, "src", "*.cc"));
+    cpp_lst = oct_glob (fullfile (packdir, "src", "*.cpp"));
+    cxx_lst = oct_glob (fullfile (packdir, "src", "*.cxx"));
     lst = [cc_lst; cpp_lst; cxx_lst];
     for i = 1:length (lst)
       nam = lst{i};
@@ -804,8 +821,8 @@
       cd (wd);
     catch
       cd (wd);
-      rmdir (desc.dir, "s");
-      rmdir (getarchdir (desc), "s");
+      sts = rmdir (desc.dir, "s");
+      sts = rmdir (getarchdir (desc), "s");
       rethrow (lasterror ());
     end_try_catch
   endif
--- a/scripts/pkg/private/installed_packages.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/installed_packages.m	Sun May 16 09:44:35 2021 +0200
@@ -134,8 +134,8 @@
     header = sprintf ("%s | %s | %s\n", h1, h2, h3);
     printf (header);
     tmp = sprintf (repmat ("-", 1, length (header) - 1));
-    tmp(length(h1)+2) = "+";
-    tmp(length(h1)+length(h2)+5) = "+";
+    tmp(length (h1)+2) = "+";
+    tmp(length (h1)+length (h2)+5) = "+";
     printf ("%s\n", tmp);
 
     ## Print the packages.
--- a/scripts/pkg/private/load_packages_and_dependencies.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/load_packages_and_dependencies.m	Sun May 16 09:44:35 2021 +0200
@@ -61,6 +61,11 @@
     EXEC_PATH (execpath);
   endif
 
+  ## Update lexer for autocompletion if necessary
+  if (isguirunning && (length (idx) > 0))
+    __event_manager_update_gui_lexer__;
+  endif
+
 endfunction
 
 
--- a/scripts/pkg/private/rebuild.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/rebuild.m	Sun May 16 09:44:35 2021 +0200
@@ -46,7 +46,11 @@
     wd = pwd ();
     unwind_protect
       cd (prefix);
-      dirlist = glob (strcat (files, '-*'));
+      if (ispc ())
+        dirlist = __wglob__ (strcat (files, '-*'));
+      else
+        dirlist = glob (strcat (files, '-*'));
+      endif
     unwind_protect_cleanup
       cd (wd);
     end_unwind_protect
--- a/scripts/pkg/private/uninstall.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/uninstall.m	Sun May 16 09:44:35 2021 +0200
@@ -32,8 +32,8 @@
                     global_list, global_install)
 
   ## Get the list of installed packages.
-  [local_packages, global_packages] = installed_packages(local_list,
-                                                         global_list);
+  [local_packages, global_packages] = installed_packages (local_list,
+                                                          global_list);
   if (global_install)
     installed_pkgs_lst = {local_packages{:}, global_packages{:}};
   else
@@ -122,6 +122,11 @@
         endif
       endif
       if (isfolder (desc.dir))
+        ## FIXME: If first call to rmdir fails, then error() will
+        ##        stop further processing of getarchdir & archprefix.
+        ##        If this is, in fact, correct, then calls should
+        ##        just be shortened to rmdir (...) and let rmdir()
+        ##        report failure and reason for failure.
         [status, msg] = rmdir (desc.dir, "s");
         if (status != 1 && isfolder (desc.dir))
           error ("couldn't delete directory %s: %s", desc.dir, msg);
@@ -131,7 +136,7 @@
           error ("couldn't delete directory %s: %s", getarchdir (desc), msg);
         endif
         if (dirempty (desc.archprefix))
-          rmdir (desc.archprefix, "s");
+          sts = rmdir (desc.archprefix, "s");
         endif
       else
         warning ("directory %s previously lost", desc.dir);
@@ -140,8 +145,8 @@
 
     ## Write a new ~/.octave_packages.
     if (global_install)
-      if (length (remaining_packages) == 0)
-        unlink (global_list);
+      if (numel (remaining_packages) == 0)
+        [~] = unlink (global_list);
       else
         global_packages = save_order (remaining_packages);
         if (ispc)
@@ -152,8 +157,8 @@
         save (global_list, "global_packages");
       endif
     else
-      if (length (remaining_packages) == 0)
-        unlink (local_list);
+      if (numel (remaining_packages) == 0)
+        [~] = unlink (local_list);
       else
         local_packages = save_order (remaining_packages);
         if (ispc)
--- a/scripts/pkg/private/unload_packages.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/pkg/private/unload_packages.m	Sun May 16 09:44:35 2021 +0200
@@ -100,6 +100,9 @@
     if (any (idx))
       rmpath (d);
       ## FIXME: We should also check if we need to remove items from EXEC_PATH.
+      if (isguirunning)
+        __event_manager_update_gui_lexer__;
+      endif
     endif
   endfor
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/plot/appearance/__clabel__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/__clabel__.m	Sun May 16 09:44:35 2021 +0200
@@ -112,19 +112,19 @@
         if (abs (trot) > 90)
           trot += 180;
         endif
+
         if (ischar (z))
-          ht = text (tpos(1), tpos(2), clev, tlabel, "rotation", trot,
-                     "horizontalalignment", "center", "userdata", clev,
-                     "parent", hparent, varargin{:});
+          tpos = [tpos.' clev];
         elseif (! isempty (z))
-          ht = text (tpos(1), tpos(2), z, tlabel, "rotation", trot,
-                     "horizontalalignment", "center", "userdata", clev,
-                     "parent", hparent, varargin{:});
+          tpos = [tpos.' z];
         else
-          ht = text (tpos(1), tpos(2), tlabel, "rotation", trot,
-                     "horizontalalignment", "center", "userdata", clev,
-                     "parent", hparent, varargin{:});
+          tpos = [tpos.' 0];
         endif
+
+        ht = __go_text__ (hparent, "position", tpos, "string", tlabel, ...
+                                   "rotation", trot, "clipping", "on", ...
+                                   "horizontalalignment", "center", ...
+                                   "userdata", clev, varargin{:});
         h = [h; ht];
       endif
     endfor
--- a/scripts/plot/appearance/annotation.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/annotation.m	Sun May 16 09:44:35 2021 +0200
@@ -217,9 +217,8 @@
 
   ## options
   opts = varargin;
-  nopts = numel (opts);
   if (! isempty (opts))
-    if (fix (nopts/2) != nopts/2 || ! all (cellfun (@ischar, opts(1:2:end))))
+    if (mod (numel (opts), 2) != 0 || ! all (cellfun (@ischar, opts(1:2:end))))
       warning ("annotation: couldn't parse PROP/VAL pairs, skipping");
       opts = {};
     endif
@@ -277,7 +276,7 @@
   listener = {@update_figsize_points, hax};
   addlistener (hf, "position", listener);
 
-  delfcn = @() dellistener (hf, "position", listener);
+  delfcn = @(~, ~) dellistener (hf, "position", listener);
   set (hax, "deletefcn", delfcn);
 
 endfunction
@@ -329,7 +328,7 @@
 
   addlistener (hax, "figsize_points", listener);
 
-  delfcn = @() dellistener (hax, "figsize_points", listener);
+  delfcn = @(~, ~) dellistener (hax, "figsize_points", listener);
   set (h, "deletefcn", delfcn);
 
   addlistener (h, "units", {@update_position, h});
@@ -676,7 +675,7 @@
 
   ## String;
   prop = "String";
-  fcn = @() stringdlg (hpar, prop);
+  fcn = @(~, ~) stringdlg (hpar, prop);
   uimenu (hm, "label", prop, "callback", fcn);
 
   ## Font properties
@@ -744,7 +743,7 @@
   hm1 = uimenu ("parent", hui, "label", "Text");
 
   prop = "String";
-  fcn = @() stringdlg (hpar, prop);
+  fcn = @(~, ~) stringdlg (hpar, prop);
   uimenu (hm1, "label", prop, "callback", fcn);
 
   prop = "Color";
@@ -832,7 +831,10 @@
            proptable(1:3:end), proptable(2:3:end), proptable(3:3:end));
 endfunction
 
-function addbasemenu (hm, hpar, pname, vals, mainlabel = "")
+## FIXME: there are some calls to addbasemenu with option-like arguments
+## but we don't do anything with varargin here.  What is the right thing
+## to do?
+function addbasemenu (hm, hpar, pname, vals, mainlabel = "", varargin)
 
   if (isempty (mainlabel))
     mainlabel = pname;
@@ -851,7 +853,7 @@
       label = disp (val);
     endif
 
-    fcn = @() set (hpar, pname, val);
+    fcn = @(~, ~) set (hpar, pname, val);
     htmp(i) = uimenu (h, "label", label, "callback", fcn);
   endfor
 
@@ -1131,7 +1133,7 @@
 
 function XY = textcoordinates (hte, pos)
   ## Get the "tight" extent of the text object in points units
-  textpos = get(hte, "position");
+  textpos = get (hte, "position");
   rot = get (hte, "rotation");
   units = get (hte, "units");
 
@@ -1451,8 +1453,8 @@
 %! xl = xlim ();
 %! yl = [-1.2 1.5];
 %! ylim (yl);
-%! x0 = (x0 - xl(1)) / diff(xl);
-%! y0 = (y0 - yl(1)) / diff(yl);
+%! x0 = (x0 - xl(1)) / diff (xl);
+%! y0 = (y0 - yl(1)) / diff (yl);
 %!
 %! pos = get (gca (), "position");
 %! x0 = x0*pos(3) + pos(1);
@@ -1575,7 +1577,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error annotation ()
+%!error <Invalid call> annotation ()
 %!error <Invalid call to annotation> annotation ({"line"}, 1:2, 1:2)
 %!error <X and Y must be 2-element vectors> annotation ("line", {1:2}, 1:2)
 %!error <X and Y must be 2-element vectors> annotation ("line", 1:2, {1:2})
--- a/scripts/plot/appearance/axis.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/axis.m	Sun May 16 09:44:35 2021 +0200
@@ -54,14 +54,20 @@
 ## The following options control the aspect ratio of the axes.
 ##
 ## @table @asis
+## @item @qcode{"equal"}
+## Force x-axis unit distance to equal y-axis (and z-axis) unit distance.
+##
 ## @item @qcode{"square"}
 ## Force a square axis aspect ratio.
 ##
-## @item @qcode{"equal"}
-## Force x-axis unit distance to equal y-axis (and z-axis) unit distance.
+## @item @nospell{@qcode{"vis3d"}}
+## Set aspect ratio modes (@qcode{"DataAspectRatio"},
+## @qcode{"PlotBoxAspectRatio"}) to @qcode{"manual"} for rotation without
+## stretching.
 ##
-## @item @qcode{"normal"}
-## Restore default aspect ratio.
+## @item  @qcode{"normal"}
+## @itemx @qcode{"fill"}
+## Restore default automatically computed aspect ratios.
 ## @end table
 ##
 ## @noindent
@@ -83,8 +89,6 @@
 ## @item @qcode{"image"}
 ## Equivalent to @qcode{"tight"} and @qcode{"equal"}.
 ##
-## @item @nospell{@qcode{"vis3d"}}
-## Set aspect ratio modes to @qcode{"manual"} for rotation without stretching.
 ## @end table
 ##
 ## @noindent
@@ -250,7 +254,7 @@
         ## Fix aspect ratio modes for rotation without stretching.
         set (ca, "dataaspectratiomode", "manual",
                  "plotboxaspectratiomode", "manual");
-      elseif (strcmpi (opt, "normal"))
+      elseif (strcmpi (opt, "normal") || strcmpi (opt, "fill"))
         ## Set plotboxaspectratio to something obtuse so that switching
         ## back to "auto" will force a re-calculation.
         set (ca, "plotboxaspectratio", [3 2 1]);
@@ -369,6 +373,7 @@
     endif
 
   endfor
+
 endfunction
 
 ## Find the limits for axis ("tight").
@@ -583,14 +588,14 @@
 %!  axis ("autoy");
 %!
 %! subplot (326);
-%!  plot (t, sin(t), t, -2*sin(t/2));
+%!  plot (t, sin (t), t, -2*sin (t/2));
 %!  axis ("tight");
 %!  title ("tight");
 
 %!demo
 %! clf;
 %! x = 0:0.1:10;
-%! plot (x, sin(x));
+%! plot (x, sin (x));
 %! axis image;
 %! title ({"image", 'equivalent to "tight" & "equal"'});
 
--- a/scripts/plot/appearance/camlookat.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/camlookat.m	Sun May 16 09:44:35 2021 +0200
@@ -35,18 +35,18 @@
 ## the bounding box approximately fills the field of view.
 ##
 ## This command fixes the camera's viewing direction
-## (@code{camtarget() - campos()}), camera up vector (@pxref{XREFcamup,,camup})
-## and viewing angle (@pxref{XREFcamva,,camva}).  The camera target
-## (@pxref{XREFcamtarget,,camtarget}) and camera position
-## (@pxref{XREFcampos,,campos}) are changed.
-##
+## (@code{camtarget() - campos()}), camera up vector
+## (@pxref{XREFcamup,,@code{camup}}) and viewing angle
+## (@pxref{XREFcamva,,@code{camva}}).  The camera target
+## (@pxref{XREFcamtarget,,@code{camtarget}}) and camera position
+## (@pxref{XREFcampos,,@code{campos}}) are changed.
 ##
 ## If the argument is a list @var{handle_list}, then a single bounding box for
 ## all the objects is computed and the camera is then adjusted as above.
 ##
 ## If the argument is an axis object @var{hax}, then the children of the axis
 ## are used as @var{handle_list}.  When called with no inputs, it uses the
-## current axis (@pxref{XREFgca,,gca}).
+## current axis (@pxref{XREFgca,,@code{gca}}).
 ##
 ## @seealso{camorbit, camzoom, camroll}
 ## @end deftypefn
@@ -54,10 +54,6 @@
 
 function camlookat (hh)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     hax = gca ();
     hh = get (hax, "children");
@@ -67,26 +63,26 @@
       hh = get (hax, "children");
     elseif (all (ishghandle (hh)))
       hax = ancestor (hh, "axes");
-      if numel (hax) > 1
+      if (numel (hax) > 1)
         hax = unique ([hax{:}]);
       endif
       if (numel (hax) > 1)
-        error ("camlookat: HANDLE_LIST must be children of the same axes.");
+        error ("camlookat: HANDLE_LIST must be children of the same axes");
       endif
     endif
   endif
 
   if (isempty (hh))
-    return
-  end
+    return;
+  endif
 
   x0 = x1 = y0 = y1 = z0 = z1 = [];
   for i = 1:numel (hh)
     h = hh(i);
 
     if (! ishghandle (h))
-      error ("camlookat: Inputs must be handles.");
-    end
+      error ("camlookat: Inputs must be handles");
+    endif
 
     x0_ = min (get (h, "xdata")(:));
     x1_ = max (get (h, "xdata")(:));
@@ -206,7 +202,7 @@
 %!   camlookat (h2);
 %!   dir2 = camtarget () - campos ();
 %!   dir2 /= norm (dir2);
-%!   assert (dir, dir2, -2*eps)
+%!   assert (dir, dir2, -2*eps);
 %!   camlookat ([h1 h2]);
 %!   dir2 = camtarget () - campos ();
 %!   dir2 /= norm (dir2);
@@ -313,7 +309,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error <Invalid call> camlookat (1, 2)
+%!error <called with too many inputs> camlookat (1, 2)
 %!error <must be handle> camlookat ("a")
 %!error <children of the same axes>
 %! hf = figure ("visible", "off");
--- a/scripts/plot/appearance/camorbit.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/camorbit.m	Sun May 16 09:44:35 2021 +0200
@@ -49,11 +49,11 @@
 ## @end example
 ##
 ## These rotations are centered around the camera target
-## (@pxref{XREFcamtarget,,camtarget}).
+## (@pxref{XREFcamtarget,,@code{camtarget}}).
 ## First the camera position is pitched up or down by rotating it @var{phi}
 ## degrees around an axis orthogonal to both the viewing direction
 ## (specifically @code{camtarget() - campos()}) and the camera ``up vector''
-## (@pxref{XREFcamup,,camup}).
+## (@pxref{XREFcamup,,@code{camup}}).
 ## Example:
 ##
 ## @example
@@ -81,7 +81,7 @@
 ##
 ## When @var{coorsys} is set to @qcode{"camera"}, the camera is moved left or
 ## right by rotating it around an axis parallel to the camera up vector
-## (@pxref{XREFcamup,,camup}).
+## (@pxref{XREFcamup,,@code{camup}}).
 ## The input @var{dir} should not be specified in this case.
 ## Example:
 ##
@@ -116,7 +116,7 @@
   phi = varargin{2};
   if (! (isnumeric (theta) && isscalar (theta)
          && isnumeric (phi) && isscalar (phi)))
-    error ("camorbit: THETA and PHI must be numeric scalars")
+    error ("camorbit: THETA and PHI must be numeric scalars");
   endif
 
   if (nargin < 3)
@@ -124,7 +124,7 @@
   else
     coorsys = varargin{3};
     if (! any (strcmpi (coorsys, {"data" "camera"})))
-      error ("camorbit: COORSYS must be 'data' or 'camera'")
+      error ("camorbit: COORSYS must be 'data' or 'camera'");
     endif
   endif
 
@@ -132,13 +132,13 @@
     dir = "z";
   else
     if (strcmpi (coorsys, "camera"))
-      error ("camorbit: DIR must not be used with 'camera' COORSYS.");
+      error ("camorbit: DIR must not be used with 'camera' COORSYS");
     endif
     dir = varargin{4};
   endif
 
   if (ischar (dir))
-    switch tolower (dir)
+    switch (tolower (dir))
       case "x"
         dir = [1 0 0];
       case "y"
@@ -172,7 +172,7 @@
     yaw_ax = up;
   else
     yaw_ax = dir;
-  end
+  endif
 
   ## First pitch up then yaw right (order matters)
   pos = num2cell (campos (hax));
@@ -219,7 +219,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   sphere ();
-%!   camorbit(20, 30, "camera")
+%!   camorbit (20, 30, "camera")
 %!   p = campos ();
 %!   u = camup ();
 %!   ## Matlab 2008a
--- a/scripts/plot/appearance/campos.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/campos.m	Sun May 16 09:44:35 2021 +0200
@@ -145,7 +145,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   sphere();
+%!   sphere ();
 %!   p_orig = campos ();
 %!   m = campos ("mode");
 %!   assert (strcmp (m, "auto"));
--- a/scripts/plot/appearance/camup.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/camup.m	Sun May 16 09:44:35 2021 +0200
@@ -57,8 +57,8 @@
 ## @end example
 ##
 ## Modifying the up vector does not modify the camera target
-## (@pxref{XREFcamtarget,,camtarget}).  Thus, the camera up vector might not be
-## orthogonal to the direction of the camera's view:
+## (@pxref{XREFcamtarget,,@code{camtarget}}).  Thus, the camera up vector might
+## not be orthogonal to the direction of the camera's view:
 ##
 ## @example
 ## @group
--- a/scripts/plot/appearance/camva.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/camva.m	Sun May 16 09:44:35 2021 +0200
@@ -135,7 +135,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   sphere();
+%!   sphere ();
 %!   a_orig = camva ();
 %!   m = camva ("mode");
 %!   assert (strcmp (m, "auto"));
--- a/scripts/plot/appearance/camzoom.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/camzoom.m	Sun May 16 09:44:35 2021 +0200
@@ -114,14 +114,14 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   sphere();
+%!   sphere ();
 %!   x = camva ();
 %!   camzoom (2);
 %!   y = camva ();
 %!   ## Matlab 2016a
 %!   xm = 10.339584907201974;
 %!   ym = 5.1803362845094822;
-%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14)
+%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14);
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
@@ -138,7 +138,7 @@
 %!   ## Matlab 2014a
 %!   xm = 13.074668029506947;
 %!   ym = 2.6258806698721222;
-%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14)
+%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14);
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
@@ -154,7 +154,7 @@
 %!   camzoom (hax1, 2)
 %!   x = camva (hax1);
 %!   y = camva (hax2);
-%!   assert (tand (y/2) / tand (x/2), 2, 2*eps)
+%!   assert (tand (y/2) / tand (x/2), 2, 2*eps);
 %! unwind_protect_cleanup
 %!   close (hf);
 %! end_unwind_protect
--- a/scripts/plot/appearance/daspect.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/daspect.m	Sun May 16 09:44:35 2021 +0200
@@ -104,7 +104,7 @@
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! axis square;
 %! daspect ([1 1 1]);
 %! title ("square plot box with axis limits [0, 4, -2, 2]");
@@ -120,7 +120,7 @@
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! daspect ([1 2 1]);
 %! pbaspect ([2 1 1]);
 %! title ("2x1 plot box with axis limits [0, 4, -2, 2]");
@@ -128,18 +128,18 @@
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x, sin(x));
+%! plot (x,cos (x), x, sin (x));
 %! axis square;
-%! set (gca, "activepositionproperty", "position");
+%! set (gca, "positionconstraint", "innerposition");
 %! daspect ([1 1 1]);
 %! title ("square plot box with axis limits [0, 4, -2, 2]");
 
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! axis ([0 4 -1 1]);
-%! set (gca, "activepositionproperty", "position");
+%! set (gca, "positionconstraint", "innerposition");
 %! daspect ([2 1 1]);
 %! title ("square plot box with axis limits [0, 4, -1, 1]");
 
--- a/scripts/plot/appearance/datetick.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/datetick.m	Sun May 16 09:44:35 2021 +0200
@@ -94,7 +94,7 @@
 %! xlabel ("year");
 %! ylabel ("average price");
 %! title ("datetick() with MM/DD/YY format");
-%! ax = gca;
+%! ax = gca ();
 %! set (ax, "xtick", datenum (1990:5:2005,1,1));
 %! datetick ("x", 2, "keepticks");
 %! set (ax, "ytick", 12:16);
--- a/scripts/plot/appearance/hidden.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/hidden.m	Sun May 16 09:44:35 2021 +0200
@@ -48,9 +48,7 @@
 
 function state = hidden (mode = "toggle")
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! ischar (mode))
       error ("hidden: MODE must be a string");
     elseif (! any (strcmpi (mode, {"on", "off"})))
--- a/scripts/plot/appearance/legend.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/legend.m	Sun May 16 09:44:35 2021 +0200
@@ -195,7 +195,11 @@
 
   ## Use the old legend code to handle gnuplot toolkit
   if (strcmp (graphics_toolkit (), "gnuplot"))
-    [hleg, hleg_obj, hplot, labels] = __gnuplot_legend__ (varargin{:});
+    if (nargout > 0)
+      [hleg, hleg_obj, hplot, labels] = __gnuplot_legend__ (varargin{:});
+    else
+      __gnuplot_legend__ (varargin{:});
+    endif
     return;
   endif
 
@@ -309,17 +313,17 @@
     hf = ancestor (hax, "figure");
 
     add_safe_listener (hl, hf, "colormap", ...
-                       @() set (hl, "colormap", get (hax, "colormap")));
+                       @(~, ~) set (hl, "colormap", get (hax, "colormap")));
 
     add_safe_listener (hl, hax, "position", {@maybe_update_layout_cb, hl});
     add_safe_listener (hl, hax, "tightinset", ...
-                       @(h) update_layout_cb (get (h, "__legend_handle__")));
+                       @(h, ~) update_layout_cb (get (h, "__legend_handle__")));
     add_safe_listener (hl, hax, "clim", ...
-                       @(hax) set (hl, "clim", get (hax, "clim")));
+                       @(hax, ~) set (hl, "clim", get (hax, "clim")));
     add_safe_listener (hl, hax, "colormap", ...
-                       @(hax) set (hl, "colormap", get (hax, "colormap")));
+                       @(hax, ~) set (hl, "colormap", get (hax, "colormap")));
     add_safe_listener (hl, hax, "fontsize", ...
-                       @(hax) set (hl, "fontsize", 0.9*get (hax, "fontsize")));
+                       @(hax, ~) set (hl, "fontsize", 0.9*get (hax, "fontsize")));
     add_safe_listener (hl, hax, "children", {@legend_autoupdate_cb, hl});
 
     ## Listeners to legend properties
@@ -345,8 +349,8 @@
     addlistener (hl, "string", @update_string_cb);
 
     addlistener (hl, "textcolor", ...
-                 @(h) set (findobj (h, "type", "text"), ...
-                           "color", get (hl, "textcolor")));
+                 @(h, ~) set (findobj (h, "type", "text"), ...
+                               "color", get (hl, "textcolor")));
 
     addlistener (hl, "visible", @update_visible_cb);
 
@@ -378,7 +382,7 @@
 
 endfunction
 
-function update_box_cb (hl)
+function update_box_cb (hl, ~)
 
   if (strcmp (get (hl, "box"), "on"))
     if (strcmp (get (hl, "color"), "none"))
@@ -404,23 +408,27 @@
 
 endfunction
 
-function update_edgecolor_cb (hl)
+function update_edgecolor_cb (hl, ~)
 
   ecolor = get (hl, "edgecolor");
   set (hl, "xcolor", ecolor, "ycolor", ecolor);
 
 endfunction
 
-function update_position_cb (hl)
+function update_position_cb (hl, ~)
 
   updating = getappdata (hl, "__updating_layout__");
   if (isempty (updating) || ! updating)
-    set (hl, "location", "none");
+    if (! strcmp (get (hl, "location"), "none"))
+      set (hl, "location", "none");
+    else
+      update_layout_cb (hl);
+    endif
   endif
 
 endfunction
 
-function update_string_cb (hl)
+function update_string_cb (hl, ~)
 
   ## Check that the number of legend item and the number of labels match
   ## before calling update_layout_cb.
@@ -454,7 +462,7 @@
 
 endfunction
 
-function update_visible_cb (hl)
+function update_visible_cb (hl, ~)
 
   location = get (hl, "location");
   if (strcmp (location(end:-1:end-3), "edis"))
@@ -463,7 +471,7 @@
 
 endfunction
 
-function reset_cb (ht, evt, hl, deletelegend = true)
+function reset_cb (ht, ~, hl, deletelegend = true)
 
   if (ishghandle (hl))
     listeners = getappdata (hl, "__listeners__");
@@ -480,7 +488,7 @@
 
 endfunction
 
-function delete_legend_cb (hl)
+function delete_legend_cb (hl, ~)
 
   reset_cb ([], [], hl, false);
 
@@ -525,7 +533,7 @@
 
   addproperty ("numcolumnsmode", hl, "radio", "{auto}|manual");
 
-  addlistener (hl, "numcolumns", @(h) set (h, "numcolumnsmode", "manual"));
+  addlistener (hl, "numcolumns", @(h, ~) set (h, "numcolumnsmode", "manual"));
 
   addproperty ("autoupdate", hl, "radio", "{on}|off");
 
@@ -543,7 +551,7 @@
 
 endfunction
 
-function maybe_update_layout_cb (h, d, hl)
+function maybe_update_layout_cb (h, ~, hl)
 
   persistent updating = false;
 
@@ -569,7 +577,7 @@
 
 endfunction
 
-function update_numchild_cb (hl)
+function update_numchild_cb (hl, ~)
 
   if (strcmp (get (hl, "autoupdate"), "on"))
 
@@ -587,7 +595,7 @@
 
 endfunction
 
-function legend_autoupdate_cb (hax, d, hl)
+function legend_autoupdate_cb (hax, ~, hl)
 
   ## Get all current children including eventual peer plotyy axes children
   try
@@ -895,7 +903,7 @@
     return;
   endif
 
-  setappdata(hl, "__updating_layout__", true);
+  setappdata (hl, "__updating_layout__", true);
 
   ## Scale limits so that item positions are expressed in points, from
   ## top to bottom and from left to right or reverse depending on textposition
@@ -904,10 +912,10 @@
 
   unwind_protect
 
+    pos = get (hl, "position");
+
     if (update_item)
-      pos = get (hl, "position")(3:4);
-      set (hl, "xlim",  [0, pos(1)], "ylim",  [0, pos(2)]);
-
+      set (hl, "xlim",  [0, pos(3)], "ylim",  [0, pos(4)]);
       textright = strcmp (get (hl, "textposition"), "right");
       set (hl, "ydir", "reverse", ...
                "xdir", ifelse (textright, "normal", "reverse"));
@@ -919,15 +927,38 @@
       ## Prepare the array of text/icon pairs and update their position
       sz = update_texticon_position (hl, objlist);
     else
-      sz = [diff(get (hl, "xlim")), diff(get (hl, "ylim"))];
+      sz = getappdata (hl, "__item_bouding_box__");
     endif
 
     ## Place the legend
-    update_legend_position (hl, sz);
+    if (! strcmp (get (hl, "location"), "none"))
+      update_legend_position (hl, sz);
+    else
+      ## Custom location: Adapt width and height if necessary.
+      [x0, y0, x1, y1] = deal (0, 0, sz(1), sz(2));
+
+      if (sz(1) > pos(3))
+        pos(3) = sz(1);
+      else
+        dx = pos(3)-sz(1);
+        x0 -= dx/2;
+        x1 += dx/2;
+      endif
+
+      if (sz(2) > pos(4))
+        pos(4) = sz(2);
+      else
+        dy = pos(4)-sz(2);
+        y0 -= dy/2;
+        y1 += dy/2;
+      endif
+
+      set (hl, "position",  pos, "xlim", [x0 x1], "ylim", [y0 y1]);
+    endif
 
   unwind_protect_cleanup
     set (hl, "units", units);
-    setappdata(hl, "__updating_layout__", false);
+    setappdata (hl, "__updating_layout__", false);
   end_unwind_protect
 
 endfunction
@@ -1056,12 +1087,12 @@
       safe_property_link (hplt(1), hicon, lprops);
       safe_property_link (hplt(end), hmarker, mprops);
       addlistener (hicon, "ydata", ...
-                   @(h) set (hmarker, "ydata", get (h, "markerydata")));
+                   @(h, ~) set (hmarker, "ydata", get (h, "markerydata")));
       addlistener (hicon, "xdata", ...
-                   @(h) set (hmarker, "xdata", get (h, "markerxdata")));
+                   @(h, ~) set (hmarker, "xdata", get (h, "markerxdata")));
       addlistener (hmarker, "markersize", @update_marker_cb);
       add_safe_listener (hl, hplt(1), "beingdeleted",
-                         @() delete ([hicon hmarker]))
+                         @(~, ~) delete ([hicon hmarker]))
       if (! strcmp (typ, "__errplot__"))
         setappdata (hicon, "__creator__", typ);
       else
@@ -1099,11 +1130,11 @@
       safe_property_link (hplt(1), hicon, pprops);
       safe_property_link (hplt(end), htmp, pprops);
       addlistener (hicon, "ydata", ...
-                   @(h) set (htmp, "ydata", get (h, "innerydata")));
+                   @(h, ~) set (htmp, "ydata", get (h, "innerydata")));
       addlistener (hicon, "xdata", ...
-                   @(h) set (htmp, "xdata", get (h, "innerxdata")));
+                   @(h, ~) set (htmp, "xdata", get (h, "innerxdata")));
       add_safe_listener (hl, hplt(1), "beingdeleted",
-                         @() delete ([hicon htmp]))
+                         @(~, ~) delete ([hicon htmp]))
 
       setappdata (hicon, "__creator__", typ);
 
@@ -1119,9 +1150,9 @@
 function safe_property_link (h1, h2, props)
   for ii = 1:numel (props)
     prop = props{ii};
-    lsn = {h1, prop, @(h) set (h2, prop, get (h, prop))};
+    lsn = {h1, prop, @(h, ~) set (h2, prop, get (h, prop))};
     addlistener (lsn{:});
-    addlistener (h2, "beingdeleted", @() dellistener (lsn{:}));
+    addlistener (h2, "beingdeleted", @(~, ~) dellistener (lsn{:}));
   endfor
 endfunction
 
@@ -1143,7 +1174,7 @@
 
 endfunction
 
-function update_marker_cb (h)
+function update_marker_cb (h, ~)
 
   if (get (h, "markersize") > 8)
     set (h, "markersize", 8);
@@ -1237,7 +1268,7 @@
 
     nrow = ceil (nitem / ncol);
 
-    colwidth = arrayfun (@(idx) max(ext(idx:ncol:end, 1)),
+    colwidth = arrayfun (@(idx) max (ext(idx:ncol:end, 1)),
                          1:ncol);
     y = vmargin;
     for ii = 1:nrow
@@ -1278,6 +1309,7 @@
   endif
 
   sz = [xmax, ymax];
+  setappdata (hl, "__item_bouding_box__", sz);
 
 endfunction
 
@@ -1347,12 +1379,13 @@
       set (hicon, "markerxdata", x0, "markerydata", y0, ...
            "xdata", xdata, "ydata", ydata);
     case "__scatter__"
-      set (hicon, "xdata", mean(xdata), "ydata", mean(ydata));
+      set (hicon, "xdata", mean (xdata), "ydata", mean (ydata));
     case "__stem__"
       xdata(2) -= (get (get (hicon, "peer_object"), "markersize") / 2);
       set (hicon, "markerxdata", xdata(2), "markerydata", mean (ydata), ...
            "xdata", xdata, "ydata", [mean(ydata), mean(ydata)]);
   endswitch
+
 endfunction
 
 function pos = boxposition (axpos, pba, pbam, dam)
@@ -1749,7 +1782,7 @@
 %!demo
 %! clf;
 %! x = 0:0.1:7;
-%! h = plot (x,sin(x), x,cos(x), x,sin(x.^2/10), x,cos(x.^2/10));
+%! h = plot (x,sin (x), x,cos (x), x,sin (x.^2/10), x,cos (x.^2/10));
 %! title ("Only the sin() objects have keylabels");
 %! legend (h([1, 3]), {"sin (x)", "sin (x^2/10)"}, "location", "southwest");
 
--- a/scripts/plot/appearance/lighting.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/lighting.m	Sun May 16 09:44:35 2021 +0200
@@ -184,10 +184,10 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   ha = axes;
+%!   ha = axes ();
 %!   hm = mesh (sombrero ());
-%!   hp = patch;
-%!   hs = surface;
+%!   hp = patch ();
+%!   hs = surface ();
 %!   lighting flat
 %!   assert (get (hp, "facelighting"), "flat");
 %!   assert (get (hs, "facelighting"), "flat");
@@ -225,7 +225,7 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error lighting ()
+%!error <Invalid call> lighting ()
 %!error lighting (1, 2, "flat")
 %!error <MODE must be a string> lighting (-1)
 %!error <MODE must be a string> lighting ({})
--- a/scripts/plot/appearance/material.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/material.m	Sun May 16 09:44:35 2021 +0200
@@ -227,8 +227,8 @@
 %!test
 %! hf = figure ("Visible", "off");
 %! unwind_protect
-%!   hp = patch;
-%!   hs = surface;
+%!   hp = patch ();
+%!   hs = surface ();
 %!   material dull
 %!   assert (get (hp, "ambientstrength"), 0.3);
 %!   assert (get (hs, "ambientstrength"), 0.3);
@@ -296,7 +296,7 @@
 
 %!test
 %! refl_props = material ("metal");
-%! assert (refl_props, {0.3, 0.3, 1, 25, 0.5})
+%! assert (refl_props, {0.3, 0.3, 1, 25, 0.5});
 
 ## Test input validation
 %!error <Invalid call to material> material ()
@@ -305,7 +305,7 @@
 %!error <Invalid call to material> a = material (-1, 2)
 %!error <Invalid call to material> a = material ({})
 %!error <Invalid call to material> a = material ([.3 .4 .5])
-%!error <Invalid call to material> [a, b] = material ()
+%!error <called with too many outputs> [a, b] = material ()
 %!error <first argument must be a list of handles> material (-1, "metal")
 %!error <unknown material type 'foo'> material foo
 %!error <incorrect number of elements in material vector> material (-1)
--- a/scripts/plot/appearance/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -5,9 +5,11 @@
 %canon_reldir%_PRIVATE_FCN_FILES = \
   %reldir%/private/__axis_label__.m \
   %reldir%/private/__axis_limits__.m \
-  %reldir%/private/__gnuplot_legend__.m
+  %reldir%/private/__gnuplot_legend__.m \
+  %reldir%/private/__tickangle__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__clabel__.m \
   %reldir%/__getlegenddata__.m \
   %reldir%/__rotate_around_axis__.m \
@@ -45,15 +47,18 @@
   %reldir%/whitebg.m \
   %reldir%/xlabel.m \
   %reldir%/xlim.m \
+  %reldir%/xtickangle.m \
   %reldir%/xticks.m \
   %reldir%/xticklabels.m \
   %reldir%/ylabel.m \
   %reldir%/ylim.m \
   %reldir%/yticks.m \
+  %reldir%/ytickangle.m \
   %reldir%/yticklabels.m \
   %reldir%/zlabel.m \
   %reldir%/zlim.m \
   %reldir%/zticks.m \
+  %reldir%/ztickangle.m \
   %reldir%/zticklabels.m
 
 %canon_reldir%dir = $(fcnfiledir)/plot/appearance
--- a/scripts/plot/appearance/pbaspect.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/pbaspect.m	Sun May 16 09:44:35 2021 +0200
@@ -105,21 +105,21 @@
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! pbaspect ([1 1 1]);
 %! title ("plot box is square");
 
 %!demo
 %! clf;
 %! x = 0:0.01:4;;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! pbaspect ([2 1 1]);
 %! title ("plot box aspect ratio is 2x1");
 
 %!demo
 %! clf;
 %! x = 0:0.01:4;
-%! plot (x,cos(x), x,sin(x));
+%! plot (x,cos (x), x,sin (x));
 %! daspect ([1 1 1]);
 %! pbaspect ([2 1 1]);
 %! title ("plot box is 2x1, and axes [0 4 -1 1]");
--- a/scripts/plot/appearance/private/__gnuplot_legend__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/private/__gnuplot_legend__.m	Sun May 16 09:44:35 2021 +0200
@@ -623,7 +623,7 @@
                           "box", box,
                           "xtick", [], "ytick", [],
                           "xlim", [0, 1], "ylim", [0, 1],
-                          "activepositionproperty", "position");
+                          "positionconstraint", "innerposition");
           setappdata (hlegend, "__axes_handle__", ud);
           try
             addproperty ("__legend_handle__", ud(1), "handle", hlegend);
@@ -1063,7 +1063,7 @@
                 ## This violates strict Matlab compatibility, but reliably
                 ## renders an aesthetic result.
                 set (ca(i), "position",  unmodified_axes_position,
-                            "activepositionproperty", "outerposition");
+                            "positionconstraint", "outerposition");
               else
                 ## numel (ca) > 1 for axes overlays (like plotyy)
                 set (ca(i), "position", new_pos);
@@ -1182,8 +1182,8 @@
       outerposition = get (hleg, "unmodified_axes_outerposition");
       units = get (hax, "units");
       set (hax, "units", "points");
-      switch (get (hax, "activepositionproperty"))
-        case "position"
+      switch (get (hax, "positionconstraint"))
+        case "innerposition"
           set (hax, "outerposition", outerposition, "position", position);
         case "outerposition"
           set (hax, "position", position, "outerposition", outerposition);
@@ -1242,11 +1242,11 @@
 endfunction
 
 ## The legend "location" property has changed.
-function cb_legend_location (hleg, d)
+function cb_legend_location (hleg, ~)
 
-  ## If it isn't "none", which means manual positioning, then rebuild .
+  ## If it isn't "none", which means manual positioning, then rebuild.
   if (! strcmp (get (hleg, "location"), "none"))
-    cb_legend_update (hleg, d);
+    cb_legend_update (hleg, []);
   endif
 
 endfunction
@@ -1557,7 +1557,7 @@
 %!demo
 %! clf;
 %! x = 0:0.1:7;
-%! h = plot (x,sin(x), x,cos(x), x,sin(x.^2/10), x,cos(x.^2/10));
+%! h = plot (x,sin (x), x,cos (x), x,sin (x.^2/10), x,cos (x.^2/10));
 %! title ("Only the sin() objects have keylabels");
 %! legend (h([1, 3]), {"sin (x)", "sin (x^2/10)"}, "location", "southwest");
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/private/__tickangle__.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,68 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{retval} =} __tickangle__ (@var{caller}, @var{hax}, @var{angle})
+## Undocumented internal function.
+## @seealso{xtickangle, ytickangle, ztickangle}
+## @end deftypefn
+
+function retval = __tickangle__ (caller, hax, angle)
+
+  ax = tolower (caller(1));
+  switch (nargin)
+    case 1
+      retval = get (gca (), [ax, "ticklabelrotation"]);
+      return;
+
+    case 2
+      if (isaxes (hax))
+        retval = get (hax, [ax, "ticklabelrotation"]);
+        return;
+      else
+        angle = hax;
+        hax = [];
+      endif
+
+    case 3
+      if (! isaxes (hax))
+        error ([caller, ": HAX must be a handle to an axes object"]);
+      endif
+
+  endswitch
+
+  if (! (isscalar (angle) && isnumeric (angle) && isfinite (angle)))
+    error ([caller ": ANGLE must be a finite, numeric, scalar value"]);
+  elseif (nargout > 0)
+    error ([caller ": function called with output query and input set value"]);
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  endif
+
+  set (hax, [ax, "ticklabelrotation"], angle);
+
+endfunction
--- a/scripts/plot/appearance/rticks.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/rticks.m	Sun May 16 09:44:35 2021 +0200
@@ -120,7 +120,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   polar (linspace (0, pi, 20), rand (20,1));
-%!   hax = gca;
+%!   hax = gca ();
 %!   ticks = rticks;
 %!   assert (rticks (hax), ticks);
 %!   rticks (hax, [0 0.25 0.75 1 2]);
@@ -135,7 +135,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   polar (linspace (0, pi, 20), 1:20);
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("rticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = rticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = rticks (hax, 'mode')", "MODE is not yet implemented");
--- a/scripts/plot/appearance/shading.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/shading.m	Sun May 16 09:44:35 2021 +0200
@@ -265,10 +265,10 @@
 %!test
 %! hf = figure ("Visible", "off");
 %! unwind_protect
-%!   ha = axes;
+%!   ha = axes ();
 %!   hm = mesh (sombrero ());
-%!   hp = patch;
-%!   hs = surface;
+%!   hp = patch ();
+%!   hs = surface ();
 %!   shading interp;
 %!   assert (get (hp, "facecolor"), "interp");
 %!   assert (get (hs, "facecolor"), "interp");
@@ -308,7 +308,7 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error shading ()
+%!error <Invalid call> shading ()
 %!error shading (1, 2, "flat")
 %!error <MODE must be a valid string> shading (-1)
 %!error <MODE must be a valid string> shading ({})
--- a/scripts/plot/appearance/specular.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/specular.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
 
 function retval = specular (sx, sy, sz, lv, vv, se)
 
-  if (nargin < 5 || nargin > 6)
+  if (nargin < 5)
     print_usage ();
   endif
 
--- a/scripts/plot/appearance/text.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/text.m	Sun May 16 09:44:35 2021 +0200
@@ -326,6 +326,24 @@
 %! ylabel (1:2);
 %! title (1:2);
 
+%!demo
+%! clf;
+%! title ("Use of the \"interpreter\" property")
+%! xlim ([0 1])
+%! ylim ([-1 1])
+%! text (0.1, 0.5, "\"none\": erf(x) = (2/\\pi^{1/2})\\int_0^x e^{y^2}dy", ...
+%!       "interpreter", "none", ...
+%!       "fontsize", 20, ...
+%!       "backgroundcolor", "r");
+%! text (0.1, 0, "\"tex\"(def.): erf(x) = (2/\\pi^{1/2})\\int_0^x e^{y^2}dy", ...
+%!       "fontsize", 20, ...
+%!       "backgroundcolor", "r");
+%! text (0.1, -0.5, "\"latex\": $erf(x) = (2/\\pi^{1/2})\\int_0^x e^{y^2}dy$", ...
+%!       "interpreter", "latex", ...
+%!       "fontsize", 20, ...
+%!       "backgroundcolor", "r");
+%! grid on;
+
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
--- a/scripts/plot/appearance/thetaticks.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/thetaticks.m	Sun May 16 09:44:35 2021 +0200
@@ -124,7 +124,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %! polar (linspace (0, pi, 20), rand (20,1));
-%!   hax = gca;
+%!   hax = gca ();
 %!   ticks = thetaticks;
 %!   assert (thetaticks (hax), ticks);
 %!   thetaticks (hax, [0 45 90 135 180]);
@@ -139,7 +139,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   polar (linspace (0, pi, 20), 1:20);
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("thetaticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = thetaticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = thetaticks (hax, 'mode')", "MODE is not yet implemented");
--- a/scripts/plot/appearance/view.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/view.m	Sun May 16 09:44:35 2021 +0200
@@ -110,13 +110,13 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   plot3 ([0,1], [0,1], [0,1]);
-%!   [az, el] = view;
+%!   [az, el] = view ();
 %!   assert ([az, el], [-37.5, 30], eps);
 %!   view (2);
-%!   [az, el] = view;
+%!   [az, el] = view ();
 %!   assert ([az, el], [0, 90], eps);
 %!   view ([1 1 0]);
-%!   [az, el] = view;
+%!   [az, el] = view ();
 %!   assert ([az, el], [135, 0], eps);
 %! unwind_protect_cleanup
 %!   close (hf);
@@ -125,11 +125,11 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   line;
-%!   [az, el] = view;
+%!   line ();
+%!   [az, el] = view ();
 %!   assert ([az, el], [0, 90], eps);
 %!   view (3);
-%!   [az, el] = view;
+%!   [az, el] = view ();
 %!   assert ([az, el], [-37.5, 30], eps);
 %! unwind_protect_cleanup
 %!   close (hf);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/xtickangle.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,93 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{angle} =} xtickangle ()
+## @deftypefnx {} {@var{angle} =} xtickangle (@var{hax})
+## @deftypefnx {} {} xtickangle (@var{angle})
+## @deftypefnx {} {} xtickangle (@var{hax}, @var{angle})
+## Query or set the rotation angle of the tick labels on the x-axis of the
+## current axes.
+##
+## When called without an argument, return the rotation angle in degrees of the
+## tick labels as specified in the axes property @qcode{"XTickLabelRotation"}.
+## When called with a numeric scalar @var{angle}, rotate the tick labels
+## counterclockwise to @var{angle} degrees.
+##
+## If the first argument @var{hax} is an axes handle, then operate on this axes
+## rather than the current axes returned by @code{gca}.
+##
+## Programming Note: Requesting a return value while also setting a specified
+## rotation will result in an error.
+##
+## @seealso{ytickangle, ztickangle, get, set}
+## @end deftypefn
+
+function retval = xtickangle (hax, angle)
+
+  switch (nargin)
+    case 0
+      retval = __tickangle__ (mfilename ());
+
+    case 1
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax);
+      else
+        __tickangle__ (mfilename (), hax);
+      endif
+
+    case 2
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax, angle);
+      else
+        __tickangle__ (mfilename (), hax, angle);
+      endif
+
+  endswitch
+
+endfunction
+
+
+%!test
+%! hf = figure ("visible", "off");
+%! hax = axes (hf);
+%! unwind_protect
+%!   xtickangle (45);
+%!   assert (xtickangle (), 45);
+%!   xtickangle (hax, 90);
+%!   a1 = xtickangle ();
+%!   a2 = xtickangle (hax);
+%!   assert (a1, a2);
+%!   assert (a1, 90);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <HAX must be a handle to an axes object> xtickangle (0, 45)
+%!error <ANGLE must be .* scalar> xtickangle (eye (2))
+%!error <ANGLE must be .* numeric> xtickangle ({90})
+%!error <ANGLE must be .* finite> xtickangle (Inf)
+%!error <called with output query and input set value> ang = xtickangle (45)
--- a/scripts/plot/appearance/xticklabels.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/xticklabels.m	Sun May 16 09:44:35 2021 +0200
@@ -142,7 +142,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "xticklabelmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = xticklabels;
 %!   assert (xticklabels (hax), vals1);
 %!   mode1 = xticklabels ("mode");
@@ -164,7 +164,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("xticklabels (-1, {})", "HAX must be a handle to an axes");
 %!   fail ("tmp = xticklabels (hax, {'A','B'})", "too many output arguments");
 %!   fail ("tmp = xticklabels (hax, [0, 1])", "too many output arguments");
--- a/scripts/plot/appearance/xticks.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/xticks.m	Sun May 16 09:44:35 2021 +0200
@@ -122,7 +122,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "xtickmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = xticks;
 %!   assert (xticks (hax), vals1);
 %!   mode1 = xticks ("mode");
@@ -143,7 +143,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("xticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = xticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = xticks (hax, 'auto')", "too many .* for arg: auto");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/ytickangle.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,93 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{angle} =} ytickangle ()
+## @deftypefnx {} {@var{angle} =} ytickangle (@var{hax})
+## @deftypefnx {} {} ytickangle (@var{angle})
+## @deftypefnx {} {} ytickangle (@var{hax}, @var{angle})
+## Query or set the rotation angle of the tick labels on the y-axis of the
+## current axes.
+##
+## When called without an argument, return the rotation angle in degrees of the
+## tick labels as specified in the axes property @qcode{"YTickLabelRotation"}.
+## When called with a numeric scalar @var{angle}, rotate the tick labels
+## counterclockwise to @var{angle} degrees.
+##
+## If the first argument @var{hax} is an axes handle, then operate on this axes
+## rather than the current axes returned by @code{gca}.
+##
+## Programming Note: Requesting a return value while also setting a specified
+## rotation will result in an error.
+##
+## @seealso{xtickangle, ztickangle, get, set}
+## @end deftypefn
+
+function retval = ytickangle (hax, angle)
+
+  switch (nargin)
+    case 0
+      retval = __tickangle__ (mfilename ());
+
+    case 1
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax);
+      else
+        __tickangle__ (mfilename (), hax);
+      endif
+
+    case 2
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax, angle);
+      else
+        __tickangle__ (mfilename (), hax, angle);
+      endif
+
+  endswitch
+
+endfunction
+
+
+%!test
+%! hf = figure ("visible", "off");
+%! hax = axes (hf);
+%! unwind_protect
+%!   ytickangle (45);
+%!   assert (ytickangle (), 45);
+%!   ytickangle (hax, 90);
+%!   a1 = ytickangle ();
+%!   a2 = ytickangle (hax);
+%!   assert (a1, a2);
+%!   assert (a1, 90);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <HAX must be a handle to an axes object> ytickangle (0, 45)
+%!error <ANGLE must be .* scalar> ytickangle (eye (2))
+%!error <ANGLE must be .* numeric> ytickangle ({90})
+%!error <ANGLE must be .* finite> ytickangle (Inf)
+%!error <called with output query and input set value> ang = ytickangle (45)
--- a/scripts/plot/appearance/yticklabels.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/yticklabels.m	Sun May 16 09:44:35 2021 +0200
@@ -142,7 +142,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "yticklabelmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = yticklabels;
 %!   assert (yticklabels (hax), vals1);
 %!   mode1 = yticklabels ("mode");
@@ -164,7 +164,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("yticklabels (-1, {})", "HAX must be a handle to an axes");
 %!   fail ("tmp = yticklabels (hax, {'A','B'})", "too many output arguments");
 %!   fail ("tmp = yticklabels (hax, [0, 1])", "too many output arguments");
--- a/scripts/plot/appearance/yticks.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/yticks.m	Sun May 16 09:44:35 2021 +0200
@@ -124,7 +124,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "ytickmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = yticks;
 %!   assert (yticks (hax), vals1);
 %!   mode1 = yticks ("mode");
@@ -145,7 +145,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("yticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = yticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = yticks (hax, 'auto')", "too many .* for arg: auto");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/ztickangle.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,93 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{angle} =} ztickangle ()
+## @deftypefnx {} {@var{angle} =} ztickangle (@var{hax})
+## @deftypefnx {} {} ztickangle (@var{angle})
+## @deftypefnx {} {} ztickangle (@var{hax}, @var{angle})
+## Query or set the rotation angle of the tick labels on the z-axis of the
+## current axes.
+##
+## When called without an argument, return the rotation angle in degrees of the
+## tick labels as specified in the axes property @qcode{"ZTickLabelRotation"}.
+## When called with a numeric scalar @var{angle}, rotate the tick labels
+## counterclockwise to @var{angle} degrees.
+##
+## If the first argument @var{hax} is an axes handle, then operate on this axes
+## rather than the current axes returned by @code{gca}.
+##
+## Programming Note: Requesting a return value while also setting a specified
+## rotation will result in an error.
+##
+## @seealso{xtickangle, ytickangle, get, set}
+## @end deftypefn
+
+function retval = ztickangle (hax, angle)
+
+  switch (nargin)
+    case 0
+      retval = __tickangle__ (mfilename ());
+
+    case 1
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax);
+      else
+        __tickangle__ (mfilename (), hax);
+      endif
+
+    case 2
+      if (nargout > 0)
+        retval = __tickangle__ (mfilename (), hax, angle);
+      else
+        __tickangle__ (mfilename (), hax, angle);
+      endif
+
+  endswitch
+
+endfunction
+
+
+%!test
+%! hf = figure ("visible", "off");
+%! hax = axes (hf);
+%! unwind_protect
+%!   ztickangle (45);
+%!   assert (ztickangle (), 45);
+%!   ztickangle (hax, 90);
+%!   a1 = ztickangle ();
+%!   a2 = ztickangle (hax);
+%!   assert (a1, a2);
+%!   assert (a1, 90);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <HAX must be a handle to an axes object> ztickangle (0, 45)
+%!error <ANGLE must be .* scalar> ztickangle (eye (2))
+%!error <ANGLE must be .* numeric> ztickangle ({90})
+%!error <ANGLE must be .* finite> ztickangle (Inf)
+%!error <called with output query and input set value> ang = ztickangle (45)
--- a/scripts/plot/appearance/zticklabels.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/zticklabels.m	Sun May 16 09:44:35 2021 +0200
@@ -80,7 +80,7 @@
       arg = varargin{2};
 
     otherwise
-      print_usage;
+      print_usage ();
 
   endswitch
 
@@ -132,7 +132,7 @@
     endswitch
 
   else
-    print_usage;
+    print_usage ();
   endif
 
 endfunction
@@ -142,7 +142,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "zticklabelmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = zticklabels;
 %!   assert (zticklabels (hax), vals1);
 %!   mode1 = zticklabels ("mode");
@@ -164,7 +164,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("zticklabels (-1, {})", "HAX must be a handle to an axes");
 %!   fail ("tmp = zticklabels (hax, {'A','B'})", "too many output arguments");
 %!   fail ("tmp = zticklabels (hax, [0, 1])", "too many output arguments");
--- a/scripts/plot/appearance/zticks.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/appearance/zticks.m	Sun May 16 09:44:35 2021 +0200
@@ -122,7 +122,7 @@
 %! hf = figure ("visible", "off");
 %! unwind_protect
 %!   set (gca, "ztickmode", "auto");
-%!   hax = gca;
+%!   hax = gca ();
 %!   vals1 = zticks;
 %!   assert (zticks (hax), vals1);
 %!   mode1 = zticks ("mode");
@@ -143,7 +143,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   fail ("zticks (-1, [0 1])", "HAX must be a handle to an axes");
 %!   fail ("tmp = zticks (hax, [0 1])", "too many output arguments");
 %!   fail ("tmp = zticks (hax, 'auto')", "too many .* for arg: auto");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/plot/draw/area.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/area.m	Sun May 16 09:44:35 2021 +0200
@@ -207,7 +207,7 @@
   set (kids, prop, get (h, prop));
 endfunction
 
-function move_baseline (h, d)
+function move_baseline (h, ~)
   persistent recursion = false;
 
   ## Don't allow recursion
@@ -225,7 +225,7 @@
           endif
         endif
       endfor
-      update_data (h, d);
+      update_data (h, []);
     unwind_protect_cleanup
       recursion = false;
     end_unwind_protect
@@ -233,7 +233,7 @@
 
 endfunction
 
-function update_data (h, d)
+function update_data (h, ~)
 
   hlist = get (h, "areagroup");
   bv = get (h, "basevalue");
@@ -288,7 +288,7 @@
 %! title ("area() plot of sorted data");
 
 ## Test input validation
-%!error area ()
+%!error <Invalid call> area ()
 %!error area (1,2,3,4)
 %!error <X and Y must be real vectors or matrices> area ({1})
 %!error <X and Y must be real vectors or matrices> area (1+i)
--- a/scripts/plot/draw/bar.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/bar.m	Sun May 16 09:44:35 2021 +0200
@@ -94,18 +94,11 @@
 ## @end example
 ##
 ## @noindent
-## The color of the bars is taken from the figure's colormap, such that
-##
-## @example
-## @group
-## bar (rand (10, 3));
-## colormap (summer (64));
-## @end group
-## @end example
-##
-## @noindent
-## will change the colors used for the bars.  The color of bars can also be set
-## manually using the @qcode{"facecolor"} property as shown below.
+## The default color for bars is taken from the axes' @qcode{"ColorOrder"}
+## property.  The default color for bars when a histogram option
+## (@qcode{"hist"}, @qcode{"histc"} is used is the @qcode{"Colormap"} property
+## of either the axes or figure.  The color of bars can also be set manually
+## using the @qcode{"facecolor"} property as shown below.
 ##
 ## @example
 ## @group
@@ -121,10 +114,9 @@
 
 function varargout = bar (varargin)
   varargout = cell (nargout, 1);
-  [varargout{:}] = __bar__ (true, "bar", varargin{:});
+  [varargout{:}] = __bar__ ("bar", true, varargin{:});
 endfunction
 
-
 %!demo
 %! clf;
 %! y = rand (11, 1);
@@ -144,3 +136,17 @@
 %! clf;
 %! h = bar (rand (5, 3), "stacked");
 %! title ("bar() graph with stacked style");
+
+%!demo
+%! clf;
+%! y = -rand (3) .* eye (3) + rand (3) .* (! eye (3));
+%! h = bar (y, "stacked");
+%! title ("stacked bar() graph including intermingled negative values");
+
+%% Test input validation
+%!error bar ()
+%!error <Y must be numeric> bar ("foo")
+%!error <X must be a vector> bar ([1 2; 3 4], [1 2 3 4])
+%!error <X vector values must be unique> bar ([1 2 3 3], [1 2 3 4])
+%!error <length of X and Y must be equal> bar ([1 2 3], [1 2 3 4])
+%!error <length of X and Y must be equal> bar ([1 2 3 4], [1 2 3])
--- a/scripts/plot/draw/barh.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/barh.m	Sun May 16 09:44:35 2021 +0200
@@ -72,13 +72,13 @@
 ##
 ## The optional return value @var{h} is a graphics handle to the created
 ## bar series hggroup.  For a description of the use of the
-## bar series, @pxref{XREFbar,,bar}.
+## bar series, @pxref{XREFbar,,@code{bar}}.
 ## @seealso{bar, hist, pie, plot, patch}
 ## @end deftypefn
 
 function varargout = barh (varargin)
   varargout = cell (nargout, 1);
-  [varargout{:}] = __bar__ (false, "barh", varargin{:});
+  [varargout{:}] = __bar__ ("barh", false, varargin{:});
 endfunction
 
 
@@ -95,3 +95,17 @@
 %! set (h(2), "facecolor", "g");
 %! set (h(3), "facecolor", "b");
 %! title ("barh() graph w/multiple bars");
+
+%!demo
+%! clf;
+%! x = -rand (3) .* eye (3) + rand (3) .* (! eye (3));
+%! h = barh (x, "stacked");
+%! title ("stacked barh() graph including intermingled negative values");
+
+%% Test input validation
+%!error barh ()
+%!error <Y must be numeric> barh ("foo")
+%!error <X must be a vector> barh ([1 2; 3 4], [1 2 3 4])
+%!error <X vector values must be unique> barh ([1 2 3 3], [1 2 3 4])
+%!error <length of X and Y must be equal> barh ([1 2 3], [1 2 3 4])
+%!error <length of X and Y must be equal> barh ([1 2 3 4], [1 2 3])
--- a/scripts/plot/draw/camlight.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/camlight.m	Sun May 16 09:44:35 2021 +0200
@@ -80,10 +80,11 @@
 ## @end group
 ## @end example
 ##
-## Here the light is first pitched upwards (@pxref{XREFcamup,,camup}) from the
-## camera position (@pxref{XREFcampos,,campos}) by 30 degrees.  It is then
-## yawed by 45 degrees to the right.  Both rotations are centered around the
-## camera target (@pxref{XREFcamtarget,,camtarget}).
+## Here the light is first pitched upwards (@pxref{XREFcamup,,@code{camup}})
+## from the camera position (@pxref{XREFcampos,,@code{campos}}) by 30
+## degrees.  It is then yawed by 45 degrees to the right.  Both rotations
+## are centered around the camera target
+## (@pxref{XREFcamtarget,,@code{camtarget}}).
 ##
 ## Return a handle to further manipulate the light object
 ##
--- a/scripts/plot/draw/colorbar.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/colorbar.m	Sun May 16 09:44:35 2021 +0200
@@ -220,7 +220,7 @@
     set (hax, "units", orig_props.units,
               "position", orig_props.position,
               "outerposition", orig_props.outerposition,
-              "activepositionproperty", orig_props.activepositionproperty);
+              "positionconstraint", orig_props.positionconstraint);
     set (hax, "units", units);
   endif
 
@@ -252,7 +252,7 @@
     ## FIXME: Matlab does not require the "position" property to be active.
     ##        Is there a way to determine the plotbox position for the
     ##        gnuplot graphics toolkit when the outerposition is active?
-    set (hax, "activepositionproperty", "position");
+    set (hax, "positionconstraint", "innerposition");
     props = get (hax);
     props.__axes_handle__ = hax;
     position = props.position;
@@ -277,7 +277,7 @@
     ## Create colorbar axes if necessary
     if (new_colorbar)
       hcb = axes ("parent", hpar, "tag", "colorbar",
-                  "activepositionproperty", "position",
+                  "positionconstraint", "innerposition",
                   "units", get (hax, "units"), "position", cbpos,
                   "colormap", cmap,
                   "box", "on", "xdir", "normal", "ydir", "normal");
@@ -440,7 +440,7 @@
     set (hax, "units", orig_props.units,
               "position", orig_props.position,
               "outerposition", orig_props.outerposition,
-              "activepositionproperty", orig_props.activepositionproperty);
+              "positionconstraint", orig_props.positionconstraint);
     set (hax, "units", units);
 
     ## Nullify colorbar link (can't delete properties yet)
@@ -471,7 +471,7 @@
 endfunction
 
 ## Update colorbar when changes to axes or figure colormap have occurred.
-function cb_colormap (h, d, hax, hcb, hi, init_sz)
+function cb_colormap (h, ~, hax, hcb, hi, init_sz)
   persistent sz = init_sz;
 
   if (ishghandle (h))
@@ -536,7 +536,7 @@
       scale = [scale, 1];
     endif
     if (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot")
-        && strcmp (props.activepositionproperty, "outerposition"))
+        && strcmp (props.positionconstraint, "outerposition"))
       props.outerposition = props.outerposition .* [1, 1, scale];
       off = 0.5 * (props.outerposition (3:4) - __actual_axis_position__ (props)(3:4));
     else
@@ -859,7 +859,7 @@
 %!demo
 %! clf;
 %! colormap ("default");
-%! axes;
+%! axes ();
 %! colorbar ();
 %! hold on;
 %! contour (peaks ());
@@ -886,7 +886,7 @@
 %! shading interp;
 %! axis ("tight", "square");
 %! colorbar ();
-#%! axes ("color","none","box","on","activepositionproperty","position");
+#%! axes ("color", "none", "box", "on", "positionconstraint", "innerposition");
 
 %!demo
 %! clf;
--- a/scripts/plot/draw/comet.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/comet.m	Sun May 16 09:44:35 2021 +0200
@@ -46,9 +46,11 @@
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("comet", varargin{:});
 
-  if (nargin == 0)
+  if (nargin == 0 || nargin > 3)
     print_usage ();
-  elseif (nargin == 1)
+  endif
+
+  if (nargin == 1)
     y = varargin{1};
     x = 1:numel (y);
     p = 5 / numel (y);
--- a/scripts/plot/draw/compass.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/compass.m	Sun May 16 09:44:35 2021 +0200
@@ -137,8 +137,8 @@
 %! title ("compass() example");
 
 ## Test input validation
-%!error compass ()
-%!error compass (1,2,3,4)
+%!error <Invalid call> compass ()
+%!error <Invalid call> compass (1,2,3,4)
 %!error compass (1, "-r", 2)
 %!error <invalid linestyle STYLE> compass (1, "abc")
 %!error <invalid linestyle STYLE> compass (1, {1})
--- a/scripts/plot/draw/contourc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/contourc.m	Sun May 16 09:44:35 2021 +0200
@@ -24,10 +24,11 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {[@var{c}, @var{lev}] =} contourc (@var{z})
-## @deftypefnx {} {[@var{c}, @var{lev}] =} contourc (@var{z}, @var{vn})
-## @deftypefnx {} {[@var{c}, @var{lev}] =} contourc (@var{x}, @var{y}, @var{z})
-## @deftypefnx {} {[@var{c}, @var{lev}] =} contourc (@var{x}, @var{y}, @var{z}, @var{vn})
+## @deftypefn  {} {@var{c} =} contourc (@var{z})
+## @deftypefnx {} {@var{c} =} contourc (@var{z}, @var{vn})
+## @deftypefnx {} {@var{c} =} contourc (@var{x}, @var{y}, @var{z})
+## @deftypefnx {} {@var{c} =} contourc (@var{x}, @var{y}, @var{z}, @var{vn})
+## @deftypefnx {} {[@var{c}, @var{lev}] =} contourc (@dots{})
 ## Compute contour lines (isolines of constant Z value).
 ##
 ## The matrix @var{z} contains height values above the rectangular grid
@@ -42,8 +43,8 @@
 ## at a given value use @code{@var{vn} = [val, val]}.  If @var{vn} is omitted
 ## it defaults to 10.
 ##
-## The return value @var{c} is a 2x@var{n} matrix containing the
-## contour lines in the following format
+## The return value @var{c} is a 2x@var{n} matrix containing the contour lines
+## in the following format
 ##
 ## @example
 ## @group
@@ -53,11 +54,11 @@
 ## @end example
 ##
 ## @noindent
-## in which contour line @var{n} has a level (height) of @var{levn} and
-## length of @var{lenn}.
+## in which contour line @var{n} has a level (height) of @var{levn} and length
+## of @var{lenn}.
 ##
-## The optional return value @var{lev} is a vector with the Z values of
-## the contour levels.
+## The optional return value @var{lev} is a vector with the Z values of the
+## contour levels.
 ##
 ## Example:
 ##
@@ -104,8 +105,9 @@
   endif
 
   if (! (isnumeric (z) && isnumeric (x) && isnumeric (y))
-      || ! (ismatrix (z) && ismatrix (x) && ismatrix (y)))
-    error ("contourc: X, Y, and Z must be numeric matrices");
+      || ! (ismatrix (z) && ismatrix (x) && ismatrix (y))
+      || ! (isreal (z) && isreal (x) && isreal (y)))
+    error ("contourc: X, Y, and Z must be real numeric matrices");
   endif
 
   if (rows (z) < 2 || columns (z) < 2)
@@ -113,17 +115,17 @@
   endif
 
   if (isscalar (vn))
-    vv = linspace (min (z(:)), max (z(:)), vn+2)(2:end-1);
+    lev = linspace (min (z(:)), max (z(:)), vn+2)(2:end-1);
   else
-    vv = unique (sort (vn));
+    lev = unique (sort (vn));
   endif
 
   if (isvector (x) && isvector (y))
-    cdat = __contourc__ (x(:)', y(:)', z, vv);
+    c = __contourc__ (x(:)', y(:)', z, lev);
   elseif (! any (bsxfun (@minus, x, x(1,:))(:))
           && ! any (bsxfun (@minus, y, y(:,1))(:)))
     ## x,y are uniform grid (such as from meshgrid)
-    cdat = __contourc__ (x(1,:), y(:,1)', z, vv);
+    c = __contourc__ (x(1,:), y(:,1)', z, lev);
   else
     ## Data is sampled over non-uniform mesh.
     ## Algorithm calculates contours for uniform grid
@@ -134,39 +136,33 @@
     ii = 1:nc;
     jj = 1:nr;
 
-    cdat = __contourc__ (ii, jj, z, vv);
+    c = __contourc__ (ii, jj, z, lev);
 
     ## Map the contour lines from index space (i,j)
     ## back to the original grid (x,y)
     i = 1;
 
-    while (i < columns (cdat))
-      clen = cdat(2, i);
+    while (i < columns (c))
+      clen = c(2, i);
       idx = i + (1:clen);
 
-      ci = cdat(1, idx);
-      cj = cdat(2, idx);
+      ci = c(1, idx);
+      cj = c(2, idx);
 
-      ## Due to rounding errors, some elements of ci and cj
-      ## can fall out of the range of ii and jj and
-      ## interp2 would return NA for those values.
+      ## Due to rounding errors, some elements of ci and cj can fall out of the
+      ## range of ii and jj and interp2 would return NA for those values.
       ## The permitted range is enforced here:
 
       ci = max (ci, 1); ci = min (ci, nc);
       cj = max (cj, 1); cj = min (cj, nr);
 
-      cdat(1, idx) = interp2 (ii, jj, x, ci, cj);
-      cdat(2, idx) = interp2 (ii, jj, y, ci, cj);
+      c(1, idx) = interp2 (ii, jj, x, ci, cj);
+      c(2, idx) = interp2 (ii, jj, y, ci, cj);
 
-      i += clen + 1;
+      i += (clen + 1);
     endwhile
   endif
 
-  if (nargout > 0)
-    c = cdat;
-    lev = vv;
-  endif
-
 endfunction
 
 
@@ -181,13 +177,16 @@
 %! assert (lev_obs, lev_exp, eps);
 
 ## Test input validation
-%!error contourc ()
-%!error contourc (1,2,3,4,5)
-%!error <X, Y, and Z must be numeric> contourc ({1})
-%!error <X, Y, and Z must be numeric> contourc ({1}, 2, 3)
-%!error <X, Y, and Z must be numeric> contourc (1, {2}, 3)
+%!error <Invalid call> contourc ()
+%!error <Invalid call> contourc (1,2,3,4,5)
+%!error <X, Y, and Z must be .* numeric> contourc ({3})
+%!error <X, Y, and Z must be .* numeric> contourc ({1}, 2, 3)
+%!error <X, Y, and Z must be .* numeric> contourc (1, {2}, 3)
 %!error <X, Y, and Z must be .* matrices> contourc (ones (3,3,3))
 %!error <X, Y, and Z must be .* matrices> contourc (ones (3,3,3), 2, 3)
 %!error <X, Y, and Z must be .* matrices> contourc (1, ones (3,3,3), 3)
+%!error <X, Y, and Z must be real> contourc (3i)
+%!error <X, Y, and Z must be real> contourc (1i, 2, 3)
+%!error <X, Y, and Z must be real> contourc (1, 2i, 3)
 %!error <Z data must have at least 2 rows> contourc ([1, 2])
 %!error <Z data must have at least .* 2 columns> contourc ([1; 2])
--- a/scripts/plot/draw/cylinder.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/cylinder.m	Sun May 16 09:44:35 2021 +0200
@@ -61,17 +61,17 @@
 
   [hax, args, nargs] = __plt_get_axis_arg__ ("cylinder", varargin{:});
 
-  if (nargs == 0)
+  if (nargs > 2)
+    print_usage ();
+  elseif (nargs == 0)
     r = [1, 1];
     n = 20;
   elseif (nargs == 1)
     r = args{1};
     n = 20;
-  elseif (nargs == 2)
+  else
     r = args{1};
     n = args{2};
-  else
-    print_usage ();
   endif
 
   if (length (r) < 2)
--- a/scripts/plot/draw/errorbar.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/errorbar.m	Sun May 16 09:44:35 2021 +0200
@@ -247,7 +247,7 @@
 ## Invisible figure used for tests
 %!shared hf, hax
 %! hf = figure ("visible", "off");
-%! hax = axes;
+%! hax = axes ();
 
 %!error errorbar ()
 %!error errorbar (1)
--- a/scripts/plot/draw/feather.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/feather.m	Sun May 16 09:44:35 2021 +0200
@@ -135,8 +135,8 @@
 %! title ("feather plot");
 
 ## Test input validation
-%!error feather ()
-%!error feather (1,2,3,4)
+%!error <Invalid call> feather ()
+%!error <Invalid call> feather (1,2,3,4)
 %!error feather (1, "-r", 2)
 %!error <invalid linestyle STYLE> feather (1, "abc")
 %!error <invalid linestyle STYLE> feather (1, {1})
--- a/scripts/plot/draw/fill.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/fill.m	Sun May 16 09:44:35 2021 +0200
@@ -70,7 +70,7 @@
 ## @end group
 ## @end example
 ##
-## @seealso{patch, caxis, colormap}
+## @seealso{patch, fill3, caxis, colormap}
 ## @end deftypefn
 
 function h = fill (varargin)
@@ -107,13 +107,13 @@
         y = varargin{iargs(i) + 1};
         cdata = varargin{iargs(i) + 2};
 
-        if (! size_equal (x,y))
+        if (! size_equal (x, y))
           if (iscolumn (y) && rows (y) == rows (x))
             y = repmat (y, [1, columns(x)]);
           elseif (iscolumn (x) && rows (x) == rows (y))
             x = repmat (x, [1, columns(y)]);
           else
-            error ("fill: X annd Y must have same number of rows");
+            error ("fill: X and Y must have same number of rows");
           endif
         endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/fill3.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,258 @@
+########################################################################
+##
+## Copyright (C) 2021 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  {} {} fill3 (@var{x}, @var{y}, @var{z}, @var{c})
+## @deftypefnx {} {} fill3 (@var{x1}, @var{y1}, @var{z1}, @var{c1}, @var{x2}, @var{y2}, @var{z2}, @var{c2})
+## @deftypefnx {} {} fill3 (@dots{}, @var{prop}, @var{val})
+## @deftypefnx {} {} fill3 (@var{hax}, @dots{})
+## @deftypefnx {} {@var{h} =} fill3 (@dots{})
+## Create one or more filled 3-D polygons.
+##
+## The inputs @var{x}, @var{y}, and @var{z} are the coordinates of the polygon
+## vertices.  If the inputs are matrices then the rows represent different
+## vertices and each column produces a different polygon.  @code{fill3} will
+## close any open polygons before plotting.
+##
+## The input @var{c} determines the color of the polygon.  The simplest form
+## is a single color specification such as a @code{plot} format or an
+## RGB-triple.  In this case the polygon(s) will have one unique color.  If
+## @var{c} is a vector or matrix then the color data is first scaled using
+## @code{caxis} and then indexed into the current colormap.  A row vector will
+## color each polygon (a column from matrices @var{x}, @var{y}, and @var{z})
+## with a single computed color.  A matrix @var{c} of the same size as @var{x},
+## @var{y}, and @var{z} will compute the color of each vertex and then
+## interpolate the face color between the vertices.
+##
+## Multiple property/value pairs for the underlying patch object may be
+## specified, but they must appear in pairs.  The full list of properties is
+## documented at @ref{Patch Properties}.
+##
+## If the first argument @var{hax} is an axes handle, then plot into this axes,
+## rather than the current axes returned by @code{gca}.
+##
+## The optional return value @var{h} is a vector of graphics handles to
+## the created patch objects.
+##
+## Example: oblique red rectangle
+##
+## @example
+## @group
+## vertices = [0 0 0
+##             1 1 0
+##             1 1 1
+##             0 0 1];
+## fill3 (vertices(:,1), vertices(:,2), vertices(:,3), "r");
+## axis ([-0.5 1.5, -0.5 1.5, -0.5 1.5]);
+## axis ("equal");
+## grid ("on");
+## view (-80, 25);
+## @end group
+## @end example
+##
+## @seealso{patch, fill, caxis, colormap}
+## @end deftypefn
+
+function h = fill3 (varargin)
+
+  [hax, varargin] = __plt_get_axis_arg__ ("fill3", varargin{:});
+
+  hlist = [];
+  iargs = __find_patches__ (varargin{:});
+
+  opts = {};
+  if (numel (varargin) > iargs(end) + 3)
+    opts = varargin(iargs(end)+4 : end);
+  endif
+
+  if (! all (cellfun (@(x) iscolorspec (x), varargin(iargs + 3))))
+    print_usage ();
+  endif
+
+  oldfig = [];
+  if (! isempty (hax))
+    oldfig = get (0, "currentfigure");
+  endif
+  unwind_protect
+    hax = newplot (hax);
+    old_nxtplt = get (hax, "nextplot");
+    if (! ishold ())
+      set (hax, "box", "on");
+    endif
+    unwind_protect
+      set (hax, "nextplot", "add");
+
+      for i = 1 : length (iargs)
+        x = varargin{iargs(i)};
+        y = varargin{iargs(i) + 1};
+        z = varargin{iargs(i) + 2};
+        cdata = varargin{iargs(i) + 3};
+
+        if (! size_equal (x, y, z))
+          if (rows (x) != rows (y) || rows (x) != rows (z))
+            error ("fill3: X, Y, and Z must have same number of rows");
+          endif
+
+          num_cols = max ([columns(x), columns(y), columns(z)]);
+          if (iscolumn (x))
+            x = repmat (x, [1, num_cols]);
+          end
+          if (iscolumn (y))
+            y = repmat (y, [1, num_cols]);
+          end
+          if (iscolumn (z))
+            z = repmat (z, [1, num_cols]);
+          end
+        endif
+
+        if (isrow (x))
+          x = x(:);
+        endif
+        if (isrow (y))
+          y = y(:);
+        endif
+        if (isrow (z))
+          z = z(:);
+        endif
+
+        if (ischar (cdata) || isequal (size (cdata), [1, 3]))
+          one_color = true;
+        else
+          one_color = false;
+        endif
+
+        ## For Matlab compatibility, replicate cdata to match size of data
+        if (! one_color && iscolumn (cdata))
+          sz = size (x);
+          if (all (sz > 1))
+            cdata = repmat (cdata, [1, sz(2)]);
+          endif
+        endif
+
+        ## For Matlab compatibility, return 1 patch object for each column
+        for j = 1 : columns (x)
+          if (one_color)
+            [htmp, err] = __patch__ (hax, x(:,j), y(:,j), z(:,j), ...
+                                     cdata, opts{:});
+          else
+            [htmp, err] = __patch__ (hax, x(:,j), y(:,j), z(:,j), ...
+                                     cdata(:,j), opts{:});
+          endif
+          if (err)
+            print_usage ();
+          endif
+          hlist(end+1, 1) = htmp;
+        endfor
+      endfor
+
+      view (hax, 3);
+
+    unwind_protect_cleanup
+      if (strcmp (old_nxtplt, "replace"))
+        set (hax, "nextplot", old_nxtplt);
+      endif
+    end_unwind_protect
+
+  unwind_protect_cleanup
+    if (! isempty (oldfig))
+      set (0, "currentfigure", oldfig);
+    endif
+  end_unwind_protect
+
+  if (nargout > 0)
+    h = hlist;
+  endif
+
+endfunction
+
+function iargs = __find_patches__ (varargin)
+  iargs = 1:4:nargin;
+  optidx = find (! cellfun (@isnumeric, varargin(iargs)), 1);
+  iargs(optidx:end) = [];
+endfunction
+
+function retval = iscolorspec (arg)
+
+  retval = false;
+  if (ischar (arg))
+    persistent colors = {"y", "yellow", "r", "red", "m", "magenta", ...
+                         "c", "cyan", "g", "green", "b", "blue", ...
+                         "w", "white", "k", "black"};
+    if (any (strcmpi (arg, colors)))
+      retval = true;
+    endif
+  elseif (isnumeric (arg))
+    ## Assume any numeric argument is correctly formatted cdata.
+    ## Let patch worry about the multiple different input formats.
+    retval = true;
+  endif
+
+endfunction
+
+
+%!demo
+%! clf;
+%! t1 = (1/16:1/8:1) * 2*pi;
+%! t2 = ((1/16:1/8:1) + 1/32) * 2*pi;
+%! x1 = sin (t1) - 0.8;
+%! y1 = cos (t1);
+%! z1 = sin (t1);
+%! x2 = sin (t2) + 0.8;
+%! y2 = cos (t2);
+%! z2 = sin (t2);
+%! h = fill3 (x1,y1,z1,"r", x2,y2,z2,"g");
+%! title ({"fill3() function"; "cdata specified with string"});
+%! grid ("on");
+
+%!demo
+%! clf;
+%! t1 = (1/16:1/8:1) * 2*pi;
+%! t2 = ((1/16:1/8:1) + 1/32) * 2*pi;
+%! x1 = sin (t1) - 0.8;
+%! y1 = cos (t1);
+%! z1 = sin (t1);
+%! x2 = sin (t2) + 0.8;
+%! y2 = cos (t2);
+%! z2 = sin (t2);
+%! h = fill3 (x1,y1,z1,1, x2,y2,z2,2);
+%! title ({"fill3() function"; 'cdata = row vector produces FaceColor = "flat"'});
+%! grid ("on");
+
+%!demo
+%! clf;
+%! x = [0 0
+%!      1 0.5
+%!      1 0.5
+%!      0 0];
+%! y = [0 0
+%!      0 0
+%!      1 0.5
+%!      1 0.5];
+%! z = y;
+%! z(:,2) += 1e-4;
+%! c = [1 2 3 4]';
+%! fill3 (x, y, z, [c c]);
+%! title ({"fill3() function"; 'cdata = column vector produces FaceColor = "interp"'});
+%! grid ("on");
--- a/scripts/plot/draw/fplot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/fplot.m	Sun May 16 09:44:35 2021 +0200
@@ -128,6 +128,7 @@
   n = 5;
   tol = 2e-3;
   fmt = {};
+  prop_vals = {};
   while (i <= numel (varargin))
     arg = varargin{i};
     if (ischar (arg))
@@ -138,7 +139,7 @@
         if (i == numel (varargin))
           error ("fplot: bad input in position %d", i);
         endif
-        fmt(end+(1:2)) = varargin([i, i+1]);
+        prop_vals(end+(1:2)) = varargin([i, i+1]);
         i++;  # Skip PROPERTY.
       endif
     elseif (isnumeric (arg) && isscalar (arg) && arg > 0)
@@ -225,18 +226,24 @@
     if (isempty (hax))
       hax = gca ();
     endif
-    plot (hax, x, y, fmt{:});
+    hl = plot (hax, x, y, fmt{:});
+    if (isempty (get (hl(1), "displayname")))
+      ## Set displayname for legend if FMT did not contain a name.
+      if (isvector (y))
+        set (hl, "displayname", nam);
+      else
+        for i = 1:columns (y)
+          nams{i} = sprintf ("%s(:,%i)", nam, i);
+        endfor
+        set (hl, {"displayname"}, nams(:));
+      endif
+    endif
+    ## Properties passed as input arguments override other properties.
+    if (! isempty (prop_vals))
+      set (hl, prop_vals{:});
+    endif
     axis (hax, limits);
-    ## FIXME: If hold is on, then this erases the existing legend rather than
-    ##        adding to it.
-    if (isvector (y))
-      legend (hax, nam);
-    else
-      for i = 1:columns (y)
-        nams{i} = sprintf ("%s(:,%i)", nam, i);
-      endfor
-      legend (hax, nams{:});
-    endif
+    legend (hax, "show");
   endif
 
 endfunction
@@ -281,9 +288,31 @@
 %! assert (rows (x) == rows (y));
 %! assert (y, repmat ([0], size (x)));
 
+%!test <*59274>
+%! ## Manual displayname overrides automatic legend entry
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   fplot (@sin, [0, 3], "displayname", "mysin");
+%!   hl = legend ();
+%!   assert (get (hl, "string"), {"mysin"});
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+%!test <*59274>
+%! ## displayname in format string overrides automatic legend entry
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   fplot (@sin, [0, 3], "+;mysin;");
+%!   hl = legend ();
+%!   assert (get (hl, "string"), {"mysin"});
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
 ## Test input validation
-%!error fplot ()
-%!error fplot (1,2,3,4,5,6)
+%!error <Invalid call> fplot ()
+%!error <Invalid call> fplot (1,2,3,4,5,6)
 %!error <FN must be a function handle> fplot (1, [0 1])
 %!error <LIMITS must be a real vector> fplot (@cos, [i, 2*i])
 %!error <LIMITS must be a real vector with 2 or 4> fplot (@cos, [1])
--- a/scripts/plot/draw/hist.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/hist.m	Sun May 16 09:44:35 2021 +0200
@@ -61,16 +61,9 @@
 ## @end example
 ##
 ## @noindent
-## The histogram's colors also depend upon the current colormap.
-##
-## @example
-## @group
-## hist (rand (10, 3));
-## colormap (summer ());
-## @end group
-## @end example
-##
 ## The full list of patch properties is documented at @ref{Patch Properties}.
+## property.  If not specified, the default colors for the histogram are taken
+## from the @qcode{"Colormap"} property of the axes or figure.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
@@ -118,14 +111,15 @@
   ## Process possible second argument
   if (nargin == 1 || ischar (varargin{iarg}))
     n = 10;
-    ## Use range type to preserve accuracy
+    ## Use integer range values and perform division last to preserve
+    ## accuracy.
     if (min_val != max_val)
-      x = (0.5:n) * (1/n);
-      x = (max_val - min_val) * x + min_val;
+      x = 1:2:2*n;
+      x = ((max_val - min_val) * x + 2*n*min_val) / (2*n);
     else
       x = (-floor ((n-1)/2):ceil ((n-1)/2)) + min_val;
     endif
-    x = x.';  # Convert to matrix;
+    x = x.';  # Convert to matrix
   else
     ## Parse bin specification argument
     x = varargin{iarg++};
@@ -143,14 +137,15 @@
       if (n <= 0)
         error ("hist: number of bins NBINS must be positive");
       endif
-      ## Use range type to preserve accuracy
+      ## Use integer range values and perform division last to preserve
+      ## accuracy.
       if (min_val != max_val)
-        x = (0.5:n) * (1/n);
-        x = (max_val - min_val) * x + min_val;
+        x = 1:2:2*n;
+        x = ((max_val - min_val) * x + 2*n*min_val) / (2*n);
       else
         x = (-floor ((n-1)/2):ceil ((n-1)/2)) + min_val;
       endif
-      x = x.';  # Convert to matrix;
+      x = x.';  # Convert to matrix
     elseif (isvector (x))
       equal_bin_spacing = strcmp (typeinfo (x), "range");
       if (! equal_bin_spacing)
@@ -198,7 +193,7 @@
     ## Lookup is more efficient if y is sorted, but sorting costs.
     if (! equal_bin_spacing && n > sqrt (rows (y) * 1e4))
       y = sort (y);
-    end
+    endif
 
     nanidx = isnan (y);
     y(nanidx) = 0;
@@ -208,21 +203,21 @@
         d = 1;
       else
         d = (x(end) - x(1)) / (length (x) - 1);
-      end
+      endif
       cutlen = length (cutoff);
       for j = 1:y_nc
         freq(:,j) = accumarray (1 + max (0, min (cutlen, ceil ((double (y(:,j))
                                                          - cutoff(1)) / d))),
                                 double (! nanidx(:,j)),
                                 [n, 1]);
-      end
+      endfor
     else
       for j = 1:y_nc
         i = lookup (cutoff, y(:,j));
         i = 1 + i - (cutoff(max (i, 1)) == y(:,j));
         freq(:,j) = accumarray (i, double (! nanidx(:,j)), [n, 1]);
-      end
-    end
+      endfor
+    endif
   endif
 
   if (norm)
@@ -386,13 +381,13 @@
 %! assert (isa (xx, "single"));
 
 ## Test input validation
-%!error hist ()
+%!error <Invalid call> hist ()
 %!error <Y must be real-valued> hist (2+i)
 %!error <bin specification must be a numeric> hist (1, {0,1,2})
 %!error <number of bins NBINS must be positive> hist (1, 0)
 %!test
 %! hf = figure ("visible", "off");
-%! hax = gca;
+%! hax = gca ();
 %! unwind_protect
 %!   fail ("hist (hax, 1, [2 1 0])", "warning", "bin values X not sorted");
 %! unwind_protect_cleanup
--- a/scripts/plot/draw/isocaps.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/isocaps.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
 ## vectors with lengths corresponding to the dimensions of @var{v}, then the
 ## volume data is taken at the specified points.  If @var{x}, @var{y}, or
 ## @var{z} are empty, the grid corresponds to the indices (@code{1:n}) in
-## the respective direction (@pxref{XREFmeshgrid,,meshgrid}).
+## the respective direction (@pxref{XREFmeshgrid,,@code{meshgrid}}).
 ##
 ## The optional parameter @var{which_caps} can have one of the following
 ## string values which defines how the data will be enclosed:
@@ -376,7 +376,7 @@
 %! [x, y, z] = meshgrid (lin, lin, lin);
 %! v = abs ((x-0.45).^2 + (y-0.55).^2 + (z-0.8).^2);
 %! hf = clf;
-%! ha = axes;
+%! ha = axes ();
 %! view (3);  box off;
 %! fvc_iso = isosurface (x, y, z, v, isoval);
 %! cmap = get (hf, "Colormap");
@@ -544,8 +544,8 @@
 %! assert (rows (vertices), rows (fvcdata));
 
 ## test for each error
-%!error isocaps ()
-%!error isocaps (1,2,3,4,5,6,7,8,9)
+%!error <Invalid call> isocaps ()
+%!error <Invalid call> isocaps (1,2,3,4,5,6,7,8,9)
 %!error <parameter 'foo' not supported> isocaps (val, iso, "foo")
 %!error <incorrect number of input arguments> isocaps (x, val, iso)
 %!error <incorrect number of input arguments> isocaps (xx, yy, zz, val, iso, 5)
--- a/scripts/plot/draw/isocolors.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/isocolors.m	Sun May 16 09:44:35 2021 +0200
@@ -185,11 +185,11 @@
 %! assert (rows (cdat) == rows (v));
 
 ## Test input validation
-%!error isocolors ()
-%!error isocolors (1)
-%!error isocolors (1,2,3)
-%!error isocolors (1,2,3,4,5,6)
-%!error isocolors (1,2,3,4,5,6,7,8)
+%!error <Invalid call> isocolors ()
+%!error <Invalid call> isocolors (1)
+%!error <Invalid call> isocolors (1,2,3)
+%!error <Invalid call> isocolors (1,2,3,4,5,6)
+%!error <Invalid call> isocolors (1,2,3,4,5,6,7,8)
 %!error <last argument must be a vertex list> isocolors (1, {1})
 %!error <last argument must be a vertex list> isocolors (1, [1 2 3 4])
 %!error <last argument must be a .*patch handle> isocolors (1, 0)
--- a/scripts/plot/draw/isonormals.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/isonormals.m	Sun May 16 09:44:35 2021 +0200
@@ -65,12 +65,14 @@
 
   narg = nargin;
   negate = false;
-  if (ischar (varargin{narg}))
-    if (strcmpi (varargin{narg}, "negate"))
-      negate = true;
-      narg -= 1;
-    else
-      error ("isonormals: Unknown option '%s'", varargin{narg});
+  if (nargin > 2)
+    if (ischar (varargin{end}))
+      if (strcmpi (varargin{end}, "negate"))
+        negate = true;
+        narg -= 1;
+      else
+        error ("isonormals: Unknown option '%s'", varargin{end});
+      endif
     endif
   endif
 
@@ -191,11 +193,11 @@
 %! assert (all (dirn(isfinite (dirn)) <= 0));
 
 ## Test input validation
-%!error isonormals ()
-%!error isonormals (1)
-%!error isonormals (1,2,3)
-%!error isonormals (1,2,3,4)
-%!error isonormals (1,2,3,4,5,6)
+%!error <Invalid call> isonormals ()
+%!error <Invalid call> isonormals (1)
+%!error <Invalid call> isonormals (1,2,3)
+%!error <Invalid call> isonormals (1,2,3,4)
+%!error <Invalid call> isonormals (1,2,3,4,5,6)
 %!error <Unknown option 'foo'> isonormals (x, y, z, val, vert, "foo")
 %!error <must be a list of vertices> isonormals (1, {1})
 %!error <must be a list of vertices> isonormals (1, [1 2 3 4])
--- a/scripts/plot/draw/isosurface.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/isosurface.m	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
 ## vectors with lengths corresponding to the dimensions of @var{v}, then the
 ## volume data is taken at the specified points.  If @var{x}, @var{y}, or
 ## @var{z} are empty, the grid corresponds to the indices (@code{1:n}) in
-## the respective direction (@pxref{XREFmeshgrid,,meshgrid}).
+## the respective direction (@pxref{XREFmeshgrid,,@code{meshgrid}}).
 ##
 ## The optional input argument @var{col}, which is a three-dimensional array
 ## of the same size as @var{v}, specifies coloring of the isosurface.  The
@@ -168,7 +168,7 @@
     warning ("isosurface: triangulation is empty");
   endif
 
-  # remove faces for which at least one of the vertices is NaN
+  ## remove faces for which at least one of the vertices is NaN
   vert_nan = 1:size (fvc.vertices, 1);
   vert_nan(any (isnan (fvc.vertices), 2)) = NaN;
   fvc.faces = vert_nan(fvc.faces);
@@ -307,7 +307,7 @@
       colors = varargin{6};
 
     otherwise
-      error ("isosurface: incorrect number of input arguments")
+      error ("isosurface: incorrect number of input arguments");
 
   endswitch
 
@@ -355,19 +355,19 @@
   endif
 
   if (! isscalar (isoval))
-    error ("isosurface: ISOVAL must be a scalar")
+    error ("isosurface: ISOVAL must be a scalar");
   endif
 
   ## check colors
   if (! isempty (colors))
     if (! size_equal (v, colors))
-      error ("isosurface: COL must match the size of V")
+      error ("isosurface: COL must match the size of V");
     endif
     if (nout == 2)
-      warning ("isosurface: colors will be calculated, but no output argument to receive it.");
+      warning ("isosurface: colors will be calculated, but no output argument to receive it");
     endif
   elseif (nout >= 3)
-    error ("isosurface: COL must be passed to return C")
+    error ("isosurface: COL must be passed to return C");
   endif
 
 endfunction
@@ -559,8 +559,8 @@
 %! assert (size (fvc.facevertexcdata), [7 1]);
 
 ## test for each error and warning
-%!error isosurface ()
-%!error isosurface (1,2,3,4,5,6,7,8,9)
+%!error <Invalid call> isosurface ()
+%!error <Invalid call> isosurface (1,2,3,4,5,6,7,8,9)
 %!error <parameter 'foobar' not supported>
 %! fvc = isosurface (val, iso, "foobar");
 %!error <incorrect number of input arguments>
@@ -592,9 +592,9 @@
 %! [xx, yy, zz] = meshgrid (x, y, z);
 %! fvc = isosurface (xx, yy, zz, val, iso);
 %!error <ISOVAL must be a scalar> fvc = isosurface (val, [iso iso], yy)
-%!error <COL must match the size of V> fvc = isosurface (val, [iso iso]);
+%!error <COL must match the size of V> fvc = isosurface (val, [iso iso])
 %!error <COL must be passed to return C> [f, v, c] = isosurface (val, iso)
-%!warning <colors will be calculated, but no output argument to receive it.>
+%!warning <colors will be calculated, but no output argument to receive it>
 %! [f, v] = isosurface (val, iso, yy);
 
 ## test for __calc_isovalue_from_data__
--- a/scripts/plot/draw/light.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/light.m	Sun May 16 09:44:35 2021 +0200
@@ -163,9 +163,9 @@
 %! h_axes1 = axes ();
 %! surf (X, Y, Z, "LineStyle", "none", "FaceLighting", "none");
 %! hold on;
-%! surf (X + round(1.2 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
+%! surf (X + round (1.2 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
 %!       "FaceLighting", "flat");
-%! surf (X + round(2.4 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
+%! surf (X + round (2.4 * size (Z, 2)), Y, Z, "LineStyle", "none", ...
 %!       "FaceLighting", "gouraud");
 %! axis tight
 %! axis equal
@@ -592,7 +592,7 @@
 
 %!test
 %! hf = figure ("visible", "off");
-%! ha = gca;
+%! ha = gca ();
 %! unwind_protect
 %!   h = light (ha, "Position", [1 2 3], "Color", "r");
 %!   assert (get (h, "Position"), [1 2 3]);
--- a/scripts/plot/draw/lightangle.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/lightangle.m	Sun May 16 09:44:35 2021 +0200
@@ -122,7 +122,7 @@
     pos -= get (hax, "CameraTarget");
   endif
 
-  pos = sph2cart (az, el, norm (pos));
+  [pos(1), pos(2), pos(3)] = sph2cart (az, el, norm (pos));
 
   if (strcmp (get (hl, "Style"), "local"))
     pos += get (hax, "CameraTarget");
@@ -165,8 +165,8 @@
 ## Test input validation
 %!error <Invalid call> lightangle ()
 %!error <Invalid call> lightangle (1, 2, 3, 4)
+%!error <Invalid call> [a, b, c] = lightangle (45, 30)
 %!error <Invalid call> [a, b] = lightangle (45, 30)
-%!error <Invalid call> [a, b, c] = lightangle (45, 30)
 %!error <HL must be a handle to a light object> lightangle (0)
 %!error <H must be a handle to an axes or light object> lightangle (0, 90, 45)
 %!error <AZ and EL must be numeric scalars> lightangle ([1 2], 0)
--- a/scripts/plot/draw/line.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/line.m	Sun May 16 09:44:35 2021 +0200
@@ -123,7 +123,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   h = line;
+%!   h = line ();
 %!   assert (findobj (hf, "type", "line"), h);
 %!   assert (get (h, "xdata"), [0 1], eps);
 %!   assert (get (h, "ydata"), [0 1], eps);
--- a/scripts/plot/draw/loglogerr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/loglogerr.m	Sun May 16 09:44:35 2021 +0200
@@ -46,8 +46,8 @@
 ## @noindent
 ## which produces a double logarithm plot of @var{y} versus @var{x}
 ## with errors in the @var{y}-scale defined by @var{ey} and the plot
-## format defined by @var{fmt}.  @xref{XREFerrorbar,,errorbar}, for available
-## formats and additional information.
+## format defined by @var{fmt}.  @xref{XREFerrorbar,,@code{errorbar}}, for
+## available formats and additional information.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
--- a/scripts/plot/draw/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -9,6 +9,7 @@
   %reldir%/private/__contour__.m \
   %reldir%/private/__errplot__.m \
   %reldir%/private/__ezplot__.m \
+  %reldir%/private/__gnuplot_scatter__.m \
   %reldir%/private/__interp_cube__.m \
   %reldir%/private/__line__.m \
   %reldir%/private/__marching_cube__.m \
@@ -21,6 +22,7 @@
   %reldir%/private/__unite_shared_vertices__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/area.m \
   %reldir%/bar.m \
   %reldir%/barh.m \
@@ -47,6 +49,7 @@
   %reldir%/ezsurfc.m \
   %reldir%/feather.m \
   %reldir%/fill.m \
+  %reldir%/fill3.m \
   %reldir%/fplot.m \
   %reldir%/hist.m \
   %reldir%/isocaps.m \
@@ -98,6 +101,7 @@
   %reldir%/stream2.m \
   %reldir%/stream3.m \
   %reldir%/streamline.m \
+  %reldir%/streamribbon.m \
   %reldir%/streamtube.m \
   %reldir%/surf.m \
   %reldir%/surface.m \
--- a/scripts/plot/draw/ostreamtube.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/ostreamtube.m	Sun May 16 09:44:35 2021 +0200
@@ -71,7 +71,7 @@
 ## @end group
 ## @end example
 ##
-## @seealso{stream3, streamline, streamtube}
+## @seealso{stream3, streamline, streamribbon, streamtube}
 ## @end deftypefn
 
 ## References:
@@ -97,8 +97,6 @@
   options = [];
   xyz = [];
   switch (nargin)
-    case 0
-      print_usage ();
     case 6
       [u, v, w, spx, spy, spz] = varargin{:};
       [m, n, p] = size (u);
@@ -118,7 +116,7 @@
     case 10
       [x, y, z, u, v, w, spx, spy, spz, options] = varargin{:};
     otherwise
-      error ("ostreamtube: invalid number of inputs");
+      print_usage ();
   endswitch
 
   scale = 1;
@@ -131,7 +129,7 @@
         scale = options(1);
         num_circum = options(2);
       otherwise
-        error ("ostreamtube: invalid number of OPTIONS elements");
+        error ("ostreamtube: OPTIONS must be a 1- or 2-element vector");
     endswitch
 
     if (! isreal (scale) || scale <= 0)
@@ -161,7 +159,7 @@
   for i = 1 : length (xyz)
     sl = xyz{i};
     if (! isempty (sl))
-      slx = sl(:, 1); sly = sl(:, 2); slz = sl(:, 3);
+      slx = sl(:,1); sly = sl(:,2); slz = sl(:,3);
       mxx(j) = max (slx); mnx(j) = min (slx);
       mxy(j) = max (sly); mny(j) = min (sly);
       mxz(j) = max (slz); mnz(j) = min (slz);
@@ -179,12 +177,12 @@
     num_vertices = rows (sl);
     if (! isempty (sl) && num_vertices > 2)
 
-      usl = interp3 (x, y, z, u, sl(:, 1), sl(:, 2), sl(:, 3));
-      vsl = interp3 (x, y, z, v, sl(:, 1), sl(:, 2), sl(:, 3));
-      wsl = interp3 (x, y, z, w, sl(:, 1), sl(:, 2), sl(:, 3));
+      usl = interp3 (x, y, z, u, sl(:,1), sl(:,2), sl(:,3));
+      vsl = interp3 (x, y, z, v, sl(:,1), sl(:,2), sl(:,3));
+      wsl = interp3 (x, y, z, w, sl(:,1), sl(:,2), sl(:,3));
       vv = sqrt (usl.*usl + vsl.*vsl + wsl.*wsl);
 
-      div_sl = interp3 (x, y, z, div, sl(:, 1), sl(:, 2), sl(:, 3));
+      div_sl = interp3 (x, y, z, div, sl(:,1), sl(:,2), sl(:,3));
       is_singular_div = find (isnan (div_sl), 1, "first");
 
       if (! isempty (is_singular_div))
@@ -211,61 +209,65 @@
   cp = cos (phi);
   sp = sin (phi);
 
-  X0 = sl(1, :);
-  X1 = sl(2, :);
-
-  ## 1st rotation axis
+  ## 1st streamline segment
+  X0 = sl(1,:);
+  X1 = sl(2,:);
   R = X1 - X0;
   RE = R / norm (R);
 
-  ## Initial radius
-  vold = vv(1);
-  vact = vv(2);
-  ract = rstart * exp (0.5 * div_sl(2) * norm (R) / vact) * sqrt (vold / vact);
-  vold = vact;
+  ## Guide point and its rotation to create a segment
+  KE = get_normal1 (RE);
+  K = rstart * KE;
+  XS0 = rotation (K, RE, cp, sp) + repmat (X0.', 1, num_circum);
+
+  ## End of first segment
+  ract = rstart * exp (0.5 * div_sl(2) * norm (R) / vv(2)) * ...
+                  sqrt (vv(1) / vv(2));
   rold = ract;
-
-  ## Guide point and its rotation to create a segment
-  N = get_normal1 (R);
-  K = ract * N;
+  K = ract * KE;
   XS = rotation (K, RE, cp, sp) + repmat (X1.', 1, num_circum);
 
-  px = zeros (num_circum, max_vertices - 1);
-  py = zeros (num_circum, max_vertices - 1);
-  pz = zeros (num_circum, max_vertices - 1);
-  pc = zeros (num_circum, max_vertices - 1);
+  px = zeros (num_circum, max_vertices);
+  py = zeros (num_circum, max_vertices);
+  pz = zeros (num_circum, max_vertices);
+  pc = zeros (num_circum, max_vertices);
 
-  px(:, 1) = XS(1, :).';
-  py(:, 1) = XS(2, :).';
-  pz(:, 1) = XS(3, :).';
-  pc(:, 1) = vact * ones (num_circum, 1);
+  px(:,1) = XS0(1,:).';
+  py(:,1) = XS0(2,:).';
+  pz(:,1) = XS0(3,:).';
+  pc(:,1) = vv(1) * ones (num_circum, 1);
+
+  px(:,2) = XS(1,:).';
+  py(:,2) = XS(2,:).';
+  pz(:,2) = XS(3,:).';
+  pc(:,2) = vv(2) * ones (num_circum, 1);
 
   for i = 3 : max_vertices
 
-    KK = K;
+    ## Next streamline segment
     X0 = X1;
-    X1 = sl(i, :);
+    X1 = sl(i,:);
     R = X1 - X0;
     RE = R / norm (R);
 
     ## Tube radius
-    vact = vv(i);
-    ract = rold * exp (0.5 * div_sl(i) * norm (R) / vact) * sqrt (vold / vact);
-    vold = vact;
+    ract = rold * exp (0.5 * div_sl(i) * norm (R) / vv(i)) * ...
+                  sqrt (vv(i-1) / vv(i));
     rold = ract;
 
-    ## Project KK onto RE and get the difference in order to calculate the next
-    ## guiding point
-    Kp = KK - RE * dot (KK, RE);
-    K = ract * Kp / norm (Kp);
+    ## Project KE onto RE and get the difference in order to transport
+    ## the normal vector KE along the vertex array
+    Kp = KE - RE * dot (KE, RE);
+    KE = Kp / norm (Kp);
+    K = ract * KE;
 
     ## Rotate around RE and collect surface patches
     XS = rotation (K, RE, cp, sp) + repmat (X1.', 1, num_circum);
 
-    px(:, i - 1) = XS(1, :).';
-    py(:, i - 1) = XS(2, :).';
-    pz(:, i - 1) = XS(3, :).';
-    pc(:, i - 1) = vact * ones (num_circum, 1);
+    px(:,i) = XS(1,:).';
+    py(:,i) = XS(2,:).';
+    pz(:,i) = XS(3,:).';
+    pc(:,i) = vv(i) * ones (num_circum, 1);
 
   endfor
 
@@ -277,9 +279,9 @@
 function N = get_normal1 (X)
 
   if ((X(3) == 0) && (X(1) == -X(2)))
-    N = [- X(2) - X(3), X(1), X(1)];
+    N = [(- X(2) - X(3)), X(1), X(1)];
   else
-    N = [X(3), X(3), - X(1) - X(2)];
+    N = [X(3), X(3), (- X(1) - X(2))];
   endif
 
   N /= norm (N);
@@ -294,20 +296,21 @@
   uy = U(2);
   uz = U(3);
 
-  Y(1, :) = X(1) * (cp + ux * ux * (1 - cp)) + ...
-            X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
-            X(3) * (ux * uz * (1 - cp) + uy * sp);
+  Y(1,:) = X(1) * (cp + ux * ux * (1 - cp)) + ...
+           X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
+           X(3) * (ux * uz * (1 - cp) + uy * sp);
 
-  Y(2, :) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
-            X(2) * (cp + uy * uy * (1 - cp)) + ...
-            X(3) * (uy * uz * (1 - cp) - ux * sp);
+  Y(2,:) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
+           X(2) * (cp + uy * uy * (1 - cp)) + ...
+           X(3) * (uy * uz * (1 - cp) - ux * sp);
 
-  Y(3, :) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
-            X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
-            X(3) * (cp + uz * uz * (1 - cp));
+  Y(3,:) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
+           X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
+           X(3) * (cp + uz * uz * (1 - cp));
 
 endfunction
 
+
 %!demo
 %! clf;
 %! [x, y, z] = meshgrid (-1:0.1:1, -1:0.1:1, -3.5:0.1:0);
@@ -353,14 +356,14 @@
 %! title ("Integration Towards Sink");
 
 ## Test input validation
-%!error ostreamtube ()
-%!error <invalid number of inputs> ostreamtube (1)
-%!error <invalid number of inputs> ostreamtube (1,2)
-%!error <invalid number of inputs> ostreamtube (1,2,3)
-%!error <invalid number of inputs> ostreamtube (1,2,3,4)
-%!error <invalid number of inputs> ostreamtube (1,2,3,4,5)
-%!error <invalid number of OPTIONS> ostreamtube (1,2,3,4,5,6, [1,2,3])
-%!error <SCALE must be a real scalar . 0> ostreamtube (1,2,3,4,5,6, [1i])
-%!error <SCALE must be a real scalar . 0> ostreamtube (1,2,3,4,5,6, [0])
-%!error <N must be greater than 2> ostreamtube (1,2,3,4,5,6, [1, 1i])
-%!error <N must be greater than 2> ostreamtube (1,2,3,4,5,6, [1, 2])
+%!error <Invalid call> ostreamtube ()
+%!error <Invalid call> ostreamtube (1)
+%!error <Invalid call> ostreamtube (1,2)
+%!error <Invalid call> ostreamtube (1,2,3)
+%!error <Invalid call> ostreamtube (1,2,3,4)
+%!error <Invalid call> ostreamtube (1,2,3,4,5)
+%!error <OPTIONS must be a 1- or 2-element> ostreamtube (1,2,3,4,5,6,[1,2,3])
+%!error <SCALE must be a real scalar . 0> ostreamtube (1,2,3,4,5,6,[1i])
+%!error <SCALE must be a real scalar . 0> ostreamtube (1,2,3,4,5,6,[0])
+%!error <N must be greater than 2> ostreamtube (1,2,3,4,5,6,[1,1i])
+%!error <N must be greater than 2> ostreamtube (1,2,3,4,5,6,[1,2])
--- a/scripts/plot/draw/pareto.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/pareto.m	Sun May 16 09:44:35 2021 +0200
@@ -72,7 +72,7 @@
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("pareto", varargin{:});
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1 || nargin > 2)
     print_usage ();
   endif
 
--- a/scripts/plot/draw/patch.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/patch.m	Sun May 16 09:44:35 2021 +0200
@@ -94,16 +94,6 @@
     print_usage ();
   endif
 
-  ## FIXME: ishold called this way is very slow.
-  if (! ishold (hax))
-    ## FIXME: This is a hack to get 'layer' command to work for 2D patches
-    ##        Alternative is much more complicated surgery in graphics.cc.
-    ##        of get_children_limits() for 'z' axis and 'patch' object type.
-    if (isempty (get (htmp, "zdata")))
-      set (hax, "zlim", [-1 1]);
-    endif
-  endif
-
   if (nargout > 0)
     h = htmp;
   endif
@@ -259,21 +249,21 @@
 
 %!demo
 %! clf;
-%! vertices = [0 0 0; 0.5 -0.5 0; 1 0 0; 1 1 0; 0 1 1; 1 0 1; 0 -1 0;]+3;
+%! vertices = [0 0 0; 0.5 -0.5 0; 1 0 0; 1 1 0; 0 1 1; 1 0 1; 0 -1 0] + 3;
 %! faces = [1 2 3 4 5 6 7];
 %! ha = axes ();
-%! hp = patch ('Vertices', vertices, 'Faces', faces, 'FaceColor', 'g');
-%! xlabel('x'), ylabel('y'), zlabel('z')
-%! view(3)
-%! set (ha, "XTick", [], "YTick", [], "ZTick", [])
-%! text (vertices(1,1), vertices(1,2), vertices(1,3), "1")
-%! text (vertices(2,1), vertices(2,2), vertices(2,3), "2")
-%! text (vertices(3,1), vertices(3,2), vertices(3,3), "3")
-%! text (vertices(4,1), vertices(4,2), vertices(4,3), "4")
-%! text (vertices(5,1), vertices(5,2), vertices(5,3), "5")
-%! text (vertices(6,1), vertices(6,2), vertices(6,3), "6")
-%! text (vertices(7,1), vertices(7,2), vertices(7,3), "7")
-%! title ("Non-coplanar patch")
+%! hp = patch ("Vertices", vertices, "Faces", faces, "FaceColor", "g");
+%! xlabel ("x"), ylabel ("y"), zlabel ("z");
+%! view (3);
+%! set (ha, "XTick", [], "YTick", [], "ZTick", []);
+%! text (vertices(1,1), vertices(1,2), vertices(1,3), "1");
+%! text (vertices(2,1), vertices(2,2), vertices(2,3), "2");
+%! text (vertices(3,1), vertices(3,2), vertices(3,3), "3");
+%! text (vertices(4,1), vertices(4,2), vertices(4,3), "4");
+%! text (vertices(5,1), vertices(5,2), vertices(5,3), "5");
+%! text (vertices(6,1), vertices(6,2), vertices(6,3), "6");
+%! text (vertices(7,1), vertices(7,2), vertices(7,3), "7");
+%! title ("Non-coplanar patch");
 
 
 %!test
@@ -297,7 +287,7 @@
 %!   assert (get (h, "linewidth"), get (0, "defaultpatchlinewidth"), eps);
 %!   assert (get (h, "marker"), get (0, "defaultpatchmarker"));
 %!   assert (get (h, "markersize"), get (0, "defaultpatchmarkersize"));
-%!   hl = light;
+%!   hl = light ();
 %!   assert (get (h, "facelighting"), "flat");
 %!   assert (get (h, "facenormals"), [0 0 1], eps);
 %!   assert (get (h, "vertexnormals"), []);
--- a/scripts/plot/draw/pie.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/pie.m	Sun May 16 09:44:35 2021 +0200
@@ -113,6 +113,6 @@
 %! title ("pie() with missing slice");
 
 ## Test input validation
-%!error pie ()
+%!error <Invalid call> pie ()
 %!error <all data in X must be finite> pie ([1 2 Inf])
 %!error <all data in X must be finite> pie ([1 2 NaN])
--- a/scripts/plot/draw/pie3.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/pie3.m	Sun May 16 09:44:35 2021 +0200
@@ -112,6 +112,6 @@
 %! title ("pie3() with missing slice");
 
 ## Test input validation
-%!error pie3 ()
+%!error <Invalid call> pie3 ()
 %!error <all data in X must be finite> pie3 ([1 2 Inf])
 %!error <all data in X must be finite> pie3 ([1 2 NaN])
--- a/scripts/plot/draw/plot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/plot.m	Sun May 16 09:44:35 2021 +0200
@@ -152,24 +152,26 @@
 ##
 ## @item color
 ##
-## @multitable @columnfractions 0.06 0.94
-## @item @samp{k} @tab blacK
-## @item @samp{r} @tab Red
-## @item @samp{g} @tab Green
-## @item @samp{b} @tab Blue
-## @item @samp{y} @tab Yellow
-## @item @samp{m} @tab Magenta
-## @item @samp{c} @tab Cyan
-## @item @samp{w} @tab White
+## @multitable @columnfractions 0.21 0.79
+## @item @samp{k}, @qcode{"black"}   @tab blacK
+## @item @samp{r}, @qcode{"red"}     @tab Red
+## @item @samp{g}, @qcode{"green"}   @tab Green
+## @item @samp{b}, @qcode{"blue"}    @tab Blue
+## @item @samp{y}, @qcode{"yellow"}  @tab Yellow
+## @item @samp{m}, @qcode{"magenta"} @tab Magenta
+## @item @samp{c}, @qcode{"cyan"}    @tab Cyan
+## @item @samp{w}, @qcode{"white"}   @tab White
 ## @end multitable
 ##
 ## @item @qcode{";displayname;"}
-## Here @qcode{"displayname"} is the label to use for the plot legend.
+## The text between semicolons is used to set the @qcode{"displayname"}
+## property which determines the label used for the plot legend.
+##
 ## @end table
 ##
 ## The @var{fmt} argument may also be used to assign legend labels.
 ## To do so, include the desired label between semicolons after the
-## formatting sequence described above, e.g., @qcode{"+b;Key Title;"}.
+## formatting sequence described above, e.g., @qcode{"+b;Data Series 3;"}.
 ## Note that the last semicolon is required and Octave will generate
 ## an error if it is left out.
 ##
--- a/scripts/plot/draw/plotmatrix.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/plotmatrix.m	Sun May 16 09:44:35 2021 +0200
@@ -78,7 +78,7 @@
 
   [bigax2, varargin, nargin] = __plt_get_axis_arg__ ("plotmatrix", varargin{:});
 
-  if (nargin > 3 || nargin < 1)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
@@ -121,7 +121,7 @@
 %! title ("plotmatrix() demo #1");
 
 
-function plotmatrixdelete (h, d, ax)
+function plotmatrixdelete (h, ~, ax)
 
   for i = 1 : numel (ax)
     hc = ax(i);
--- a/scripts/plot/draw/plotyy.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/plotyy.m	Sun May 16 09:44:35 2021 +0200
@@ -43,8 +43,10 @@
 ## The function to use for each of the plots can be independently defined
 ## with @var{fun1} and @var{fun2}.
 ##
-## If the first argument @var{hax} is an axes handle, then it defines
-## the principal axes in which to plot the @var{x1} and @var{y1} data.
+## The first argument @var{hax} can be an axes handle to the principal axes in
+## which to plot the @var{x1} and @var{y1} data.  It can also be a two-element
+## vector with the axes handles to the primary and secondary axes (see output
+## @var{ax}).
 ##
 ## The return value @var{ax} is a vector with the axes handles of the two
 ## y-axes.  @var{h1} and @var{h2} are handles to the objects generated by the
@@ -72,7 +74,17 @@
 
 function [ax, h1, h2] = plotyy (varargin)
 
-  [hax, varargin] = __plt_get_axis_arg__ ("plotyy", varargin{:});
+  ## Check if first argument is axes handle(s).
+  hax = [];
+  if numel (varargin) > 0
+    if (isscalar (varargin{1}))
+      [hax, varargin] = __plt_get_axis_arg__ ("plotyy", varargin{:});
+    elseif (numel (varargin{1}) == 2 && all (isaxes (varargin{1})))
+      ## First argument might be vector with the two handles to plotyy axes.
+      hax = varargin{1}(1);
+      varargin(1) = [];
+    endif
+  endif
 
   nargin = numel (varargin);
   if (nargin < 4 || nargin > 6)
@@ -93,7 +105,7 @@
       hax = get (hax, "__plotyy_axes__");
     else
       hax = [hax; axes("nextplot", get (hax(1), "nextplot"), ...
-                       "parent", get(hax(1), "parent"))];
+                       "parent", get (hax(1), "parent"))];
     endif
 
     [axtmp, h1tmp, h2tmp] = __plotyy__ (hax, varargin{:});
@@ -136,15 +148,21 @@
 
   axes (ax(2));
 
+  if (strcmp (get (ax(1), "nextplot"), "replace"))
+    ## Reset axes here because we don't want it to reset later after we set
+    ## some properties in preparation for the plot in the secondary axes.
+    reset (ax(2));
+  endif
+
   colors = get (ax(1), "colororder");
   set (ax(2), "colororder", circshift (colors, -numel (h1), 1));
 
   if (strcmp (get (ax(1), "__autopos_tag__"), "subplot"))
     set (ax(2), "__autopos_tag__", "subplot");
   elseif (strcmp (graphics_toolkit (), "gnuplot"))
-    set (ax, "activepositionproperty", "position");
+    set (ax, "positionconstraint", "innerposition");
   else
-    set (ax, "activepositionproperty", "outerposition");
+    set (ax, "positionconstraint", "outerposition");
   endif
 
   ## Don't replace axis which has colororder property already modified
@@ -161,7 +179,7 @@
   endif
 
   set (ax(2), "units", get (ax(1), "units"));
-  if (strcmp (get(ax(1), "activepositionproperty"), "position"))
+  if (strcmp (get (ax(1), "positionconstraint"), "innerposition"))
     set (ax(2), "position", get (ax(1), "position"));
   else
     set (ax(2), {"outerposition", "looseinset"},
@@ -198,21 +216,20 @@
   ## Store the axes handles for the sister axes.
   if (! isprop (ax(1), "__plotyy_axes__"))
     addproperty ("__plotyy_axes__", ax(1), "data");
-    set (ax(1), "__plotyy_axes__", ax);
-  else
-    set (ax(1), "__plotyy_axes__", ax);
   endif
+  set (ax(1), "__plotyy_axes__", ax);
   if (! isprop (ax(2), "__plotyy_axes__"))
     addproperty ("__plotyy_axes__", ax(2), "data");
-    set (ax(2), "__plotyy_axes__", ax);
-  else
-    set (ax(2), "__plotyy_axes__", ax);
   endif
+  set (ax(2), "__plotyy_axes__", ax);
+
+  ## Call position property listener explicitly
+  update_prop (ax(1), [], ax(2), "position");
 
 endfunction
 
 function deleteplotyy (h, ~, ax2, t2)
-  if (isaxes (ax2))
+  if (isaxes (ax2) && ! any (strcmp({dbstack().name}, "plotyy")))
     set (t2, "deletefcn", []);
     delete (ax2);
   endif
@@ -241,8 +258,8 @@
       val = get (h, prop);
       if (strcmpi (prop, "position") || strcmpi (prop, "outerposition"))
         ## Save/restore "positionconstraint"
-        constraint = get (ax2, "activepositionproperty");
-        set (ax2, prop, get (h, prop), "activepositionproperty", constraint);
+        constraint = get (ax2, "positionconstraint");
+        set (ax2, prop, get (h, prop), "positionconstraint", constraint);
       else
         set (ax2, prop, get (h, prop));
       endif
@@ -292,13 +309,13 @@
 %! colormap ("default");
 %! x = linspace (-1, 1, 201);
 %! subplot (2,2,1);
-%!  plotyy (x,sin(pi*x), x,10*cos(pi*x));
+%!  plotyy (x,sin (pi*x), x,10*cos (pi*x));
 %!  title ("plotyy() in subplot");
 %! subplot (2,2,2);
 %!  surf (peaks (25));
 %! subplot (2,2,3);
 %!  contour (peaks (25));
 %! subplot (2,2,4);
-%!  plotyy (x,10*sin(2*pi*x), x,cos(2*pi*x));
+%!  plotyy (x,10*sin (2*pi*x), x,cos (2*pi*x));
 %!  title ("plotyy() in subplot");
 %!  axis square;
--- a/scripts/plot/draw/polar.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/polar.m	Sun May 16 09:44:35 2021 +0200
@@ -34,8 +34,8 @@
 ##
 ## The input @var{theta} is assumed to be radians and is converted to degrees
 ## for plotting.  If you have degrees then you must convert
-## (@pxref{XREFcart2pol,,cart2pol}) to radians before passing the data to this
-## function.
+## (@pxref{XREFcart2pol,,@code{cart2pol}}) to radians before passing the
+## data to this function.
 ##
 ## If a single complex input @var{cplx} is given then the real part is used
 ## for @var{theta} and the imaginary part is used for @var{rho}.
@@ -398,6 +398,7 @@
 endfunction
 
 function resetaxis (~, ~, hax)
+
   if (isaxes (hax))
     dellistener (hax, "rtick");
     dellistener (hax, "ttick");
@@ -412,6 +413,7 @@
     dellistener (hax, "gridlinestyle");
     dellistener (hax, "linewidth");
   endif
+
 endfunction
 
 
--- a/scripts/plot/draw/private/__bar__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__bar__.m	Sun May 16 09:44:35 2021 +0200
@@ -28,7 +28,7 @@
 ## Undocumented internal function.
 ## @end deftypefn
 
-function varargout = __bar__ (vertical, func, varargin)
+function varargout = __bar__ (func, vertical, varargin)
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ (func, varargin{:});
 
@@ -38,6 +38,7 @@
 
   width = 0.8;
   group = true;
+  stacked = false;
   histc = NA;
   ## BaseValue
   if (strcmp (get (hax, "yscale"), "log"))
@@ -84,6 +85,7 @@
       group = true;
       idx += 1;
     elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "stacked"))
+      stacked = true;
       group = false;
       idx += 1;
     elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "histc"))
@@ -123,6 +125,8 @@
     endif
   endwhile
 
+  ishist = islogical (histc);
+
   ngrp = rows (x);
 
   if (isvector (y) && ngrp != rows (y))
@@ -135,7 +139,7 @@
   nbars = columns (y);
 
   ## Column width is 1 for 'hist*' styles (bars touch).
-  if (islogical (histc))
+  if (ishist)
     cwidth = 1;
     if (nbars == 1)
       gwidth = 1;
@@ -171,7 +175,7 @@
   xb = repmat ([x1; x1; x2; x2](:), 1, nbars);
 
   if (group)
-    if (islogical (histc) && histc)
+    if (ishist && histc)
       offset = 2*cdelta * [0:(nbars-1)] + cdelta(1);  # not centered
     else
       offset = 2*cdelta * [-(nbars - 1) / 2 : (nbars - 1) / 2];
@@ -185,8 +189,22 @@
     y0 = zeros (size (y)) + bv;
     y1 = y;
   else
-    y1 = cumsum (y,2);
-    y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
+    if (stacked && any (y(:) < 0))
+      ypos = (y >= 0);
+      yneg = (y <  0);
+
+      y1p =  cumsum (y .* ypos, 2);
+      y1n =  cumsum (y .* yneg, 2);
+      y1 = y1p .* ypos + y1n .* yneg;
+
+      y0p = [zeros(ngrp,1)+bv, y1p(:,1:end-1)];
+      y0n = [zeros(ngrp,1)+bv, y1n(:,1:end-1)];
+      y0 = y0p .* ypos + y0n .* yneg;
+
+    else
+      y1 = cumsum (y,2);
+      y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
+    endif
   endif
 
   yb = zeros (4*ngrp, nbars);
@@ -206,7 +224,7 @@
     unwind_protect
       hax = newplot (hax);
 
-      htmp = bars (hax, vertical, x, y, xb, yb, gwidth, group,
+      htmp = bars (hax, ishist, vertical, x, y, xb, yb, gwidth, group,
                    have_line_spec, bv, newargs{:});
 
       if (! ishold ())
@@ -219,11 +237,15 @@
             set (hax, "ytick", x(:,1));
           endif
         endif
-        ## Hack prevents color and xlim setting changes when basevalue changes.
-        if (vertical)
-          set (hax, "clim", [0 1], "xlimmode", "manual");
+        if (ishist)
+          set (hax, "climmode", "auto");
         else
-          set (hax, "clim", [0 1], "ylimmode", "manual");
+          ## Hack prevents xlim setting changes when basevalue changes.
+          if (vertical)
+            set (hax, "xlimmode", "manual");
+          else
+            set (hax, "ylimmode", "manual");
+          endif
         endif
         set (hax, "box", "on", "layer", "top");
       endif
@@ -247,12 +269,35 @@
 
 endfunction
 
-function hglist = bars (hax, vertical, x, y, xb, yb, width, group, have_color_spec, base_value, varargin)
+function hglist = bars (hax, ishist, vertical, x, y, xb, yb, width, group, have_color_spec, base_value, varargin)
 
+  hglist = [];
   nbars = columns (y);
-  clim = get (hax, "clim");
-  hglist = [];
+
+  if (ishist)
+    ## Special case for Matlab compatibility.  For 'hist', 'histc' arguments,
+    ## return Patch objects rather than hggroup Bar object.
+    for i = 1:nbars
 
+      if (vertical)
+        h = patch (hax, xb(:,:,i), yb(:,:,i),
+                   "cdata", i*ones (columns (xb),1), "FaceColor", "flat");
+      else
+        h = patch (hax, yb(:,:,i), xb(:,:,i),
+                   "cdata", i*ones (columns (yb),1), "FaceColor", "flat");
+      endif
+
+      if (! isempty (varargin))
+        set (h, varargin{:});
+      endif
+
+      hglist = [hglist; h];
+    endfor
+
+    return;  # return immediately, rest of function is for creating Bar object.
+  endif
+
+  ## Code to create hggroup Bar object
   for i = 1:nbars
     hg = hggroup ();
     hglist = [hglist; hg];
@@ -260,27 +305,17 @@
 
     if (vertical)
       if (! have_color_spec)
-        if (nbars == 1)
-          lev = clim(1);
-        else
-          lev = (i - 1) * (clim(2) - clim(1)) / (nbars - 1) - clim(1);
-        endif
-        h = patch (hax, xb(:,:,i), yb(:,:,i),
-                        "FaceColor", "flat", "cdata", lev, "parent", hg);
+        color = __next_line_color__ ();
+        h = patch (hax, xb(:,:,i), yb(:,:,i), "FaceColor", color, "parent", hg);
       else
-        h = patch (hax, xb(:,:,i), yb(:,:,i), "parent", hg);
+        h = patch (hax, xb(:,:,i), yb(:,:,i), "cdata", i, "parent", hg);
       endif
     else
       if (! have_color_spec)
-        if (nbars == 1)
-          lev = clim(1);
-        else
-          lev = (i - 1) * (clim(2) - clim(1)) / (nbars - 1) - clim(1);
-        endif
-        h = patch (hax, yb(:,:,i), xb(:,:,i),
-                        "FaceColor", "flat", "cdata", lev, "parent", hg);
+        color = __next_line_color__ ();
+        h = patch (hax, yb(:,:,i), xb(:,:,i), "FaceColor", color, "parent", hg);
       else
-        h = patch (hax, yb(:,:,i), xb(:,:,i), "parent", hg);
+        h = patch (hax, yb(:,:,i), xb(:,:,i), "cdata", i, "parent", hg);
       endif
     endif
 
--- a/scripts/plot/draw/private/__contour__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__contour__.m	Sun May 16 09:44:35 2021 +0200
@@ -197,6 +197,9 @@
   addproperty ("linestyle", hg, "linelinestyle", linespec.linestyle);
   addproperty ("linewidth", hg, "linelinewidth", 0.5);
 
+  ## Matlab property just for compatibility (bug #60513).
+  addproperty ("facecolor", hg, "patchfacecolor", "none");
+
   ## Matlab property, although Octave does not implement it.
   addproperty ("hittestarea", hg, "radio", "on|{off}", "off");
 
--- a/scripts/plot/draw/private/__ezplot__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__ezplot__.m	Sun May 16 09:44:35 2021 +0200
@@ -364,7 +364,7 @@
         Y = __eliminate_sing__ (Y);
         Z = __eliminate_sing__ (Z);
       endif
-    else  ## non-parametric plots
+    else  # non-parametric plots
       if (isplot && nargs == 2)
         Z = feval (fun, X, Y);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/private/__gnuplot_scatter__.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,345 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn {} {@var{hg} =} __gnuplot_scatter__ (@dots{})
+## Undocumented internal function.
+## @end deftypefn
+
+function hg = __gnuplot_scatter__ (hax, fcn, x, y, z, c, s, marker, filled, newargs)
+
+if (isempty (c))
+  c = __next_line_color__ ();
+endif
+
+## Must occur after __next_line_color__ in order to work correctly.
+hg = hggroup (hax, "__appdata__", struct ("__creator__", "__scatter__"));
+newargs = __add_datasource__ (fcn, hg, {"x", "y", "z", "c", "size"},
+                              newargs{:});
+
+addproperty ("xdata", hg, "data", x);
+addproperty ("ydata", hg, "data", y);
+addproperty ("zdata", hg, "data", z);
+if (ischar (c))
+  ## For single explicit color, cdata is unused
+  addproperty ("cdata", hg, "data", []);
+else
+  addproperty ("cdata", hg, "data", c);
+endif
+addproperty ("sizedata", hg, "data", s);
+addlistener (hg, "xdata", @update_data);
+addlistener (hg, "ydata", @update_data);
+addlistener (hg, "zdata", @update_data);
+addlistener (hg, "cdata", @update_data);
+addlistener (hg, "sizedata", @update_data);
+
+one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
+s = sqrt (s);  # size adjustment for visual compatibility w/Matlab
+
+if (numel (x) <= 100)
+
+  ## For small number of points, we'll construct an object for each point.
+
+  if (numel (s) == 1)
+    s = repmat (s, numel (x), 1);
+  endif
+
+  if (one_explicit_color)
+    for i = 1 : numel (x)
+      if (filled)
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                      "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
+                      "faces", 1, "vertices", [x(i), y(i), z(i,:)],
+                      "marker", marker,  "markersize", s(i),
+                      "markeredgecolor", c, "markerfacecolor", c,
+                      "linestyle", "none");
+      else
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                      "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
+                      "faces", 1, "vertices", [x(i), y(i), z(i,:)],
+                      "marker", marker,  "markersize", s(i),
+                      "markeredgecolor", c, "markerfacecolor", "none",
+                      "linestyle", "none");
+      endif
+    endfor
+  else
+    if (rows (c) == 1)
+      c = repmat (c, rows (x), 1);
+    endif
+    for i = 1 : numel (x)
+      if (filled)
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                      "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
+                      "faces", 1, "vertices", [x(i), y(i), z(i,:)],
+                      "marker", marker, "markersize", s(i),
+                      "markeredgecolor", "none",
+                      "markerfacecolor", "flat",
+                      "cdata", c(i,:), "facevertexcdata", c(i,:),
+                      "linestyle", "none");
+      else
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                      "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
+                      "faces", 1, "vertices", [x(i), y(i), z(i,:)],
+                      "marker", marker, "markersize", s(i),
+                      "markeredgecolor", "flat",
+                      "markerfacecolor", "none",
+                      "cdata", c(i,:), "facevertexcdata", c(i,:),
+                      "linestyle", "none");
+      endif
+    endfor
+  endif
+
+else
+
+  ## For larger numbers of points, we use one single object.
+  vert = [x, y, z];
+  render_size_color (hg, vert, s, c, marker, filled, true);
+
+endif
+
+if (! ischar (c) && rows (c) > 1)
+  ax = get (hg, "parent");
+  clim = get (ax, "clim");
+  if (min (c(:)) < clim(1))
+    clim(1) = min (c(:));
+    set (ax, "clim", clim);
+  endif
+  if (max (c(:)) > clim(2))
+    set (ax, "clim", [clim(1), max(c(:))]);
+  endif
+endif
+
+addproperty ("linewidth", hg, "patchlinewidth", 0.5);
+addproperty ("marker", hg, "patchmarker", marker);
+if (filled)
+  addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "none");
+  if (one_explicit_color)
+    addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", c);
+  else
+    addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "flat");
+  endif
+else
+  addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "none");
+  if (one_explicit_color)
+    addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", c);
+  else
+    addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "flat");
+  endif
+endif
+addlistener (hg, "linewidth", @update_props);
+addlistener (hg, "marker", @update_props);
+addlistener (hg, "markerfacecolor", @update_props);
+addlistener (hg, "markeredgecolor", @update_props);
+
+## Matlab property, although Octave does not implement it.
+addproperty ("hittestarea", hg, "radio", "on|{off}", "off");
+
+if (! isempty (newargs))
+  set (hg, newargs{:});
+endif
+
+endfunction
+
+function render_size_color (hg, vert, s, c, marker, filled, isflat)
+
+  if (isempty (c))
+    c = __next_line_color__ ();
+  endif
+
+  if (isscalar (s))
+    x = vert(:,1);
+    y = vert(:,2);
+    z = vert(:,3:end);
+    toolkit = get (ancestor (hg, "figure"), "__graphics_toolkit__");
+    ## Does gnuplot only support triangles with different vertex colors ?
+    ## FIXME: Verify gnuplot can only support one color.  If RGB triplets
+    ##        can be assigned to each vertex, then fix __gnuplot_draw_axes__.m
+    gnuplot_hack = (numel (x) > 1 && columns (c) == 3
+                    && strcmp (toolkit, "gnuplot"));
+    if (ischar (c) || ! isflat || gnuplot_hack)
+      if (filled)
+        ## "facecolor" and "edgecolor" must be set before any other properties
+        ## to skip co-planarity check (see bug #55751).
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                          "xdata", x, "ydata", y, "zdata", z,
+                          "faces", 1:numel (x), "vertices", vert,
+                          "marker", marker,
+                          "markeredgecolor", "none",
+                          "markerfacecolor", c(1,:),
+                          "markersize", s, "linestyle", "none");
+      else
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                          "xdata", x, "ydata", y, "zdata", z,
+                          "faces", 1:numel (x), "vertices", vert,
+                          "marker", marker,
+                          "markeredgecolor", c(1,:),
+                          "markerfacecolor", "none",
+                          "markersize", s, "linestyle", "none");
+      endif
+    else
+      if (filled)
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                          "xdata", x, "ydata", y, "zdata", z,
+                          "faces", 1:numel (x), "vertices", vert,
+                          "marker", marker, "markersize", s,
+                          "markeredgecolor", "none",
+                          "markerfacecolor", "flat",
+                          "cdata", c, "facevertexcdata", c,
+                          "linestyle", "none");
+      else
+        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
+                          "xdata", x, "ydata", y, "zdata", z,
+                          "faces", 1:numel (x), "vertices", vert,
+                          "marker", marker, "markersize", s,
+                          "markeredgecolor", "flat",
+                          "markerfacecolor", "none",
+                          "cdata", c, "facevertexcdata", c,
+                          "linestyle", "none");
+      endif
+    endif
+  else
+    ## Round size to one decimal place.
+    [ss, ~, s_to_ss] = unique (ceil (s*10) / 10);
+    for i = 1:rows (ss)
+      idx = (i == s_to_ss);
+      render_size_color (hg, vert(idx,:), ss(i), c,
+                             marker, filled, isflat);
+    endfor
+  endif
+
+endfunction
+
+function update_props (h, ~)
+
+  lw = get (h, "linewidth");
+  m  = get (h, "marker");
+  fc = get (h, "markerfacecolor");
+  ec = get (h, "markeredgecolor");
+  kids = get (h, "children");
+
+  set (kids, "linewidth", lw, "marker", m,
+             "markerfacecolor", fc, "markeredgecolor", ec);
+
+endfunction
+
+## FIXME: This callback routine doesn't handle the case where N > 100.
+function update_data (h, ~)
+
+  x = get (h, "xdata");
+  y = get (h, "ydata");
+  z = get (h, "zdata");
+  if (numel (x) > 100)
+    error ("scatter: cannot update data with more than 100 points.  Call scatter (x, y, ...) with new data instead.");
+  endif
+  c = get (h, "cdata");
+  one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
+  if (! one_explicit_color)
+    if (rows (c) == 1)
+      c = repmat (c, numel (x), 1);
+    endif
+  endif
+  filled = ! strcmp (get (h, "markerfacecolor"), "none");
+  s = get (h, "sizedata");
+  ## Size adjustment for visual compatibility with Matlab.
+  s = sqrt (s);
+  if (numel (s) == 1)
+    s = repmat (s, numel (x), 1);
+  endif
+  hlist = get (h, "children");
+
+  if (one_explicit_color)
+    if (filled)
+      if (isempty (z))
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", c, "markerfacecolor", c);
+
+        endfor
+      else
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i), z(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", c, "markerfacecolor", c);
+        endfor
+      endif
+    else
+      if (isempty (z))
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", c, "markerfacecolor", "none");
+
+        endfor
+      else
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i), z(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", c, "markerfacecolor", "none");
+        endfor
+      endif
+    endif
+  else
+    if (filled)
+      if (isempty (z))
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", "none", "markerfacecolor", "flat",
+                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
+                         "facevertexcdata", c(i,:));
+        endfor
+      else
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i), z(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", "none", "markerfacecolor", "flat",
+                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
+                         "facevertexcdata", c(i,:));
+        endfor
+      endif
+    else
+      if (isempty (z))
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", "flat", "markerfacecolor", "none",
+                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
+                         "facevertexcdata", c(i,:));
+        endfor
+      else
+        for i = 1 : length (hlist)
+          set (hlist(i), "vertices", [x(i), y(i), z(i)],
+                         "markersize", s(i),
+                         "markeredgecolor", "flat", "markerfacecolor", "none",
+                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
+                         "facevertexcdata", c(i,:));
+        endfor
+      endif
+    endif
+  endif
+
+endfunction
+
--- a/scripts/plot/draw/private/__line__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__line__.m	Sun May 16 09:44:35 2021 +0200
@@ -24,8 +24,8 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{h} =} __line__ (@var{parent}, @dots{})
-## Create line object with parent @var{parent}.
+## @deftypefn {} {@var{h} =} __line__ (@var{hp}, @dots{})
+## Create line object with parent handle @var{hp}.
 ##
 ## Return handle @var{h} to created line objects.
 ## @end deftypefn
--- a/scripts/plot/draw/private/__marching_cube__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__marching_cube__.m	Sun May 16 09:44:35 2021 +0200
@@ -24,18 +24,18 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {[@var{t}, @var{p}] =} __marching_cube__ (@var{x}, @var{y}, @var{z}, @var{val}, @var{iso})
-## @deftypefnx {} {[@var{t}, @var{p}, @var{c}] =} __marching_cube__ (@var{x}, @var{y}, @var{z}, @var{val}, @var{iso}, @var{col})
+## @deftypefn  {} {[@var{t}, @var{p}] =} __marching_cube__ (@var{xx}, @var{yy}, @var{zz}, @var{val}, @var{iso})
+## @deftypefnx {} {[@var{t}, @var{p}, @var{c}] =} __marching_cube__ (@var{xx}, @var{yy}, @var{zz}, @var{v}, @var{iso}, @var{colors})
 ##
 ## Return the triangulation information @var{t} at points @var{p} for the
-## isosurface values resp. the volume data @var{val} and the iso level
-## @var{iso}.  It is considered that the volume data @var{val} is given at
-## the points @var{x}, @var{y} and @var{z} which are of type
+## isosurface values resp. the volume data @var{v} and the iso level
+## @var{iso}.  It is considered that the volume data @var{v} is given at
+## the points @var{xx}, @var{yy}, and @var{zz} which are of type
 ## three-dimensional numeric arrays.  The orientation of the triangles is
 ## chosen such that the normals point from the higher values to the lower
 ## values.
 ##
-## Optionally the color data @var{col} can be passed to this function
+## Optionally the color data @var{colors} can be passed to this function
 ## whereas computed vertices color data @var{c} is returned as third
 ## argument.
 ##
@@ -51,10 +51,10 @@
 ## @group
 ## N = 20;
 ## lin = linspace (0, 2, N);
-## [x, y, z] = meshgrid (lin, lin, lin);
+## [xx, yy, zz] = meshgrid (lin, lin, lin);
 ##
-## c = (x-.5).^2 + (y-.5).^2 + (z-.5).^2;
-## [t, p] = __marching_cube__ (x, y, z, c, .5);
+## v = (xx-.5).^2 + (yy-.5).^2 + (zz-.5).^2;
+## [t, p] = __marching_cube__ (xx, yy, zz, v, .5);
 ##
 ## figure ();
 ## trimesh (t, p(:,1), p(:,2), p(:,3));
@@ -82,7 +82,7 @@
 ##
 ## @end deftypefn
 
-function [T, p, col] = __marching_cube__ (xx, yy, zz, c, iso, colors)
+function [T, p, col] = __marching_cube__ (xx, yy, zz, v, iso, colors)
 
   persistent edge_table = [];
   persistent tri_table = [];
@@ -94,19 +94,14 @@
     [edge_table, tri_table] = init_mc ();
   endif
 
-  ## FIXME: Do we need all of the following validation on an internal function?
-  if ((nargin != 5 && nargin != 6) || (nargout != 2 && nargout != 3))
-    print_usage ();
+  if (! isnumeric (xx) || ! isnumeric (yy) || ! isnumeric (zz)
+      || ! isnumeric (v) || ndims (xx) != 3 || ndims (yy) != 3
+      || ndims (zz) != 3 || ndims (v) != 3)
+    error ("__marching_cube__: XX, YY, ZZ, v must be 3-D matrices");
   endif
 
-  if (! isnumeric (xx) || ! isnumeric (yy) || ! isnumeric (zz)
-      || ! isnumeric (c) || ndims (xx) != 3 || ndims (yy) != 3
-      || ndims (zz) != 3 || ndims (c) != 3)
-    error ("__marching_cube__: XX, YY, ZZ, C must be 3-D matrices");
-  endif
-
-  if (! size_equal (xx, yy, zz, c))
-    error ("__marching_cube__: XX, YY, ZZ, C must be of equal size");
+  if (! size_equal (xx, yy, zz, v))
+    error ("__marching_cube__: XX, YY, ZZ, v must be of equal size");
   endif
 
   if (any (size (xx) < [2 2 2]))
@@ -118,14 +113,14 @@
   endif
 
   if (nargin == 6)
-    if (! isnumeric (colors) || ndims (colors) != 3 || ! size_equal (colors, c))
-      error ( "COLORS must be a 3-D matrix with the same size as C" );
+    if (! isnumeric (colors) || ndims (colors) != 3 || ! size_equal (colors, v))
+      error ( "COLORS must be a 3-D matrix with the same size as v" );
     endif
     calc_cols = true;
     lindex = 5;
   endif
 
-  n = size (c) - 1;
+  n = size (v) - 1;
 
   ## phase I: assign information to each voxel which edges are intersected by
   ## the isosurface.
@@ -143,7 +138,7 @@
 
   ## calculate which vertices have values higher than iso
   for ii = 1:8
-    idx = c(vertex_idx{ii, :}) > iso;
+    idx = v(vertex_idx{ii, :}) > iso;
     cc(idx) = bitset (cc(idx), ii);
   endfor
 
@@ -157,7 +152,7 @@
   ## phase II: calculate the list of intersection points
   xyz_off = [1, 1, 1; 2, 1, 1; 2, 2, 1; 1, 2, 1; 1, 1, 2; 2, 1, 2; 2, 2, 2; 1, 2, 2];
   edges = [1 2; 2 3; 3 4; 4 1; 5 6; 6 7; 7 8; 8 5; 1 5; 2 6; 3 7; 4 8];
-  offset = sub2ind (size (c), xyz_off(:, 1), xyz_off(:, 2), xyz_off(:, 3)) - 1;
+  offset = sub2ind (size (v), xyz_off(:, 1), xyz_off(:, 2), xyz_off(:, 3)) - 1;
   pp = zeros (length (id), lindex, 12);
   ccedge = [vec(cedge(id)), id];
   ix_offset=0;
@@ -165,16 +160,16 @@
     id__ = bitget (ccedge(:, 1), jj);
     id_ = ccedge(id__, 2);
     [ix iy iz] = ind2sub (size (cc), id_);
-    id_c = sub2ind (size (c), ix, iy, iz);
+    id_c = sub2ind (size (v), ix, iy, iz);
     id1 = id_c + offset(edges(jj, 1));
     id2 = id_c + offset(edges(jj, 2));
     if (calc_cols)
       pp(id__, 1:5, jj) = [vertex_interp(iso, xx(id1), yy(id1), zz(id1), ...
-        xx(id2), yy(id2), zz(id2), c(id1), c(id2), colors(id1), colors(id2)), ...
+        xx(id2), yy(id2), zz(id2), v(id1), v(id2), colors(id1), colors(id2)), ...
         (1:rows (id_))' + ix_offset ];
     else
       pp(id__, 1:4, jj) = [vertex_interp(iso, xx(id1), yy(id1), zz(id1), ...
-        xx(id2), yy(id2), zz(id2), c(id1), c(id2)), ...
+        xx(id2), yy(id2), zz(id2), v(id1), v(id2)), ...
         (1:rows (id_))' + ix_offset ];
     endif
     ix_offset += rows (id_);
@@ -245,38 +240,38 @@
 function [edge_table, tri_table] = init_mc ()
 
   edge_table = [
-  0x0  , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, ...
-  0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, ...
-  0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, ...
-  0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, ...
-  0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, ...
-  0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, ...
-  0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, ...
-  0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, ...
-  0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, ...
-  0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, ...
-  0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, ...
-  0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, ...
-  0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, ...
-  0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, ...
-  0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , ...
-  0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, ...
-  0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, ...
-  0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, ...
-  0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, ...
-  0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, ...
-  0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, ...
-  0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, ...
-  0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, ...
-  0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, ...
-  0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, ...
-  0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, ...
-  0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, ...
-  0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, ...
-  0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, ...
-  0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, ...
-  0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, ...
-  0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0   ];
+    0x0000, 0x0109, 0x0203, 0x030a, 0x0406, 0x050f, 0x0605, 0x070c, ...
+    0x080c, 0x0905, 0x0a0f, 0x0b06, 0x0c0a, 0x0d03, 0x0e09, 0x0f00, ...
+    0x0190, 0x0099, 0x0393, 0x029a, 0x0596, 0x049f, 0x0795, 0x069c, ...
+    0x099c, 0x0895, 0x0b9f, 0x0a96, 0x0d9a, 0x0c93, 0x0f99, 0x0e90, ...
+    0x0230, 0x0339, 0x0033, 0x013a, 0x0636, 0x073f, 0x0435, 0x053c, ...
+    0x0a3c, 0x0b35, 0x083f, 0x0936, 0x0e3a, 0x0f33, 0x0c39, 0x0d30, ...
+    0x03a0, 0x02a9, 0x01a3, 0x00aa, 0x07a6, 0x06af, 0x05a5, 0x04ac, ...
+    0x0bac, 0x0aa5, 0x09af, 0x08a6, 0x0faa, 0x0ea3, 0x0da9, 0x0ca0, ...
+    0x0460, 0x0569, 0x0663, 0x076a, 0x0066, 0x016f, 0x0265, 0x036c, ...
+    0x0c6c, 0x0d65, 0x0e6f, 0x0f66, 0x086a, 0x0963, 0x0a69, 0x0b60, ...
+    0x05f0, 0x04f9, 0x07f3, 0x06fa, 0x01f6, 0x00ff, 0x03f5, 0x02fc, ...
+    0x0dfc, 0x0cf5, 0x0fff, 0x0ef6, 0x09fa, 0x08f3, 0x0bf9, 0x0af0, ...
+    0x0650, 0x0759, 0x0453, 0x055a, 0x0256, 0x035f, 0x0055, 0x015c, ...
+    0x0e5c, 0x0f55, 0x0c5f, 0x0d56, 0x0a5a, 0x0b53, 0x0859, 0x0950, ...
+    0x07c0, 0x06c9, 0x05c3, 0x04ca, 0x03c6, 0x02cf, 0x01c5, 0x00cc, ...
+    0x0fcc, 0x0ec5, 0x0dcf, 0x0cc6, 0x0bca, 0x0ac3, 0x09c9, 0x08c0, ...
+    0x08c0, 0x09c9, 0x0ac3, 0x0bca, 0x0cc6, 0x0dcf, 0x0ec5, 0x0fcc, ...
+    0x00cc, 0x01c5, 0x02cf, 0x03c6, 0x04ca, 0x05c3, 0x06c9, 0x07c0, ...
+    0x0950, 0x0859, 0x0b53, 0x0a5a, 0x0d56, 0x0c5f, 0x0f55, 0x0e5c, ...
+    0x015c, 0x0055, 0x035f, 0x0256, 0x055a, 0x0453, 0x0759, 0x0650, ...
+    0x0af0, 0x0bf9, 0x08f3, 0x09fa, 0x0ef6, 0x0fff, 0x0cf5, 0x0dfc, ...
+    0x02fc, 0x03f5, 0x00ff, 0x01f6, 0x06fa, 0x07f3, 0x04f9, 0x05f0, ...
+    0x0b60, 0x0a69, 0x0963, 0x086a, 0x0f66, 0x0e6f, 0x0d65, 0x0c6c, ...
+    0x036c, 0x0265, 0x016f, 0x0066, 0x076a, 0x0663, 0x0569, 0x0460, ...
+    0x0ca0, 0x0da9, 0x0ea3, 0x0faa, 0x08a6, 0x09af, 0x0aa5, 0x0bac, ...
+    0x04ac, 0x05a5, 0x06af, 0x07a6, 0x00aa, 0x01a3, 0x02a9, 0x03a0, ...
+    0x0d30, 0x0c39, 0x0f33, 0x0e3a, 0x0936, 0x083f, 0x0b35, 0x0a3c, ...
+    0x053c, 0x0435, 0x073f, 0x0636, 0x013a, 0x0033, 0x0339, 0x0230, ...
+    0x0e90, 0x0f99, 0x0c93, 0x0d9a, 0x0a96, 0x0b9f, 0x0895, 0x099c, ...
+    0x069c, 0x0795, 0x049f, 0x0596, 0x029a, 0x0393, 0x0099, 0x0190, ...
+    0x0f00, 0x0e09, 0x0d03, 0x0c0a, 0x0b06, 0x0a0f, 0x0905, 0x080c, ...
+    0x070c, 0x0605, 0x050f, 0x0406, 0x030a, 0x0203, 0x0109, 0x0000 ];
 
   tri_table = [
   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1;
--- a/scripts/plot/draw/private/__pie__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__pie__.m	Sun May 16 09:44:35 2021 +0200
@@ -130,7 +130,7 @@
 
       hlist = [hlist;
         patch(xoff + [0, -sind(xn)], yoff + [0, cosd(xn)], zeros (1, ln + 1), i);
-        surface(sx, sy, sz, sc);
+        surface (sx, sy, sz, sc);
         patch(xoff + [0, -sind(xn)], yoff + [0, cosd(xn)], zlvl * ones (1, ln + 1), i);
         text(xt, yt, zlvl, labels{i})];
 
--- a/scripts/plot/draw/private/__plt__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__plt__.m	Sun May 16 09:44:35 2021 +0200
@@ -24,7 +24,7 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {} __plt__ (@var{caller}, @var{hparent}, @var{varargin})
+## @deftypefn {} {} __plt__ (@var{caller}, @var{hp}, @var{varargin})
 ## Undocumented internal function.
 ## @end deftypefn
 
@@ -33,125 +33,124 @@
   persistent warned_callers = {};
   nargs = nargin - 2;
 
-  if (nargs > 0)
+  if (nargs < 1)
+    error ("__plt__: invalid number of arguments");
+  endif
 
-    k = 1;
+  k = 1;
 
-    x_set = false;
-    y_set = false;
-    property_set = false;
-    properties = {};
+  x_set = false;
+  y_set = false;
+  property_set = false;
+  properties = {};
+
+  ## Find any legend associated with this axes
+  try
+    hlegend = get (hp, "__legend_handle__");
+  catch
+    hlegend = [];
+  end_try_catch
 
-    ## Find any legend associated with this axes
-    try
-      hlegend = get (hp, "__legend_handle__");
-    catch
-      hlegend = [];
-    end_try_catch
+  setlgnd = false;
+  if (isempty (hlegend))
+    hlgnd = [];
+    tlgnd = {};
+  else
+    [hlgnd, tlgnd] = __getlegenddata__ (hlegend);
+  endif
+
+  ## Gather arguments, decode format, gather plot strings, and plot lines.
 
-    setlgnd = false;
-    if (isempty (hlegend))
-      hlgnd = [];
-      tlgnd = {};
+  retval = [];
+
+  while (nargs > 0 || x_set)
+
+    if (nargs == 0)
+      ## Force the last plot when input variables run out.
+      next_cell = {};
+      next_arg = {""};
     else
-      [hlgnd, tlgnd] = __getlegenddata__ (hlegend);
+      next_cell = varargin(k);
+      next_arg = varargin{k++};
     endif
 
-    ## Gather arguments, decode format, gather plot strings, and plot lines.
-
-    retval = [];
-
-    while (nargs > 0 || x_set)
-
-      if (nargs == 0)
-        ## Force the last plot when input variables run out.
-        next_cell = {};
-        next_arg = {""};
-      else
-        next_cell = varargin(k);
-        next_arg = varargin{k++};
+    if (isnumeric (next_arg) && ndims (next_arg) > 2
+        && any (size (next_arg) == 1))
+      next_arg = squeeze (next_arg);
+      if (! any (strcmp (caller, warned_callers)) && ndims (next_arg) < 3)
+        warning (["%s: N-d inputs have been squeezed to less than " ...
+                  "three dimensions"], caller);
+        warned_callers(end+1) = caller;
       endif
+    endif
+    if (isnumeric (next_arg) && ndims (next_arg) > 2)
+      error ("%s: plot arrays must have less than 2 dimensions", caller);
+    endif
 
-      if (isnumeric (next_arg) && ndims (next_arg) > 2
-          && any (size (next_arg) == 1))
-        next_arg = squeeze (next_arg);
-        if (! any (strcmp (caller, warned_callers)) && ndims (next_arg) < 3)
-          warning (["%s: N-d inputs have been squeezed to less than " ...
-                    "three dimensions"], caller);
-          warned_callers(end+1) = caller;
-        endif
-      endif
-      if (isnumeric (next_arg) && ndims (next_arg) > 2)
-        error ("%s: plot arrays must have less than 2 dimensions", caller);
-      endif
-
-      nargs -= 1;
+    nargs -= 1;
 
-      if (ischar (next_arg) || iscellstr (next_arg))
-        if (x_set)
-          [options, valid] = __pltopt__ (caller, next_arg, false);
-          if (! valid)
-            if (nargs == 0)
-              error ("%s: properties must appear followed by a value", caller);
-            endif
-            properties = [properties, [next_cell, varargin(k++)]];
-            nargs -= 1;
-            continue;
-          else
-            while (nargs > 0 && ischar (varargin{k}))
-              if (nargs < 2)
-                error ("%s: properties must appear followed by a value",
-                       caller);
-              endif
-              properties = [properties, varargin(k:k+1)];
-              k += 2;
-              nargs -= 2;
-            endwhile
+    if (ischar (next_arg) || iscellstr (next_arg))
+      if (x_set)
+        [options, valid] = __pltopt__ (caller, next_arg, false);
+        if (! valid)
+          if (nargs == 0)
+            error ("%s: properties must appear followed by a value", caller);
           endif
-          if (y_set)
-            htmp = __plt2__ (hp, x, y, options, properties);
-            [hlgnd, tlgnd, setlgnd] = ...
-              __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
-            properties = {};
-            retval = [retval; htmp];
-          else
-            htmp = __plt1__ (hp, x, options, properties);
-            [hlgnd, tlgnd, setlgnd] = ...
-               __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
-            properties = {};
-            retval = [retval; htmp];
-          endif
-          x_set = false;
-          y_set = false;
+          properties = [properties, [next_cell, varargin(k++)]];
+          nargs -= 1;
+          continue;
         else
-          error ("plot: no data to plot");
+          while (nargs > 0 && ischar (varargin{k}))
+            if (nargs < 2)
+              error ("%s: properties must appear followed by a value",
+                     caller);
+            endif
+            properties = [properties, varargin(k:k+1)];
+            k += 2;
+            nargs -= 2;
+          endwhile
         endif
-      elseif (x_set)
         if (y_set)
-          options = __pltopt__ (caller, {""});
           htmp = __plt2__ (hp, x, y, options, properties);
           [hlgnd, tlgnd, setlgnd] = ...
             __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
+          properties = {};
           retval = [retval; htmp];
-          x = next_arg;
-          y_set = false;
-          properties = {};
         else
-          y = next_arg;
-          y_set = true;
+          htmp = __plt1__ (hp, x, options, properties);
+          [hlgnd, tlgnd, setlgnd] = ...
+             __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
+          properties = {};
+          retval = [retval; htmp];
         endif
+        x_set = false;
+        y_set = false;
       else
+        error ("plot: no data to plot");
+      endif
+    elseif (x_set)
+      if (y_set)
+        options = __pltopt__ (caller, {""});
+        htmp = __plt2__ (hp, x, y, options, properties);
+        [hlgnd, tlgnd, setlgnd] = ...
+          __plt_key__ (htmp, options, hlgnd, tlgnd, setlgnd);
+        retval = [retval; htmp];
         x = next_arg;
-        x_set = true;
+        y_set = false;
+        properties = {};
+      else
+        y = next_arg;
+        y_set = true;
       endif
-
-    endwhile
+    else
+      x = next_arg;
+      x_set = true;
+    endif
 
-    if (setlgnd)
-      legend (gca (), hlgnd, tlgnd);
-    endif
-  else
-    error ("__plt__: invalid number of arguments");
+  endwhile
+
+  if (setlgnd)
+    legend (gca (), hlgnd, tlgnd);
   endif
 
 endfunction
@@ -365,6 +364,7 @@
   retval = __go_line__ (hp, "xdata", x, "ydata", y,
                         "color", color, "linestyle", linestyle,
                         "marker", marker, properties{:});
+
 endfunction
 
 function retval = __plt2sv__ (hp, x, y, options, properties = {})
--- a/scripts/plot/draw/private/__scatter__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__scatter__.m	Sun May 16 09:44:35 2021 +0200
@@ -24,13 +24,13 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{hg} =} __scatter__ (@dots{})
+## @deftypefn {} {@var{hs} =} __scatter__ (@dots{})
 ## Undocumented internal function.
 ## @end deftypefn
 
-function hg = __scatter__ (varargin)
+function hs = __scatter__ (varargin)
 
-  hax = varargin{1};  # We don't do anything with this.  Could remove it.
+  hax = varargin{1};
   nd  = varargin{2};
   fcn = varargin{3};
   x   = varargin{4}(:);
@@ -108,7 +108,7 @@
   x(idx) = [];
   y(idx) = [];
   if (nd == 2)
-    z = zeros (length (x), 0);
+    z = zeros (numel (x), 0);
   endif
   if (numel (s) > 1)
     s(idx) = [];
@@ -169,311 +169,58 @@
     endif
   endwhile
 
-  if (isempty (c))
-    c = __next_line_color__ ();
-  endif
+  if (strcmp ("gnuplot", graphics_toolkit ()))
+    ## Legacy code using patch for gnuplot toolkit
+    hs = __gnuplot_scatter__ (hax, fcn, x, y, z, c, s, marker, filled, newargs);
 
-  ## Must occur after __next_line_color__ in order to work correctly.
-  hg = hggroup ("__appdata__", struct ("__creator__", "__scatter__"));
-  newargs = __add_datasource__ (fcn, hg, {"x", "y", "z", "c", "size"},
-                                newargs{:});
-
-  addproperty ("xdata", hg, "data", x);
-  addproperty ("ydata", hg, "data", y);
-  addproperty ("zdata", hg, "data", z);
-  if (ischar (c))
-    ## For single explicit color, cdata is unused
-    addproperty ("cdata", hg, "data", []);
   else
-    addproperty ("cdata", hg, "data", c);
-  endif
-  addproperty ("sizedata", hg, "data", s);
-  addlistener (hg, "xdata", @update_data);
-  addlistener (hg, "ydata", @update_data);
-  addlistener (hg, "zdata", @update_data);
-  addlistener (hg, "cdata", @update_data);
-  addlistener (hg, "sizedata", @update_data);
-
-  one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
-  s = sqrt (s);  # size adjustment for visual compatibility w/Matlab
-
-  if (numel (x) <= 100)
-
-    ## For small number of points, we'll construct an object for each point.
-
-    if (numel (s) == 1)
-      s = repmat (s, numel (x), 1);
+    ## Use OpenGL rendering for "qt" and "fltk" graphics toolkits
+    if (isempty (x))
+      c = x;
+    endif
+    if (ischar (c))
+      c = str2rgb (c);
+    endif
+    if (isempty (c))
+      cdata_args = {};
+    else
+      cdata_args = {"cdata", c};
+    endif
+    if (filled)
+      filled_args = {"markeredgecolor", "none", "markerfacecolor", "flat"};
+    else
+      filled_args = {};
     endif
 
-    if (one_explicit_color)
-      for i = 1 : numel (x)
-        if (filled)
-          __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                        "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
-                        "faces", 1, "vertices", [x(i), y(i), z(i,:)],
-                        "marker", marker,  "markersize", s(i),
-                        "markeredgecolor", c, "markerfacecolor", c,
-                        "linestyle", "none");
-        else
-          __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                        "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
-                        "faces", 1, "vertices", [x(i), y(i), z(i,:)],
-                        "marker", marker,  "markersize", s(i),
-                        "markeredgecolor", c, "markerfacecolor", "none",
-                        "linestyle", "none");
-        endif
-      endfor
-    else
-      if (rows (c) == 1)
-        c = repmat (c, rows (x), 1);
-      endif
-      for i = 1 : numel (x)
-        if (filled)
-          __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                        "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
-                        "faces", 1, "vertices", [x(i), y(i), z(i,:)],
-                        "marker", marker, "markersize", s(i),
-                        "markeredgecolor", "none",
-                        "markerfacecolor", "flat",
-                        "cdata", c(i,:), "facevertexcdata", c(i,:),
-                        "linestyle", "none");
-        else
-          __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                        "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
-                        "faces", 1, "vertices", [x(i), y(i), z(i,:)],
-                        "marker", marker, "markersize", s(i),
-                        "markeredgecolor", "flat",
-                        "markerfacecolor", "none",
-                        "cdata", c(i,:), "facevertexcdata", c(i,:),
-                        "linestyle", "none");
-        endif
-      endfor
-    endif
-
-  else
-
-    ## For larger numbers of points, we use one single object.
-    vert = [x, y, z];
-    render_size_color (hg, vert, s, c, marker, filled, true);
-
-  endif
-
-  if (! ischar (c) && rows (c) > 1)
-    ax = get (hg, "parent");
-    clim = get (ax, "clim");
-    if (min (c(:)) < clim(1))
-      clim(1) = min (c(:));
-      set (ax, "clim", clim);
-    endif
-    if (max (c(:)) > clim(2))
-      set (ax, "clim", [clim(1), max(c(:))]);
-    endif
-  endif
-
-  addproperty ("linewidth", hg, "patchlinewidth", 0.5);
-  addproperty ("marker", hg, "patchmarker", marker);
-  if (filled)
-    addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "none");
-    if (one_explicit_color)
-      addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", c);
-    else
-      addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "flat");
-    endif
-  else
-    addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "none");
-    if (one_explicit_color)
-      addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", c);
-    else
-      addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "flat");
-    endif
-  endif
-  addlistener (hg, "linewidth", @update_props);
-  addlistener (hg, "marker", @update_props);
-  addlistener (hg, "markerfacecolor", @update_props);
-  addlistener (hg, "markeredgecolor", @update_props);
-
-  ## Matlab property, although Octave does not implement it.
-  addproperty ("hittestarea", hg, "radio", "on|{off}", "off");
-
-  if (! isempty (newargs))
-    set (hg, newargs{:});
+    hs = __go_scatter__ (hax, "xdata", x(:), "ydata", y(:), "zdata", z(:),
+                         cdata_args{:}, "sizedata", s(:), "marker", marker,
+                         filled_args{:}, newargs{:});
   endif
 
 endfunction
 
-function render_size_color (hg, vert, s, c, marker, filled, isflat)
+
+function rgb = str2rgb (str)
+  ## Convert a color code to the corresponding RGB values
+  rgb = [];
 
-  if (isscalar (s))
-    x = vert(:,1);
-    y = vert(:,2);
-    z = vert(:,3:end);
-    toolkit = get (ancestor (hg, "figure"), "__graphics_toolkit__");
-    ## Does gnuplot only support triangles with different vertex colors ?
-    ## FIXME: Verify gnuplot can only support one color.  If RGB triplets
-    ##        can be assigned to each vertex, then fix __gnuplot_draw_axes__.m
-    gnuplot_hack = (numel (x) > 1 && columns (c) == 3
-                    && strcmp (toolkit, "gnuplot"));
-    if (ischar (c) || ! isflat || gnuplot_hack)
-      if (filled)
-        ## "facecolor" and "edgecolor" must be set before any other properties
-        ## to skip co-planarity check (see bug #55751).
-        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                          "xdata", x, "ydata", y, "zdata", z,
-                          "faces", 1:numel (x), "vertices", vert,
-                          "marker", marker,
-                          "markeredgecolor", "none",
-                          "markerfacecolor", c(1,:),
-                          "markersize", s, "linestyle", "none");
-      else
-        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                          "xdata", x, "ydata", y, "zdata", z,
-                          "faces", 1:numel (x), "vertices", vert,
-                          "marker", marker,
-                          "markeredgecolor", c(1,:),
-                          "markerfacecolor", "none",
-                          "markersize", s, "linestyle", "none");
-      endif
-    else
-      if (filled)
-        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                          "xdata", x, "ydata", y, "zdata", z,
-                          "faces", 1:numel (x), "vertices", vert,
-                          "marker", marker, "markersize", s,
-                          "markeredgecolor", "none",
-                          "markerfacecolor", "flat",
-                          "cdata", c, "facevertexcdata", c,
-                          "linestyle", "none");
-      else
-        __go_patch__ (hg, "facecolor", "none", "edgecolor", "none",
-                          "xdata", x, "ydata", y, "zdata", z,
-                          "faces", 1:numel (x), "vertices", vert,
-                          "marker", marker, "markersize", s,
-                          "markeredgecolor", "flat",
-                          "markerfacecolor", "none",
-                          "cdata", c, "facevertexcdata", c,
-                          "linestyle", "none");
-      endif
-    endif
-  else
-    ## Round size to one decimal place.
-    [ss, ~, s_to_ss] = unique (ceil (s*10) / 10);
-    for i = 1:rows (ss)
-      idx = (i == s_to_ss);
-      render_size_color (hg, vert(idx,:), ss(i), c,
-                             marker, filled, isflat);
-    endfor
-  endif
-
-endfunction
-
-function update_props (h, d)
-
-  lw = get (h, "linewidth");
-  m  = get (h, "marker");
-  fc = get (h, "markerfacecolor");
-  ec = get (h, "markeredgecolor");
-  kids = get (h, "children");
-
-  set (kids, "linewidth", lw, "marker", m,
-             "markerfacecolor", fc, "markeredgecolor", ec);
+  switch (str)
+    case 'b'
+      rgb = [0, 0, 1];
+    case 'k'
+      rgb = [0, 0, 0];
+    case 'r'
+      rgb = [1, 0, 0];
+    case 'g'
+      rgb = [0, 1, 0];
+    case 'y'
+      rgb = [1, 1, 0];
+    case 'm'
+      rgb = [1, 0, 1];
+    case 'c'
+      rgb = [0, 1, 1];
+    case 'w'
+      rgb = [1, 1, 1];
+endswitch
 
 endfunction
-
-## FIXME: This callback routine doesn't handle the case where N > 100.
-function update_data (h, d)
-
-  x = get (h, "xdata");
-  y = get (h, "ydata");
-  z = get (h, "zdata");
-  if (numel (x) > 100)
-    error ("scatter: cannot update data with more than 100 points.  Call scatter (x, y, ...) with new data instead.");
-  endif
-  c = get (h, "cdata");
-  one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
-  if (! one_explicit_color)
-    if (rows (c) == 1)
-      c = repmat (c, numel (x), 1);
-    endif
-  endif
-  filled = ! strcmp (get (h, "markerfacecolor"), "none");
-  s = get (h, "sizedata");
-  ## Size adjustment for visual compatibility with Matlab.
-  s = sqrt (s);
-  if (numel (s) == 1)
-    s = repmat (s, numel (x), 1);
-  endif
-  hlist = get (h, "children");
-
-  if (one_explicit_color)
-    if (filled)
-      if (isempty (z))
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", c, "markerfacecolor", c);
-
-        endfor
-      else
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i), z(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", c, "markerfacecolor", c);
-        endfor
-      endif
-    else
-      if (isempty (z))
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", c, "markerfacecolor", "none");
-
-        endfor
-      else
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i), z(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", c, "markerfacecolor", "none");
-        endfor
-      endif
-    endif
-  else
-    if (filled)
-      if (isempty (z))
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", "none", "markerfacecolor", "flat",
-                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
-                         "facevertexcdata", c(i,:));
-        endfor
-      else
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i), z(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", "none", "markerfacecolor", "flat",
-                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
-                         "facevertexcdata", c(i,:));
-        endfor
-      endif
-    else
-      if (isempty (z))
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", "flat", "markerfacecolor", "none",
-                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
-                         "facevertexcdata", c(i,:));
-        endfor
-      else
-        for i = 1 : length (hlist)
-          set (hlist(i), "vertices", [x(i), y(i), z(i)],
-                         "markersize", s(i),
-                         "markeredgecolor", "flat", "markerfacecolor", "none",
-                         "cdata", reshape (c(i,:),[1, size(c)(2:end)]),
-                         "facevertexcdata", c(i,:));
-        endfor
-      endif
-    endif
-  endif
-
-endfunction
--- a/scripts/plot/draw/private/__unite_shared_vertices__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/private/__unite_shared_vertices__.m	Sun May 16 09:44:35 2021 +0200
@@ -55,7 +55,7 @@
   [J, idx] = sort (J);
   j(idx) = 1:length (idx);
   vertices = vertices(idx,:);
-  if any (nan_vertices)
+  if (any (nan_vertices))
     j(end+1) = length (idx) + 1;
     vertices(end+1,:) = NaN;
     lut(nan_vertices) = rows (vertices);
--- a/scripts/plot/draw/rectangle.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/rectangle.m	Sun May 16 09:44:35 2021 +0200
@@ -107,7 +107,7 @@
         pos = varargin{iarg+1};
         varargin(iarg:iarg+1) = [];
         if (! isvector (pos) || numel (pos) != 4)
-          error ("rectangle: position must be a 4 element vector");
+          error ("rectangle: position must be a 4-element vector");
         endif
       elseif (strcmpi (arg, "curvature"))
         curv2 = varargin{iarg+1};
--- a/scripts/plot/draw/reducepatch.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/reducepatch.m	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,8 @@
 ## The input patch can be represented by a structure @var{fv} with the
 ## fields @code{faces} and @code{vertices}, by two matrices @var{faces} and
 ## @var{vertices} (see, e.g., the result of @code{isosurface}), or by a
-## handle to a patch object @var{patch_handle} (@pxref{XREFpatch,,patch}).
+## handle to a patch object @var{patch_handle}
+## (@pxref{XREFpatch,,@code{patch}}).
 ##
 ## The number of faces and vertices in the patch is reduced by iteratively
 ## collapsing the shortest edge of the patch to its midpoint (as discussed,
@@ -363,7 +364,7 @@
 %! patch (fv, "FaceColor", "g");
 %! view (3);  axis equal;
 %! title ("Sphere with all faces");
-%! ax2 = subplot(1, 2, 2);
+%! ax2 = subplot (1, 2, 2);
 %! patch (reducepatch (fv, 72), "FaceColor", "g");
 %! view (3);  axis equal;
 %! title ("Sphere with reduced number of faces");
@@ -438,8 +439,8 @@
 %! assert (size (vertices_reduced, 2), 3);
 
 ## test for each error
-%!error reducepatch ()
-%!error reducepatch (fv, faces, vertices, .5, "f", "v")
+%!error <Invalid call> reducepatch ()
+%!error <Invalid call> reducepatch (fv, faces, vertices, .5, "f", "v")
 %!error <reducepatch: parameter 'foo' not supported>
 %! fv_reduced = reducepatch (faces, vertices, .7, "foo");
 %!error <struct FV must contain the fields 'vertices' and 'faces'>
--- a/scripts/plot/draw/reducevolume.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/reducevolume.m	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,8 @@
 ## Optionally, @var{x}, @var{y}, and @var{z} can be supplied to represent the
 ## set of coordinates of @var{v}.  They can either be matrices of the same size
 ## as @var{v} or vectors with sizes according to the dimensions of @var{v}, in
-## which case they are expanded to matrices (@pxref{XREFmeshgrid,,meshgrid}).
+## which case they are expanded to matrices
+## (@pxref{XREFmeshgrid,,@code{meshgrid}}).
 ##
 ## If @code{reducevolume} is called with two arguments then @var{x}, @var{y},
 ## and @var{z} are assumed to match the respective indices of @var{v}.
@@ -263,9 +264,9 @@
 
 ## Test for each error
 %!test
-%!error reducevolume ()
-%!error reducevolume (1)
-%!error reducevolume (1,2,3,4,5,6)
+%!error <Invalid call> reducevolume ()
+%!error <Invalid call> reducevolume (1)
+%!error <Invalid call> reducevolume (1,2,3,4,5,6)
 %!error <incorrect number of arguments> reducevolume (1, 2, 3)
 %!error <R must be a scalar or a vector of length 3> reducevolume (v, [])
 %!error <R must be a scalar or a vector of length 3> reducevolume (v, [1 2])
--- a/scripts/plot/draw/ribbon.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/ribbon.m	Sun May 16 09:44:35 2021 +0200
@@ -60,7 +60,7 @@
     if (isvector (y))
       y = y(:);
     endif
-    x = 1:rows(y);
+    x = 1:rows (y);
     width = 0.75;
   elseif (nargin == 2)
     x = varargin{1};
@@ -122,6 +122,6 @@
 %! colormap ("default");
 %! [x, y, z] = sombrero ();
 %! ribbon (y, z);
-%! title ("ribbon() plot of sombrero()");
+%! title ("ribbon() plot of sombrero ()");
 
 %!FIXME: Could have some input validation tests here
--- a/scripts/plot/draw/rose.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/rose.m	Sun May 16 09:44:35 2021 +0200
@@ -72,7 +72,7 @@
 
   [hax, varargin, nargin] = __plt_get_axis_arg__ ("rose", varargin{:});
 
-  if (nargin < 1)
+  if (nargin < 1 || nargin > 2)
     print_usage ();
   endif
 
@@ -166,7 +166,8 @@
 %! title ("rose() angular histogram plot with specified bins");
 
 ## Test input validation
-%!error rose ()
+%!error <Invalid call> rose ()
+%!error <Invalid call> rose (1,2,3)
 %!warning <bin sizes .= pi will not plot correctly>
 %! [th, r] = rose ([1 2 2 4 4 4], 2);
 %!warning <bin 1 and bin 3 are not centered>
--- a/scripts/plot/draw/scatter.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/scatter.m	Sun May 16 09:44:35 2021 +0200
@@ -53,10 +53,6 @@
 ## If no marker is specified it defaults to @qcode{"o"} or circles.
 ## If the argument @qcode{"filled"} is given then the markers are filled.
 ##
-## Additional property/value pairs are passed directly to the underlying
-## patch object.  The full list of properties is documented at
-## @ref{Patch Properties}.
-##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
 ##
@@ -73,6 +69,8 @@
 ## @end group
 ## @end example
 ##
+## Programming Note: The full list of properties is documented at
+## @ref{Scatter Properties}.
 ## @seealso{scatter3, patch, plot}
 ## @end deftypefn
 
@@ -220,3 +218,20 @@
 %!     title (str);
 %!   endfor
 %! endfor
+
+
+%!testif ; ! strcmp (graphics_toolkit (), "gnuplot")
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   hs = scatter ([], []);
+%!   assert (get (hs, "type"), "scatter");
+%!   assert (isempty (get (hs, "xdata")));
+%!   assert (isempty (get (hs, "ydata")));
+%!   assert (isempty (get (hs, "zdata")));
+%!   assert (get (hs, "cdata"), [0, 0.4470, 0.7410]);
+%!   assert (get (hs, "cdatamode"), "auto");
+%!   assert (get (hs, "sizedata"), 36);
+%!   assert (get (hs, "linewidth"), 0.5);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
--- a/scripts/plot/draw/scatter3.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/scatter3.m	Sun May 16 09:44:35 2021 +0200
@@ -53,14 +53,10 @@
 ## If no marker is specified it defaults to @qcode{"o"} or circles.
 ## If the argument @qcode{"filled"} is given then the markers are filled.
 ##
-## Additional property/value pairs are passed directly to the underlying
-## patch object.  The full list of properties is documented at
-## @ref{Patch Properties}.
-##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
 ##
-## The optional return value @var{h} is a graphics handle to the hggroup
+## The optional return value @var{h} is a graphics handle to the scatter
 ## object representing the points.
 ##
 ## @example
@@ -70,6 +66,8 @@
 ## @end group
 ## @end example
 ##
+## Programming Note: The full list of properties is documented at
+## @ref{Scatter Properties}.
 ## @seealso{scatter, patch, plot}
 ## @end deftypefn
 
--- a/scripts/plot/draw/semilogx.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/semilogx.m	Sun May 16 09:44:35 2021 +0200
@@ -104,12 +104,12 @@
 %!
 %! subplot (1,2,1);
 %!  semilogx (x, y);
-%!  set (gca, "xdir", "reverse", "activepositionproperty", "outerposition");
+%!  set (gca, "xdir", "reverse", "positionconstraint", "outerposition");
 %!  title ({"semilogx (x, y)", "xdir = reversed"});
 %!
 %! subplot (1,2,2);
 %!  semilogx (-x, y);
-%!  set (gca, "xdir", "reverse", "activepositionproperty", "outerposition");
+%!  set (gca, "xdir", "reverse", "positionconstraint", "outerposition");
 %!  title ({"semilogx (-x, y)", "xdir = reversed"});
 
 %!test
--- a/scripts/plot/draw/semilogxerr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/semilogxerr.m	Sun May 16 09:44:35 2021 +0200
@@ -47,8 +47,8 @@
 ## @noindent
 ## which produces a semi-logarithmic plot of @var{y} versus @var{x}
 ## with errors in the @var{y}-scale defined by @var{ey} and the plot
-## format defined by @var{fmt}.  @xref{XREFerrorbar,,errorbar}, for available
-## formats and additional information.
+## format defined by @var{fmt}.  @xref{XREFerrorbar,,@code{errorbar}}, for
+## available formats and additional information.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
--- a/scripts/plot/draw/semilogy.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/semilogy.m	Sun May 16 09:44:35 2021 +0200
@@ -104,12 +104,12 @@
 %!
 %! subplot (2,1,1);
 %!  semilogy (x, y);
-%!  set (gca, "ydir", "reverse", "activepositionproperty", "outerposition");
+%!  set (gca, "ydir", "reverse", "positionconstraint", "outerposition");
 %!  title ({"semilogy (x, y)", "ydir = reversed"});
 %!
 %! subplot (2,1,2);
 %!  semilogy (x, -y);
-%!  set (gca, "ydir", "reverse", "activepositionproperty", "outerposition");
+%!  set (gca, "ydir", "reverse", "positionconstraint", "outerposition");
 %!  title ({"semilogy (x, -y)", "ydir = reversed"});
 
 %!test
--- a/scripts/plot/draw/semilogyerr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/semilogyerr.m	Sun May 16 09:44:35 2021 +0200
@@ -47,8 +47,8 @@
 ## @noindent
 ## which produces a semi-logarithmic plot of @var{y} versus @var{x}
 ## with errors in the @var{y}-scale defined by @var{ey} and the plot
-## format defined by @var{fmt}.  @xref{XREFerrorbar,,errorbar}, for available
-## formats and additional information.
+## format defined by @var{fmt}.  @xref{XREFerrorbar,,@code{errorbar}}, for
+## available formats and additional information.
 ##
 ## If the first argument @var{hax} is an axes handle, then plot into this axes,
 ## rather than the current axes returned by @code{gca}.
--- a/scripts/plot/draw/shrinkfaces.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/shrinkfaces.m	Sun May 16 09:44:35 2021 +0200
@@ -73,7 +73,7 @@
 
 function [nf, nv] = shrinkfaces (varargin)
 
-  if (nargin < 1 || nargin > 3 || nargout > 2)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
@@ -215,7 +215,7 @@
 %! axis auto;   # Kludge required for Octave
 %! axis equal;
 %! view (115, 30);
-%! drawnow;
+%! drawnow ();
 %! shrinkfaces (p, 0.6);
 %! title ("shrinkfaces() on 3-D complex shapes");
 
@@ -231,8 +231,8 @@
 %!assert (norm (nfv2.vertices - vertices), 0, 2*eps)
 
 ## Test input validation
-%!error shrinkfaces ()
-%!error shrinkfaces (1,2,3,4)
+%!error <Invalid call> shrinkfaces ()
+%!error <Invalid call> shrinkfaces (1,2,3,4)
 %!error [a,b,c] = shrinkfaces (1)
 %!error <scale factor must be a positive scalar> shrinkfaces (nfv, ones (2))
 %!error <scale factor must be a positive scalar> shrinkfaces (nfv, 0)
--- a/scripts/plot/draw/smooth3.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/smooth3.m	Sun May 16 09:44:35 2021 +0200
@@ -65,7 +65,7 @@
 
 function smoothed_data = smooth3 (data, method = "box", sz = 3, std_dev = 0.65)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -257,8 +257,7 @@
 %! assert (size_equal (a, b), true);
 
 ## Test input validation
-%!error smooth3 ()
-%!error smooth3 (1,2,3,4,5)
+%!error <Invalid call> smooth3 ()
 %!error <DATA must be a 3-D numeric matrix> smooth3 (cell (2,2,2))
 %!error <DATA must be a 3-D numeric matrix> smooth3 (1)
 %!error <METHOD must be a string> smooth3 (ones (2,2,2), {3})
--- a/scripts/plot/draw/sombrero.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/sombrero.m	Sun May 16 09:44:35 2021 +0200
@@ -56,9 +56,7 @@
 
 function [x, y, z] = sombrero (n = 41)
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (n <= 1)
+  if (n <= 1)
     error ("sombrero: number of grid lines N must be greater than 1");
   endif
 
--- a/scripts/plot/draw/stairs.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/stairs.m	Sun May 16 09:44:35 2021 +0200
@@ -329,9 +329,9 @@
 ## Invisible figure used for tests
 %!shared hf, hax
 %! hf = figure ("visible", "off");
-%! hax = axes;
+%! hax = axes ();
 
-%!error stairs ()
+%!error <Invalid call> stairs ()
 %!error <Y must be a numeric 2-D vector> stairs (hax, {1})
 %!error <Y must be a numeric 2-D vector> stairs (ones (2,2,2))
 %!error <X and Y must be numeric 2-D vector> stairs ({1}, 1)
--- a/scripts/plot/draw/stem.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/stem.m	Sun May 16 09:44:35 2021 +0200
@@ -225,7 +225,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error stem ()
+%!error <Invalid call> stem ()
 %!error <can not define Z for 2-D stem plot> stem (1,2,3)
 %!error <Y must be a vector or 2-D array> stem (ones (2,2,2))
 %!error <X and Y must be numeric> stem ({1})
--- a/scripts/plot/draw/stem3.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/stem3.m	Sun May 16 09:44:35 2021 +0200
@@ -90,7 +90,7 @@
 %! stem3 (cos (theta), sin (theta), theta);
 %! title ("stem3() plot");
 
-%!error stem3 ()
+%!error <Invalid call> stem3 ()
 %!error <must define X, Y, and Z> stem3 (1,2)
 %!error <X, Y, and Z must be numeric> stem3 ({1}, 1, 1)
 %!error <X, Y, and Z must be numeric> stem3 (1, {1}, 1)
--- a/scripts/plot/draw/stemleaf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/stemleaf.m	Sun May 16 09:44:35 2021 +0200
@@ -130,7 +130,7 @@
   ## other options for the kinds of plots described by Tukey could be
   ## provided.  This may best be left to users.
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -585,8 +585,7 @@
 %! assert (r, rexp);
 
 ## Test input validation
-%!error stemleaf ()
-%!error stemleaf (1, 2, 3, 4)
+%!error <Invalid call> stemleaf ()
 %!error <X must be a vector> stemleaf (ones (2,2), "")
 %!warning <X truncated to integer values> tmp = stemleaf ([0 0.5 1],"");
 %!error <X must be a numeric vector> stemleaf ("Hello World", "data")
--- a/scripts/plot/draw/stream2.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/stream2.m	Sun May 16 09:44:35 2021 +0200
@@ -82,8 +82,6 @@
 
   options = [];
   switch (numel (varargin))
-    case 0
-      print_usage ();
     case {4,5}
       if (numel (varargin) == 4)
         [u, v, spx, spy] = varargin{:};
@@ -97,7 +95,7 @@
     case 7
       [x, y, u, v, spx, spy, options] = varargin{:};
     otherwise
-      error ("stream2: invalid number of inputs");
+      print_usage ();
   endswitch
 
   stepsize = 0.1;
@@ -110,7 +108,7 @@
         stepsize = options(1);
         max_vertices = options(2);
       otherwise
-        error ("stream2: invalid number of OPTIONS elements");
+        error ("stream2: OPTIONS must be a 1- or 2-element vector");
     endswitch
 
     if (! isreal (stepsize) || stepsize == 0)
@@ -207,11 +205,11 @@
 %! assert (numel (xy{:}), 10);
 
 ## Test input validation
-%!error stream2 ()
-%!error <invalid number of inputs> stream2 (1)
-%!error <invalid number of inputs> stream2 (1,2)
-%!error <invalid number of inputs> stream2 (1,2,3)
-%!error <invalid number of OPTIONS> stream2 (1,2,3,4, [1,2,3])
+%!error <Invalid call> stream2 ()
+%!error <Invalid call> stream2 (1)
+%!error <Invalid call> stream2 (1,2)
+%!error <Invalid call> stream2 (1,2,3)
+%!error <OPTIONS must be a 1- or 2-element> stream2 (1,2,3,4, [1,2,3])
 %!error <STEPSIZE must be a real scalar != 0> stream2 (1,2,3,4, [1i])
 %!error <STEPSIZE must be a real scalar != 0> stream2 (1,2,3,4, [0])
 %!error <MAX_VERTICES must be an integer> stream2 (1,2,3,4, [1, 1i])
--- a/scripts/plot/draw/stream3.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/stream3.m	Sun May 16 09:44:35 2021 +0200
@@ -58,7 +58,7 @@
 ## @end group
 ## @end example
 ##
-## @seealso{stream2, streamline, streamtube, ostreamtube}
+## @seealso{stream2, streamline, streamribbon, streamtube, ostreamtube}
 ## @end deftypefn
 
 ## References:
@@ -83,8 +83,6 @@
 
   options = [];
   switch (numel (varargin))
-    case 0
-      print_usage ();
     case {6,7}
       if (numel (varargin) == 6)
         [u, v, w, spx, spy, spz] = varargin{:};
@@ -98,7 +96,7 @@
     case 10
       [x, y, z, u, v, w, spx, spy, spz, options] = varargin{:};
     otherwise
-      error ("stream3: invalid number of inputs");
+      print_usage ();
   endswitch
 
   stepsize = 0.1;
@@ -111,7 +109,7 @@
         stepsize = options(1);
         max_vertices = options(2);
       otherwise
-        error ("stream3: invalid number of OPTIONS elements");
+        error ("stream3: OPTIONS must be a 1- or 2-element vector");
     endswitch
 
     if (! isreal (stepsize) || stepsize == 0)
@@ -231,14 +229,14 @@
 %! assert (numel (xyz{:}), 15);
 
 ## Test input validation
-%!error stream3 ()
-%!error <invalid number of inputs> stream3 (1)
-%!error <invalid number of inputs> stream3 (1,2)
-%!error <invalid number of inputs> stream3 (1,2,3)
-%!error <invalid number of inputs> stream3 (1,2,3,4)
-%!error <invalid number of inputs> stream3 (1,2,3,4,5)
-%!error <invalid number of inputs> stream3 (1,2,3,4,5,6,7,8)
-%!error <invalid number of OPTIONS> stream3 (1,2,3,4,5,6, [1,2,3])
+%!error <Invalid call> stream3 ()
+%!error <Invalid call> stream3 (1)
+%!error <Invalid call> stream3 (1,2)
+%!error <Invalid call> stream3 (1,2,3)
+%!error <Invalid call> stream3 (1,2,3,4)
+%!error <Invalid call> stream3 (1,2,3,4,5)
+%!error <Invalid call> stream3 (1,2,3,4,5,6,7,8)
+%!error <OPTIONS must be a 1- or 2-element> stream3 (1,2,3,4,5,6, [1,2,3])
 %!error <STEPSIZE must be a real scalar != 0> stream3 (1,2,3,4,5,6, [1i])
 %!error <STEPSIZE must be a real scalar != 0> stream3 (1,2,3,4,5,6, [0])
 %!error <MAX_VERTICES must be an integer> stream3 (1,2,3,4,5,6, [1, 1i])
--- a/scripts/plot/draw/streamline.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/streamline.m	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
 ## @end group
 ## @end example
 ##
-## @seealso{stream2, stream3, streamtube, ostreamtube}
+## @seealso{stream2, stream3, streamribbon, streamtube, ostreamtube}
 ## @end deftypefn
 
 function h = streamline (varargin)
@@ -154,7 +154,7 @@
 %! sy = 0.0;
 %! sz = 0.0;
 %! plot3 (sx, sy, sz, ".r", "markersize", 15);
-%! t = linspace (0, 12 * 2 * pi(), 500);
+%! t = linspace (0, 12 * 2 * pi (), 500);
 %! tx = exp (-a * t).*cos (t);
 %! ty = exp (-a * t).*sin (t);
 %! tz = - b * t;
@@ -167,7 +167,7 @@
 %! axis equal tight;
 
 ## Test input validation
-%!error streamline ()
+%!error <Invalid call> streamline ()
 %!error <Invalid call to streamline>
 %! hf = figure ("visible", "off");
 %! unwind_protect
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/streamribbon.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,443 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {} streamribbon (@var{x}, @var{y}, @var{z}, @var{u}, @var{v}, @var{w}, @var{sx}, @var{sy}, @var{sz})
+## @deftypefnx {} {} streamribbon (@var{u}, @var{v}, @var{w}, @var{sx}, @var{sy}, @var{sz})
+## @deftypefnx {} {} streamribbon (@var{xyz}, @var{x}, @var{y}, @var{z}, @var{anlr_spd}, @var{lin_spd})
+## @deftypefnx {} {} streamribbon (@var{xyz}, @var{anlr_spd}, @var{lin_spd})
+## @deftypefnx {} {} streamribbon (@var{xyz}, @var{anlr_rot})
+## @deftypefnx {} {} streamribbon (@dots{}, @var{width})
+## @deftypefnx {} {} streamribbon (@var{hax}, @dots{})
+## @deftypefnx {} {@var{h} =} streamribbon (@dots{})
+## Calculate and display streamribbons.
+##
+## The streamribbon is constructed by rotating a normal vector around a
+## streamline according to the angular rotation of the vector field.
+##
+## The vector field is given by @code{[@var{u}, @var{v}, @var{w}]} and is
+## defined over a rectangular grid given by @code{[@var{x}, @var{y}, @var{z}]}.
+## The streamribbons start at the seed points
+## @code{[@var{sx}, @var{sy}, @var{sz}]}.
+##
+## @code{streamribbon} can be called with a cell array that contains
+## pre-computed streamline data.  To do this, @var{xyz} must be created with
+## the @code{stream3} function.  @var{lin_spd} is the linear speed of the
+## vector field and can be calculated from @code{[@var{u}, @var{v}, @var{w}]}
+## by the square root of the sum of the squares.  The angular speed
+## @var{anlr_spd} is the projection of the angular velocity onto the velocity
+## of the normalized vector field and can be calculated with the @code{curl}
+## command.  This option is useful if you need to alter the integrator step
+## size or the maximum number of streamline vertices.
+##
+## Alternatively, ribbons can be created from an array of vertices @var{xyz} of
+## a path curve.  @var{anlr_rot} contains the angles of rotation around the
+## edges between adjacent vertices of the path curve.
+##
+## The input parameter @var{width} sets the width of the streamribbons.
+##
+## Streamribbons are colored according to the total angle of rotation along the
+## ribbon.
+##
+## If the first argument @var{hax} is an axes handle, then plot into this axes,
+## rather than the current axes returned by @code{gca}.
+##
+## The optional return value @var{h} is a graphics handle to the plot objects
+## created for each streamribbon.
+##
+## Example:
+##
+## @example
+## @group
+## [x, y, z] = meshgrid (0:0.2:4, -1:0.2:1, -1:0.2:1);
+## u = - x + 10;
+## v = 10 * z.*x;
+## w = - 10 * y.*x;
+## streamribbon (x, y, z, u, v, w, [0, 0], [0, 0.6], [0, 0]);
+## view (3);
+## @end group
+## @end example
+##
+## @seealso{streamline, stream3, streamtube, ostreamtube}
+##
+## @end deftypefn
+
+## References:
+##
+## @inproceedings{
+##    title = {Feature Detection from Vector Quantities in a Numerically Simulated Hypersonic Flow Field in Combination with Experimental Flow Visualization},
+##    author = {Pagendarm, Hans-Georg and Walter, Birgit},
+##    year = {1994},
+##    publisher = {IEEE Computer Society Press},
+##    booktitle = {Proceedings of the Conference on Visualization ’94},
+##    pages = {117–123},
+## }
+##
+## @article{
+##    title = {Efficient streamline, streamribbon, and streamtube constructions on unstructured grids},
+##    author = {Ueng, Shyh-Kuang and Sikorski, C. and Ma, Kwan-Liu},
+##    year = {1996},
+##    month = {June},
+##    publisher = {IEEE Transactions on Visualization and Computer Graphics},
+## }
+##
+## @inproceedings{
+##    title = {Visualization of 3-D vector fields - Variations on a stream},
+##    author = {Dave Darmofal and Robert Haimes},
+##    year = {1992}
+## }
+##
+## @techreport{
+##    title = {Parallel Transport Approach to Curve Framing},
+##    author = {Andrew J. Hanson and Hui Ma},
+##    year = {1995}
+## }
+##
+## @article{
+##    title = {There is More than One Way to Frame a Curve},
+##    author = {Bishop, Richard},
+##    year = {1975},
+##    month = {03},
+##    volume = {82},
+##    publisher = {The American Mathematical Monthly}
+## }
+
+function h = streamribbon (varargin)
+
+  [hax, varargin, nargin] = __plt_get_axis_arg__ ("streamribbon", varargin{:});
+
+  width = [];
+  xyz = [];
+  anlr_spd = [];
+  lin_spd = [];
+  anlr_rot = [];
+  switch (nargin)
+    case 2
+      [xyz, anlr_rot] = varargin{:};
+    case 3
+      if (numel (varargin{3}) == 1)
+        [xyz, anlr_rot, width] = varargin{:};
+      else
+        [xyz, anlr_spd, lin_spd] = varargin{:};
+        [m, n, p] = size (anlr_spd);
+        [x, y, z] = meshgrid (1:n, 1:m, 1:p);
+      endif
+    case 4
+      [xyz, anlr_spd, lin_spd, width] = varargin{:};
+      [m, n, p] = size (anlr_spd);
+      [x, y, z] = meshgrid (1:n, 1:m, 1:p);
+    case 6
+      if (iscell (varargin{1}))
+        [xyz, x, y, z, anlr_spd, lin_spd] = varargin{:};
+      else
+        [u, v, w, spx, spy, spz] = varargin{:};
+        [m, n, p] = size (u);
+        [x, y, z] = meshgrid (1:n, 1:m, 1:p);
+      endif
+    case 7
+      if (iscell (varargin{1}))
+        [xyz, x, y, z, anlr_spd, lin_spd, width] = varargin{:};
+      else
+        [u, v, w, spx, spy, spz, width] = varargin{:};
+        [m, n, p] = size (u);
+        [x, y, z] = meshgrid (1:n, 1:m, 1:p);
+      endif
+    case 9
+      [x, y, z, u, v, w, spx, spy, spz] = varargin{:};
+    case 10
+      [x, y, z, u, v, w, spx, spy, spz, width] = varargin{:};
+    otherwise
+      print_usage ();
+  endswitch
+
+  if (isempty (xyz))
+    xyz = stream3 (x, y, z, u, v, w, spx, spy, spz);
+    anlr_spd = curl (x, y, z, u, v, w);
+    lin_spd = sqrt (u.*u + v.*v + w.*w);
+  endif
+
+  ## Derive scale factor from the bounding box diagonal
+  if (isempty (width))
+    mxx = mnx = mxy = mny = mxz = mnz = [];
+    j = 1;
+    for i = 1 : length (xyz)
+      sl = xyz{i};
+      if (! isempty (sl))
+        slx = sl(:,1); sly = sl(:,2); slz = sl(:,3);
+        mxx(j) = max (slx); mnx(j) = min (slx);
+        mxy(j) = max (sly); mny(j) = min (sly);
+        mxz(j) = max (slz); mnz(j) = min (slz);
+        j += 1;
+      endif
+    endfor
+    dx = max (mxx) - min (mnx);
+    dy = max (mxy) - min (mny);
+    dz = max (mxz) - min (mnz);
+    width = sqrt (dx*dx + dy*dy + dz*dz) / 25;
+  elseif (! isreal (width) || width <= 0)
+    error ("streamribbon: WIDTH must be a real scalar > 0");
+  endif
+
+  if (! isempty (anlr_rot))
+    for i = 1 : length (xyz)
+      if (rows (anlr_rot{i}) != rows (xyz{i}))
+        error ("streamribbon: ANLR_ROT must have same length as XYZ");
+      endif
+    endfor
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  else
+    hax = hax(1);
+  endif
+
+  ## Angular speed of a paddle wheel spinning around a streamline in a fluid
+  ## flow "V":
+  ## dtheta/dt = 0.5 * <curl(V), V/norm(V)>
+  ##
+  ## Integration along a streamline segment with the length "h" yields the
+  ## rotation angle:
+  ## theta = 0.25 * h * <curl(V), V(0)/norm(V(0))^2) + V(h)/norm(V(h))^2)>
+  ##
+  ## Alternative approach using the curl angular speed "c = curl()":
+  ## theta = 0.5 * h * (c(0)/norm(V(0)) + c(h)/norm(V(h)))
+  ##
+  ## Hints:
+  ## i. ) For integration use trapezoidal rule
+  ## ii.) "V" can be assumend to be piecewise linear and curl(V) to be
+  ##      piecewise constant because of the used linear interpolation
+
+  h = [];
+  for i = 1 : length (xyz)
+    sl = xyz{i};
+    num_vertices = rows (sl);
+    if (! isempty (sl) && num_vertices > 1)
+      if (isempty (anlr_rot))
+        ## Plot from vector field
+        ## Interpolate onto streamline vertices
+        [lin_spd_sl, anlr_spd_sl, max_vertices] = ...
+                                  interp_sl (x, y, z, lin_spd, anlr_spd, sl);
+        if (max_vertices > 1)
+          ## Euclidean distance between two adjacent vertices
+          stepsize = vecnorm (diff (sl(1:max_vertices, :)), 2, 2);
+          ## Angular rotation around edges between two adjacent sl-vertices
+          ## Note: Potential "division by zero" is checked in interp_sl()
+          anlr_rot_sl = 0.5 * stepsize.*(anlr_spd_sl(1:max_vertices - 1)./ ...
+                                         lin_spd_sl(1:max_vertices - 1) + ...
+                                         anlr_spd_sl(2:max_vertices)./ ...
+                                         lin_spd_sl(2:max_vertices));
+
+          htmp = plotribbon (hax, sl, anlr_rot_sl, max_vertices, 0.5 * width);
+          h = [h; htmp];
+        endif
+      else
+          ## Plot from vertice array
+          anlr_rot_sl = anlr_rot{i};
+
+          htmp = plotribbon (hax, sl, anlr_rot_sl, num_vertices, 0.5 * width);
+          h = [h; htmp];
+      endif
+    endif
+  endfor
+
+endfunction
+
+function h = plotribbon (hax, sl, anlr_rot_sl, max_vertices, width2)
+
+  total_angle = cumsum (anlr_rot_sl);
+  total_angle = [0; total_angle];
+
+  ## 1st streamline segment
+  X0 = sl(1,:);
+  X1 = sl(2,:);
+  R = X1 - X0;
+  RE = R / norm (R);
+
+  ## Initial vector KE which is to be transported along the vertice array
+  KE = get_normal2 (RE);
+  XS10 = - width2 * KE + X0;
+  XS20 = width2 * KE + X0;
+
+  ## Apply angular rotation
+  cp = cos (anlr_rot_sl(1));
+  sp = sin (anlr_rot_sl(1));
+  KE = rotation (KE, RE, cp, sp).';
+
+  XS1 = - width2 * KE + X1;
+  XS2 = width2 * KE + X1;
+
+  px = zeros (2, max_vertices);
+  py = zeros (2, max_vertices);
+  pz = zeros (2, max_vertices);
+  pc = zeros (2, max_vertices);
+
+  px(:,1) = [XS10(1); XS20(1)];
+  py(:,1) = [XS10(2); XS20(2)];
+  pz(:,1) = [XS10(3); XS20(3)];
+  pc(:,1) = total_angle(1) * [1; 1];
+
+  px(:,2) = [XS1(1); XS2(1)];
+  py(:,2) = [XS1(2); XS2(2)];
+  pz(:,2) = [XS1(3); XS2(3)];
+  pc(:,2) = total_angle(2) * [1; 1];
+
+  for i = 3 : max_vertices
+
+    ## Next streamline segment
+    X0 = X1;
+    X1 = sl(i,:);
+    R = X1 - X0;
+    RE = R / norm (R);
+
+    ## Project KE onto RE and get the difference in order to transport
+    ## the normal vector KE along the vertex array
+    Kp = KE - RE * dot (KE, RE);
+    KE = Kp / norm (Kp);
+
+    ## Apply angular rotation to KE
+    cp = cos (anlr_rot_sl(i - 1));
+    sp = sin (anlr_rot_sl(i - 1));
+    KE = rotation (KE, RE, cp, sp).';
+
+    XS1 = - width2 * KE + X1;
+    XS2 = width2 * KE + X1;
+
+    px(:,i) = [XS1(1); XS2(1)];
+    py(:,i) = [XS1(2); XS2(2)];
+    pz(:,i) = [XS1(3); XS2(3)];
+    pc(:,i) = total_angle(i) * [1; 1];
+
+  endfor
+
+  h = surface (hax, px, py, pz, pc);
+
+endfunction
+
+## Interpolate speed and divergence onto the streamline vertices and
+## return the first chunck of valid samples until a singularity /
+## zero is hit or the streamline vertex array "sl" ends
+function [lin_spd_sl, anlr_spd_sl, max_vertices] = ...
+                               interp_sl (x, y, z, lin_spd, anlr_spd, sl)
+
+  anlr_spd_sl = interp3 (x, y, z, anlr_spd, sl(:,1), sl(:,2), sl(:,3));
+  lin_spd_sl = interp3 (x, y, z, lin_spd, sl(:,1), sl(:,2), sl(:,3));
+
+  is_singular_anlr_spd = find (isnan (anlr_spd_sl), 1, "first");
+  is_zero_lin_spd = find (lin_spd_sl == 0, 1, "first");
+
+  max_vertices = rows (sl);
+  if (! isempty (is_singular_anlr_spd))
+    max_vertices = min (max_vertices, is_singular_anlr_spd - 1);
+  endif
+  if (! isempty (is_zero_lin_spd))
+    max_vertices = min (max_vertices, is_zero_lin_spd - 1);
+  endif
+
+endfunction
+
+## N normal to X, so that N is in span ([0 0 1], X)
+## If not possible then span ([1 0 0], X)
+function N = get_normal2 (X)
+
+  if ((X(1) == 0) && (X(2) == 0))
+    A = [1, 0, 0];
+  else
+    A = [0, 0, 1];
+  endif
+
+  ## Project A onto X and get the difference
+  N = A - X * dot (A, X) / (norm (X)^2);
+  N /= norm (N);
+
+endfunction
+
+## Rotate X around U where |U| = 1
+## cp = cos (angle), sp = sin (angle)
+function Y = rotation (X, U, cp, sp)
+
+  ux = U(1);
+  uy = U(2);
+  uz = U(3);
+
+  Y(1,:) = X(1) * (cp + ux * ux * (1 - cp)) + ...
+           X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
+           X(3) * (ux * uz * (1 - cp) + uy * sp);
+
+  Y(2,:) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
+           X(2) * (cp + uy * uy * (1 - cp)) + ...
+           X(3) * (uy * uz * (1 - cp) - ux * sp);
+
+  Y(3,:) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
+           X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
+           X(3) * (cp + uz * uz * (1 - cp));
+
+endfunction
+
+
+%!demo
+%! clf;
+%! [x, y, z] = meshgrid (0:0.2:4, -1:0.2:1, -1:0.2:1);
+%! u = - x + 10;
+%! v = 10 * z.*x;
+%! w = - 10 * y.*x;
+%! sx = [0, 0];
+%! sy = [0, 0.6];
+%! sz = [0, 0];
+%! streamribbon (x, y, z, u, v, w, sx, sy, sz);
+%! hold on;
+%! quiver3 (x, y, z, u, v, w);
+%! colormap (jet);
+%! shading interp;
+%! camlight ("headlight");
+%! view (3);
+%! axis tight equal off;
+%! set (gca, "cameraviewanglemode", "manual");
+%! hcb = colorbar;
+%! title (hcb, "Angle");
+%! title ("Streamribbon");
+
+%!demo
+%! clf;
+%! t = (0:pi/50:2*pi).';
+%! xyz{1} = [cos(t), sin(t), 0*t];
+%! twist{1} = ones (numel (t), 1) * pi / (numel (t) - 1);
+%! streamribbon (xyz, twist, 0.5);
+%! colormap (jet);
+%! view (3);
+%! camlight ("headlight");
+%! axis tight equal off;
+%! title ("Moebius Strip");
+
+## Test input validation
+%!error <Invalid call> streamribbon ()
+%!error <Invalid call> streamribbon (1)
+%!error <Invalid call> streamribbon (1,2,3,4,5)
+%!error <Invalid call> streamribbon (1,2,3,4,5,6,7,8)
+%!error <Invalid call> streamribbon (1,2,3,4,5,6,7,8,9,10,11)
+%!error <WIDTH must be a real scalar . 0> streamribbon (1,2,3,1i)
+%!error <WIDTH must be a real scalar . 0> streamribbon (1,2,3,0)
+%!error <WIDTH must be a real scalar . 0> streamribbon (1,2,3,-1)
+%!error <ANLR_ROT must have same length as XYZ> streamribbon ({[1,1,1;2,2,2]},{[1,1,1]})
--- a/scripts/plot/draw/streamtube.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/streamtube.m	Sun May 16 09:44:35 2021 +0200
@@ -66,7 +66,7 @@
 ## The optional return value @var{h} is a graphics handle to the plot objects
 ## created for each tube.
 ##
-## @seealso{stream3, streamline, ostreamtube}
+## @seealso{stream3, streamline, streamribbon, ostreamtube}
 ## @end deftypefn
 
 function h = streamtube (varargin)
@@ -78,8 +78,6 @@
   div = [];
   dia = [];
   switch (nargin)
-    case 0
-      print_usage ();
     case 2
       ## "dia" can be a cell array or a constant
       if (iscell (varargin{2}) || numel (varargin{2}) == 1)
@@ -116,7 +114,7 @@
     case 10
       [x, y, z, u, v, w, spx, spy, spz, options] = varargin{:};
     otherwise
-      error ("streamtube: invalid number of inputs");
+      print_usage ();
   endswitch
 
   scale = 1;
@@ -129,7 +127,7 @@
         scale = options(1);
         num_circum = options(2);
       otherwise
-        error ("streamtube: invalid number of OPTIONS elements");
+        error ("streamtube: OPTIONS must be a 1- or 2-element vector");
     endswitch
 
     if (! isreal (scale) || scale <= 0)
@@ -169,7 +167,7 @@
   for i = 1 : length (xyz)
     sl = xyz{i};
     if (! isempty (sl))
-      slx = sl(:, 1); sly = sl(:, 2); slz = sl(:, 3);
+      slx = sl(:,1); sly = sl(:,2); slz = sl(:,3);
       mxx(j) = max (slx); mnx(j) = min (slx);
       mxy(j) = max (sly); mny(j) = min (sly);
       mxz(j) = max (slz); mnz(j) = min (slz);
@@ -226,10 +224,9 @@
   cp = cos (phi);
   sp = sin (phi);
 
-  X0 = sl(1, :);
-  X1 = sl(2, :);
-
-  ## 1st rotation axis
+  ## 1st streamline segment
+  X0 = sl(1,:);
+  X1 = sl(2,:);
   R = X1 - X0;
   RE = R / norm (R);
 
@@ -244,35 +241,34 @@
   py = zeros (num_circum, max_vertices);
   pz = zeros (num_circum, max_vertices);
 
-  px(:, 1) = XS0(1, :).';
-  py(:, 1) = XS0(2, :).';
-  pz(:, 1) = XS0(3, :).';
+  px(:,1) = XS0(1,:).';
+  py(:,1) = XS0(2,:).';
+  pz(:,1) = XS0(3,:).';
 
-  px(:, 2) = XS(1, :).';
-  py(:, 2) = XS(2, :).';
-  pz(:, 2) = XS(3, :).';
+  px(:,2) = XS(1,:).';
+  py(:,2) = XS(2,:).';
+  pz(:,2) = XS(3,:).';
 
   for i = 3 : max_vertices
 
-    KEold = KE;
+    ## Next streamline segment
     X0 = X1;
-
-    X1 = sl(i, :);
+    X1 = sl(i,:);
     R = X1 - X0;
     RE = R / norm (R);
 
-    ## Project KE onto RE and get the difference in order to calculate the next
-    ## guiding point
-    Kp = KEold - RE * dot (KEold, RE);
+    ## Project KE onto RE and get the difference in order to transport
+    ## the normal vector KE along the vertex array
+    Kp = KE - RE * dot (KE, RE);
     KE = Kp / norm (Kp);
     K = radius_sl(i) * KE;
 
     ## Rotate around RE and collect surface patches
     XS = rotation (K, RE, cp, sp) + repmat (X1.', 1, num_circum);
 
-    px(:, i) = XS(1, :).';
-    py(:, i) = XS(2, :).';
-    pz(:, i) = XS(3, :).';
+    px(:,i) = XS(1,:).';
+    py(:,i) = XS(2,:).';
+    pz(:,i) = XS(3,:).';
 
   endfor
 
@@ -285,7 +281,7 @@
 ## the streamline vertex array "sl" ends
 function [div_sl_crop, max_vertices] = interp_sl (x, y, z, div, sl)
 
-  div_sl = interp3 (x, y, z, div, sl(:, 1), sl(:, 2), sl(:, 3));
+  div_sl = interp3 (x, y, z, div, sl(:,1), sl(:,2), sl(:,3));
   is_nan = find (isnan (div_sl), 1, "first");
   is_inf = find (isinf (div_sl), 1, "first");
 
@@ -305,9 +301,9 @@
 function N = get_normal1 (X)
 
   if ((X(3) == 0) && (X(1) == -X(2)))
-    N = [- X(2) - X(3), X(1), X(1)];
+    N = [(- X(2) - X(3)), X(1), X(1)];
   else
-    N = [X(3), X(3), - X(1) - X(2)];
+    N = [X(3), X(3), (- X(1) - X(2))];
   endif
 
   N /= norm (N);
@@ -322,20 +318,21 @@
   uy = U(2);
   uz = U(3);
 
-  Y(1, :) = X(1) * (cp + ux * ux * (1 - cp)) + ...
-            X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
-            X(3) * (ux * uz * (1 - cp) + uy * sp);
+  Y(1,:) = X(1) * (cp + ux * ux * (1 - cp)) + ...
+           X(2) * (ux * uy * (1 - cp) - uz * sp) + ...
+           X(3) * (ux * uz * (1 - cp) + uy * sp);
 
-  Y(2, :) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
-            X(2) * (cp + uy * uy * (1 - cp)) + ...
-            X(3) * (uy * uz * (1 - cp) - ux * sp);
+  Y(2,:) = X(1) * (uy * ux * (1 - cp) + uz * sp) + ...
+           X(2) * (cp + uy * uy * (1 - cp)) + ...
+           X(3) * (uy * uz * (1 - cp) - ux * sp);
 
-  Y(3, :) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
-            X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
-            X(3) * (cp + uz * uz * (1 - cp));
+  Y(3,:) = X(1) * (uz * ux * (1 - cp) - uy * sp) + ...
+           X(2) * (uz * uy * (1 - cp) + ux * sp) + ...
+           X(3) * (cp + uz * uz * (1 - cp));
 
 endfunction
 
+
 %!demo
 %! clf;
 %! [x, y, z] = meshgrid (-3:0.15:3, -1:0.1:1, -1:0.1:1);
@@ -356,7 +353,7 @@
 %!demo
 %! clf;
 %! t = 0:.15:15;
-%! xyz{1} = [cos(t)' sin(t)' (t/3)'];
+%! xyz{1} = [cos(t)', sin(t)', (t/3)'];
 %! dia{1} = cos(t)';
 %! streamtube (xyz, dia);
 %! grid on;
@@ -369,12 +366,12 @@
 %! title ("Plot Arbitrary Tube");
 
 ## Test input validation
-%!error streamtube ()
-%!error <invalid number of inputs> streamtube (1)
-%!error <invalid number of inputs> streamtube (1,2,3,4)
-%!error <invalid number of inputs> streamtube (1,2,3,4,5,6,7,8)
-%!error <invalid number of inputs> streamtube (1,2,3,4,5,6,7,8,9,10,11)
-%!error <invalid number of OPTIONS elements> streamtube (1,2,[1,2,3])
+%!error <Invalid call> streamtube ()
+%!error <Invalid call> streamtube (1)
+%!error <Invalid call> streamtube (1,2,3,4)
+%!error <Invalid call> streamtube (1,2,3,4,5,6,7,8)
+%!error <Invalid call> streamtube (1,2,3,4,5,6,7,8,9,10,11)
+%!error <OPTIONS must be a 1- or 2-element vector> streamtube (1,2,[1,2,3])
 %!error <SCALE must be a real scalar . 0> streamtube (1,2,[1i])
 %!error <SCALE must be a real scalar . 0> streamtube (1,2,[0])
 %!error <SCALE must be a real scalar . 0> streamtube (1,2,[-1])
--- a/scripts/plot/draw/surface.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/surface.m	Sun May 16 09:44:35 2021 +0200
@@ -206,7 +206,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   h = surface;
+%!   h = surface ();
 %!   assert (findobj (hf, "type", "surface"), h);
 %!   assert (get (h, "xdata"), 1:3, eps);
 %!   assert (get (h, "ydata"), (1:3)', eps);
--- a/scripts/plot/draw/surfl.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/surfl.m	Sun May 16 09:44:35 2021 +0200
@@ -156,7 +156,7 @@
 
     ## Get view vector (vv).
     [az, el] = view ();
-    vv = sph2cart ((az - 90) * pi/180.0, el * pi/180.0, 1.0);
+    [vv(1), vv(2), vv(3)] = sph2cart ((az - 90) * pi/180.0, el * pi/180.0, 1.0);
 
     if (! have_lv)
       ## Calculate light vector (lv) from view vector.
--- a/scripts/plot/draw/surfnorm.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/surfnorm.m	Sun May 16 09:44:35 2021 +0200
@@ -203,8 +203,8 @@
 %!         "sombrero() function with 10 faces"});
 
 ## Test input validation
-%!error surfnorm ()
-%!error surfnorm (1,2)
+%!error <Invalid call> surfnorm ()
+%!error <Invalid call> surfnorm (1,2)
 %!error <X, Y, and Z must be 2-D real matrices> surfnorm (i)
 %!error <X, Y, and Z must be 2-D real matrices> surfnorm (i, 1, 1)
 %!error <X, Y, and Z must be 2-D real matrices> surfnorm (1, i, 1)
--- a/scripts/plot/draw/tetramesh.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/tetramesh.m	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
 
   [reg, prop] = parseparams (varargin);
 
-  if (length (reg) < 2 || length (reg) > 3)
+  if (numel (reg) < 2 || numel (reg) > 3)
     print_usage ();
   endif
 
--- a/scripts/plot/draw/trimesh.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/trimesh.m	Sun May 16 09:44:35 2021 +0200
@@ -76,7 +76,7 @@
       varargin(1) = [];
       if (isvector (c))
         c = c(:);
-      end
+      endif
       if (rows (c) != numel (z) && rows (c) != rows (tri))
         error ("trimesh: the numbers of colors specified in C must equal the number of vertices in Z or the number of triangles in TRI");
       elseif (columns (c) != 1 && columns (c) != 3)
@@ -122,9 +122,9 @@
 %! title ("trimesh() plot of sparsely-sampled peaks() function");
 
 ## Test input validation
-%!error trimesh ()
-%!error trimesh (1)
-%!error trimesh (1,2)
+%!error <Invalid call> trimesh ()
+%!error <Invalid call> trimesh (1)
+%!error <Invalid call> trimesh (1,2)
 %!error <the numbers of colors> trimesh (1,2,3,4,[5 6])
 %!error <the numbers of colors> trimesh (1,2,3,4,[5 6]')
 %!error <the numbers of colors> trimesh ([1;1],[2;2],[3;3],[4;4], zeros (3,3))
--- a/scripts/plot/draw/trisurf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/draw/trisurf.m	Sun May 16 09:44:35 2021 +0200
@@ -71,7 +71,7 @@
     varargin(1) = [];
     if (isvector (c))
       c = c(:);
-    end
+    endif
     if (rows (c) != numel (z) && rows (c) != rows (tri))
       error ("trisurf: the numbers of colors specified in C must equal the number of vertices in Z or the number of triangles in TRI");
     elseif (columns (c) != 1 && columns (c) != 3)
@@ -138,7 +138,7 @@
 %! z = peaks (x, y);
 %! tri = delaunay (x(:), y(:));
 %! trisurf (tri, x(:), y(:), z(:));
-%! title ("trisurf() of sparsely-sampled triangulation of peaks()");
+%! title ("trisurf () of sparsely-sampled triangulation of peaks ()");
 
 %!demo
 %! clf;
@@ -171,10 +171,10 @@
 %! title ({"trisurf() of random data", '"facecolor" = "interp", "edgecolor" = "white"'});
 
 ## Test input validation
-%!error trisurf ()
-%!error trisurf (1)
-%!error trisurf (1,2)
-%!error trisurf (1,2,3)
+%!error <Invalid call> trisurf ()
+%!error <Invalid call> trisurf (1)
+%!error <Invalid call> trisurf (1,2)
+%!error <Invalid call> trisurf (1,2,3)
 %!error <the numbers of colors> trisurf (1,2,3,4,[5 6])
 %!error <the numbers of colors> trisurf (1,2,3,4,[5 6]')
 %!error <the numbers of colors> trisurf ([1;1],[2;2],[3;3],[4;4], zeros (3,3))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/util/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/plot/util/__actual_axis_position__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/__actual_axis_position__.m	Sun May 16 09:44:35 2021 +0200
@@ -50,7 +50,7 @@
   end_unwind_protect
   ## Get axes size in pixels
   if (strcmp (get (axis_obj.parent, "__graphics_toolkit__"), "gnuplot")
-      && strcmp (axis_obj.activepositionproperty, "outerposition"))
+      && strcmp (axis_obj.positionconstraint, "outerposition"))
     pos_in_pixels = axis_obj.outerposition .* fig_position([3, 4, 3, 4]);
   else
     pos_in_pixels = axis_obj.position .* fig_position([3, 4, 3, 4]);
@@ -82,7 +82,7 @@
     endif
     pos = pos_in_pixels ./ fig_position([3, 4, 3, 4]);
   elseif (strcmp (get (axis_obj.parent, "__graphics_toolkit__"), "gnuplot")
-          && strcmp (axis_obj.activepositionproperty, "outerposition"))
+          && strcmp (axis_obj.positionconstraint, "outerposition"))
     pos = axis_obj.outerposition;
   else
     pos = axis_obj.position;
--- a/scripts/plot/util/__default_plot_options__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/__default_plot_options__.m	Sun May 16 09:44:35 2021 +0200
@@ -25,16 +25,17 @@
 
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{options} =} __default_plot_options__ ()
-## Undocumented internal function.
+## Return a plot options structure @var{options} with default values
+## for all fields.
 ## @end deftypefn
 
 function options = __default_plot_options__ ()
 
-  options.key = "";
-  options.color = [];
-  options.linestyle = [];
-  options.marker = [];
-  options.errorstyle = [];
+  options = struct ("key", "",
+                    "color", [],
+                    "linestyle", [],
+                    "marker", [],
+                    "errorstyle", []);
 
 endfunction
 
--- a/scripts/plot/util/__gnuplot_drawnow__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/__gnuplot_drawnow__.m	Sun May 16 09:44:35 2021 +0200
@@ -30,7 +30,7 @@
 
 function __gnuplot_drawnow__ (h, term, file, debug_file)
 
-  if (nargin < 1 || nargin > 4 || nargin == 2)
+  if (nargin < 1 || nargin == 2)
     print_usage ();
   endif
 
@@ -269,7 +269,7 @@
     endif
 
     ## Set the gnuplot terminal (type, enhanced, title, options & size).
-    term_str = ["set terminal " term];
+    term_str = ["set encoding utf8;\nset terminal " term];
     if (__gnuplot_has_feature__ ("needs_color_with_postscript") ...
         && strcmp (term, "postscript"))
       term_str = [term_str, " color"];
--- a/scripts/plot/util/__opengl_info__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/__opengl_info__.m	Sun May 16 09:44:35 2021 +0200
@@ -59,10 +59,6 @@
 
 function retval = __opengl_info__ ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   [info, msg] = gl_info ();
 
   if (! isempty (msg))
--- a/scripts/plot/util/__plt_get_axis_arg__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/__plt_get_axis_arg__.m	Sun May 16 09:44:35 2021 +0200
@@ -49,6 +49,8 @@
   elseif (numel (varargin) > 1)
     ## FIXME: This can be fooled by any string "parent" such as
     ##        the prop/val pair "tag"/"parent".
+    ## varargin may contain char arrays. Silence respective warning.
+    warning ("off", "Octave:charmat-truncated", "local");
     parent = find (strcmpi (varargin, "parent"), 1, "last");
     if (! isempty (parent))
       if (parent == numel (varargin) || ! ishghandle (varargin{parent+1}))
--- a/scripts/plot/util/__pltopt__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/__pltopt__.m	Sun May 16 09:44:35 2021 +0200
@@ -30,93 +30,105 @@
 ##
 ## @var{opt} can currently be some combination of the following:
 ##
-## @table @code
-## @item "-"
+## @table @asis
+## @item @qcode{"-"}
 ## For solid linestyle (default).
 ##
-## @item "--"
+## @item @qcode{"--"}
 ## For dashed line style.
 ##
-## @item "-."
+## @item @qcode{"-."}
 ## For linespoints plot style.
 ##
-## @item ":"
+## @item @qcode{":"}
 ## For dots plot style.
 ##
-## @item "r"
+## @item  @qcode{"r"}
+## @itemx @qcode{"red"}
 ## Red line color.
 ##
-## @item "g"
+## @item  @qcode{"g"}
+## @itemx @qcode{"green"}
 ## Green line color.
 ##
-## @item "b"
+## @item  @qcode{"b"}
+## @itemx @qcode{"blue"}
 ## Blue line color.
 ##
-## @item "c"
+## @item  @qcode{"c"}
+## @itemx @qcode{"cyan"}
 ## Cyan line color.
 ##
-## @item "m"
+## @item  @qcode{"m"}
+## @itemx @qcode{"magenta"}
 ## Magenta line color.
 ##
-## @item "y"
+## @item  @qcode{"y"}
+## @itemx @qcode{"yellow"}
 ## Yellow line color.
 ##
-## @item "k"
+## @item  @qcode{"k"}
+## @itemx @qcode{"black"}
 ## Black line color.
 ##
-## @item "w"
+## @item  @qcode{"w"}
+## @itemx @qcode{"white"}
 ## White line color.
 ##
-## @item ";title;"
-## Here @code{"title"} is the label for the key.
+## @item @qcode{";displayname;"}
+## The text between semicolons is used to set the @qcode{"displayname"}
+## property which determines the label used for the plot legend.
 ##
-## @item  "+"
-## @itemx "o"
-## @itemx "*"
-## @itemx "."
-## @itemx "x"
-## @itemx "s"
-## @itemx "d"
-## @itemx "^"
-## @itemx "v"
-## @itemx ">"
-## @itemx "<"
-## @itemx "p"
-## @itemx "h"
+## @item  @qcode{"+"}
+## @itemx @qcode{"o"}
+## @itemx @qcode{"*"}
+## @itemx @qcode{"."}
+## @itemx @qcode{"x"}
+## @itemx @qcode{"s"}
+## @itemx @qcode{"d"}
+## @itemx @qcode{"^"}
+## @itemx @qcode{"v"}
+## @itemx @qcode{">"}
+## @itemx @qcode{"<"}
+## @itemx @qcode{"p"}
+## @itemx @qcode{"h"}
 ## Used in combination with the points or linespoints styles, set the point
 ## style.
 ## @end table
 ##
-## The legend may be fixed to include the name of the variable
-## plotted in some future version of Octave.
 ## @end deftypefn
 
 function [options, valid] = __pltopt__ (caller, opt, err_on_invalid = true)
 
-  options = __default_plot_options__ ();
-  valid = true;
-
   if (ischar (opt))
     opt = cellstr (opt);
   elseif (! iscellstr (opt))
+    ## FIXME: This is an internal function.  Can't we rely on valid input?
     error ("__pltopt__: argument must be a character string or cell array of character strings");
   endif
 
   nel = numel (opt);
 
-  for i = nel:-1:1
-    [options(i), valid] = __pltopt1__ (caller, opt{i}, err_on_invalid);
-    if (! err_on_invalid && ! valid)
-      return;
-    endif
-  endfor
+  if (nel)
+    for i = nel:-1:1
+      [options(i), valid] = decode_linespec (caller, opt{i}, err_on_invalid);
+      if (! err_on_invalid && ! valid)
+        return;
+      endif
+    endfor
+  else
+    options = __default_plot_options__ ();
+    valid = true;
+  endif
 
 endfunction
 
 ## Really decode plot option strings.
-function [options, valid] = __pltopt1__ (caller, opt, err_on_invalid)
+function [options, valid] = decode_linespec (caller, opt, err_on_invalid)
 
-  options = __default_plot_options__ ();
+  persistent default_options = __default_plot_options__ ();
+
+  options = default_options;
   valid = true;
 
   have_linestyle = false;
@@ -141,83 +153,103 @@
   endif
 
   while (! isempty (opt))
+    topt = opt(1);
+    n = 1;
+
+    ## LineStyles
     if (strncmp (opt, "--", 2) || strncmp (opt, "-.", 2))
       options.linestyle = opt(1:2);
       have_linestyle = true;
       n = 2;
-    else
-      topt = opt(1);
-      n = 1;
-      if (topt == "-" || topt == ":")
-        have_linestyle = true;
-        options.linestyle = topt;
-      elseif (topt == "+" || topt == "o" || topt == "*"
-              || topt == "." || topt == "x" || topt == "s"
-              || topt == "d" || topt == "^" || topt == "v"
-              || topt == ">" || topt == "<" || topt == "p"
-              || topt == "h" || topt == "@")
-        have_marker = true;
-        ## Check for long form marker styles
-        if (any (topt == "sdhp"))
-          if (strncmp (opt, "square", 6))
-            n = 6;
-          elseif (strncmp (opt, "diamond", 7))
-            n = 7;
-          elseif (strncmp (opt, "hexagram", 8))
-            n = 8;
-          elseif (strncmp (opt, "pentagram", 9))
-            n = 9;
-          endif
-        endif
-        ## Backward compatibility.  Leave undocumented.
-        if (topt == "@")
-          topt = "+";
+    elseif (topt == "-" || topt == ":")
+      have_linestyle = true;
+      options.linestyle = topt;
+    ## Markers
+    elseif (any (topt == "+o*.xsd^v><ph"))
+      have_marker = true;
+      ## Check for long form marker styles
+      if (any (topt == "sdhp"))
+        if (strncmp (opt, "square", 6))
+          n = 6;
+        elseif (strncmp (opt, "diamond", 7))
+          n = 7;
+        elseif (strncmp (opt, "hexagram", 8))
+          n = 8;
+        elseif (strncmp (opt, "pentagram", 9))
+          n = 9;
         endif
-        options.marker = topt;
-      ## Numeric color specs are for backward compatibility.  Don't document.
-      elseif (topt == "k" || topt == "0")
+      endif
+      options.marker = topt;
+    ## Color specs
+    elseif (topt == "k")
+      options.color = [0, 0, 0];
+    elseif (topt == "r")
+      if (strncmp (opt, "red", 3))
+        n = 3;
+      endif
+      options.color = [1, 0, 0];
+    elseif (topt == "g")
+      if (strncmp (opt, "green", 5))
+        n = 5;
+      endif
+      options.color = [0, 1, 0];
+    elseif (topt == "b")
+      if (strncmp (opt, "black", 5))
         options.color = [0, 0, 0];
-      elseif (topt == "r" || topt == "1")
-        options.color = [1, 0, 0];
-      elseif (topt == "g" || topt == "2")
-        options.color = [0, 1, 0];
-      elseif (topt == "b" || topt == "3")
+        n = 5;
+      elseif (strncmp (opt, "blue", 4))
+        options.color = [0, 0, 1];
+        n = 4;
+      else
         options.color = [0, 0, 1];
-      elseif (topt == "y")
-        options.color = [1, 1, 0];
-      elseif (topt == "m" || topt == "4")
-        options.color = [1, 0, 1];
-      elseif (topt == "c" || topt == "5")
-        options.color = [0, 1, 1];
-      elseif (topt == "w" || topt == "6")
-        options.color = [1, 1, 1];
-      elseif (isspace (topt))
-        ## Do nothing.
-      elseif (topt == ";")
-        t = index (opt(2:end), ";");
-        if (t)
-          options.key = opt(2:t);
-          n = t+1;
-        else
-          if (err_on_invalid)
-            error ("%s: unfinished key label", caller);
-          else
-            valid = false;
-            options = __default_plot_options__ ();
-            return;
-          endif
-        endif
+      endif
+    elseif (topt == "y")
+      if (strncmp (opt, "yellow", 6))
+        n = 6;
+      endif
+      options.color = [1, 1, 0];
+    elseif (topt == "m")
+      if (strncmp (opt, "magenta", 7))
+        n = 7;
+      endif
+      options.color = [1, 0, 1];
+    elseif (topt == "c")
+      if (strncmp (opt, "cyan", 4))
+        n = 4;
+      endif
+      options.color = [0, 1, 1];
+    elseif (topt == "w")
+      if (strncmp (opt, "white", 5))
+        n = 5;
+      endif
+      options.color = [1, 1, 1];
+    elseif (isspace (topt))
+      ## Do nothing.
+    elseif (topt == ";")
+      t = index (opt(2:end), ";");
+      if (t)
+        options.key = opt(2:t);
+        n = t+1;
       else
         if (err_on_invalid)
-          error ("%s: unrecognized format character: '%s'", caller, topt);
+          error ("%s: unfinished key label", caller);
         else
           valid = false;
-          options = __default_plot_options__ ();
+          options = default_options;
           return;
         endif
       endif
+    else
+      if (err_on_invalid)
+        error ("%s: unrecognized format character: '%s'", caller, topt);
+      else
+        valid = false;
+        options = default_options;
+        return;
+      endif
     endif
-    opt(1:n) = [];
+
+    opt(1:n) = [];  # Delete decoded portion
   endwhile
 
   if (! have_linestyle && have_marker)
@@ -244,7 +276,12 @@
 %! assert (opts.linestyle, ":");
 %! assert (opts.marker, "x");
 %!test
-%! opts = __pltopt__ ("abc", "2square");
+%! opts = __pltopt__ ("abc", "-.blackx");
+%! assert (opts.color, [0 0 0]);
+%! assert (opts.linestyle, "-.");
+%! assert (opts.marker, "x");
+%!test
+%! opts = __pltopt__ ("abc", "gsquare");
 %! assert (opts.color, [0 1 0]);
 %! assert (opts.linestyle, "none");
 %! assert (opts.marker, "s");
--- a/scripts/plot/util/allchild.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/allchild.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 
 function h = allchild (handles)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -57,7 +57,7 @@
 %! toolkit = graphics_toolkit ("qt");
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   l = line;
+%!   l = line ();
 %!   kids = allchild (hf);
 %!   assert (get (kids, "type"), ...
 %!           {"axes"; "uitoolbar"; "uimenu"; "uimenu"; "uimenu"});
@@ -66,5 +66,4 @@
 %!   graphics_toolkit (toolkit);
 %! end_unwind_protect
 
-%!error allchild ()
-%!error allchild (1, 2)
+%!error <Invalid call> allchild ()
--- a/scripts/plot/util/ancestor.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/ancestor.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
 
 function p = ancestor (h, type, toplevel)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -91,7 +91,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hl = line;
+%!   hl = line ();
 %!   assert (ancestor (hl, "axes"), gca);
 %!   assert (ancestor (hl, "figure"), hf);
 %! unwind_protect_cleanup
@@ -117,7 +117,6 @@
 
 %!assert (ancestor ([], "axes"), [])
 
-%!error ancestor ()
-%!error ancestor (1,2,3)
+%!error <Invalid call> ancestor ()
 %!error <TYPE must be a string> ancestor (1,2)
 %!error <third argument must be "toplevel"> ancestor (1, "axes", "foo")
--- a/scripts/plot/util/cla.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/cla.m	Sun May 16 09:44:35 2021 +0200
@@ -49,17 +49,13 @@
 
 function cla (hax, do_reset = false)
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (nargin == 0)
-    hax = gca;
+    hax = gca ();
   elseif (nargin == 1)
     if (isscalar (hax) && isaxes (hax))
       ## Normal case : cla (hax) without reset
     elseif (ischar (hax) && strcmpi (hax, "reset"))
-      hax = gca;
+      hax = gca ();
       do_reset = true;
     else
       print_usage ();
@@ -98,7 +94,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   hax = gca;
+%!   hax = gca ();
 %!   plot (hax, 1:10);
 %!   assert (get (hax, "colororderindex"), 2);
 %!   set (hax, "ticklabelinterpreter", "none");
--- a/scripts/plot/util/clf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/clf.m	Sun May 16 09:44:35 2021 +0200
@@ -52,14 +52,14 @@
   if (nargin > 2)
     print_usage ();
   elseif (nargin == 0)
-    hfig = gcf;
+    hfig = gcf ();
     do_reset = false;
   elseif (nargin == 1)
     if (isscalar (varargin{1}) && isfigure (varargin{1}))
       hfig = varargin{1};
       do_reset = false;
     elseif (ischar (varargin{1}) && strcmpi (varargin{1}, "reset"))
-      hfig = gcf;
+      hfig = gcf ();
       do_reset = true;
     else
       print_usage ();
@@ -119,7 +119,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   l = line;
+%!   l = line ();
 %!   assert (! isempty (get (gcf, "children")));
 %!   clf;
 %!   assert (isempty (get (gcf, "children")));
--- a/scripts/plot/util/close.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/close.m	Sun May 16 09:44:35 2021 +0200
@@ -63,9 +63,7 @@
 
   figs = [];
 
-  if (nargin > 2)
-    print_usage ();
-  elseif (nargin == 0)
+  if (nargin == 0)
     ## Close current figure.
     ## Can't use gcf because it opens a new plot window if one does not exist.
     figs = get (0, "currentfigure");
@@ -181,7 +179,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error close (1,2,3)
 %!error <first argument must be "all", a figure handle> close ({"all"})
 %!error <first argument must be "all", a figure handle> close (-1)
 %!error <second argument must be "hidden"> close all hid
--- a/scripts/plot/util/closereq.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/closereq.m	Sun May 16 09:44:35 2021 +0200
@@ -34,10 +34,6 @@
 
 function closereq ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   ## Get current figure, but don't use gcf to avoid creating a new figure.
   cf = get (0, "currentfigure");
   if (isfigure (cf))
--- a/scripts/plot/util/colstyle.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/colstyle.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function [l, c, m, msg] = colstyle (style)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -94,6 +94,6 @@
 %! assert (msg, "colstyle: unrecognized format character: '~'");
 
 ## Test input validation
-%!error colstyle ()
+%!error <Invalid call> colstyle ()
 %!error colstyle (1, 2)
 %!error <STYLE must be a string> colstyle (1.5)
--- a/scripts/plot/util/copyobj.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/copyobj.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
   othertypes = {"line", "patch", "surface", "image", "text", "uicontrol"};
   alltypes = [partypes othertypes];
 
-  if (! ishghandle (horig) || nargin > 2)
+  if (! ishghandle (horig))
     print_usage ();
   elseif (! ishghandle (hparent))
     hparent = figure (fix (hparent));
@@ -79,7 +79,7 @@
   endfor
 
   if (kididx <= paridx)
-    error ("copyobj: %s object can't be a child of %s.",
+    error ("copyobj: %s object can't be a child of %s",
            alltypes{kididx}, alltypes{paridx});
   endif
 
--- a/scripts/plot/util/figure.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/figure.m	Sun May 16 09:44:35 2021 +0200
@@ -85,7 +85,7 @@
   ## Check to see if we already have a figure on the screen.  If we do,
   ## then update it if it is different from the figure we are creating
   ## or switching to.
-  cf = get (0, "currentfigure");   # Can't use gcf () because it calls figure()
+  cf = get (0, "currentfigure");   # Can't use gcf() because it calls figure()
   if (! isempty (cf) && cf != 0)
     if (init_new_figure || cf != f)
       drawnow ();
--- a/scripts/plot/util/findall.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/findall.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 ##
 ## @code{findall} performs the same search as @code{findobj}, but it
 ## includes hidden objects (HandleVisibility = @qcode{"off"}).  For full
-## documentation, @pxref{XREFfindobj,,findobj}.
+## documentation, @pxref{XREFfindobj,,@code{findobj}}.
 ## @seealso{findobj, allchild, get, set}
 ## @end deftypefn
 
--- a/scripts/plot/util/findobj.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/findobj.m	Sun May 16 09:44:35 2021 +0200
@@ -88,8 +88,9 @@
 ## @end example
 ##
 ## Implementation Note: The search only includes objects with visible
-## handles (@w{HandleVisibility} = @qcode{"on"}).  @xref{XREFfindall,,findall},
-## to search for all objects including hidden ones.
+## handles (@w{HandleVisibility} = @qcode{"on"}).
+## @xref{XREFfindall,,@code{findall}}, to search for all objects including
+## hidden ones.
 ## @seealso{findall, allchild, get, set}
 ## @end deftypefn
 
@@ -329,7 +330,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   l = line;
+%!   l = line ();
 %!   obj = findobj (hf, "type", "line");
 %!   assert (l, obj);
 %!   assert (gca, findobj (hf, "type", "axes"));
--- a/scripts/plot/util/gca.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/gca.m	Sun May 16 09:44:35 2021 +0200
@@ -57,13 +57,9 @@
 
 function h = gca ()
 
-  if (nargin == 0)
-    h = get (gcf (), "currentaxes");
-    if (isempty (h))
-      h = axes ();
-    endif
-  else
-    print_usage ();
+  h = get (gcf (), "currentaxes");
+  if (isempty (h))
+    h = axes ();
   endif
 
 endfunction
@@ -71,7 +67,7 @@
 
 %!test
 %! hf = figure ("visible", "off");
-%! ax = axes;
+%! ax = axes ();
 %! unwind_protect
 %!   assert (gca, ax);
 %! unwind_protect_cleanup
--- a/scripts/plot/util/gcf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/gcf.m	Sun May 16 09:44:35 2021 +0200
@@ -60,15 +60,11 @@
 
 function h = gcf ()
 
-  if (nargin == 0)
-    h = get (0, "currentfigure");
-    if (isempty (h) || h == 0)
-      ## We only have a root object, so create a new figure object
-      ## and make it the current figure.
-      h = figure ();
-    endif
-  else
-    print_usage ();
+  h = get (0, "currentfigure");
+  if (isempty (h) || h == 0)
+    ## We only have a root object, so create a new figure object
+    ## and make it the current figure.
+    h = figure ();
   endif
 
 endfunction
--- a/scripts/plot/util/ginput.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/ginput.m	Sun May 16 09:44:35 2021 +0200
@@ -46,10 +46,6 @@
 
 function varargout = ginput (n = -1)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   ## Create an axis, if necessary.
   fig = gcf ();
   ax = gca ();
@@ -69,7 +65,7 @@
     else
       [varargout{:}] = feval (toolkit_fcn, fig, n);
     endif
-    return
+    return;
   endif
 
   x = y = button = [];
--- a/scripts/plot/util/graphics_toolkit.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/graphics_toolkit.m	Sun May 16 09:44:35 2021 +0200
@@ -45,10 +45,6 @@
 
 function retval = graphics_toolkit (name, hlist = [])
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (nargout > 0 || nargin == 0)
     retval = get (0, "defaultfigure__graphics_toolkit__");
     ## Handle case where graphics_toolkit has been called before any plotting
@@ -92,7 +88,7 @@
     if (strcmp (name, "gnuplot"))
       valid_version = __gnuplot_has_feature__ ("minimum_version");
       if (valid_version != 1)
-        error ("graphics_toolkit: gnuplot version too old.");
+        error ("graphics_toolkit: gnuplot version too old");
       endif
     endif
     feval (["__init_", name, "__"]);
@@ -109,6 +105,7 @@
 
 endfunction
 
+
 %!testif HAVE_OPENGL, HAVE_QT; have_window_system () && any (strcmp ("qt", available_graphics_toolkits ()))
 %! unwind_protect
 %!   hf = figure ("visible", "off");
--- a/scripts/plot/util/groot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/groot.m	Sun May 16 09:44:35 2021 +0200
@@ -58,16 +58,9 @@
 
 function h = groot ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   h = 0;
 
 endfunction
 
 
 %!assert (groot (), 0)
-
-## Test input validation
-%!error groot (1)
--- a/scripts/plot/util/hdl2struct.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/hdl2struct.m	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
 
 function s = hdl2struct (h)
 
-  if (nargin != 1 || ! ishghandle (h))
+  if (nargin < 1 || ! ishghandle (h))
     print_usage ();
   endif
 
@@ -139,12 +139,13 @@
   persistent excluded;
 
   if (isempty (excluded))
-    excluded = cell2struct (repmat ({[]}, 1, 15),
+    excluded = cell2struct (repmat ({[]}, 1, 16),
                             {"beingdeleted", "busyaction", "buttondownfcn", ...
-                             "children", "clipping", "createfcn", ...
-                             "deletefcn", "handlevisibility", "hittest", ...
-                             "interruptible", "parent", "selected" , ...
-                             "selectionhighlight", "type", "uicontextmenu"}, 2);
+                             "children", "clipping", "contextmenu", ...
+                             "createfcn", "deletefcn", "handlevisibility", ...
+                             "hittest", "interruptible", "parent", ...
+                             "selected" , "selectionhighlight", "type", ...
+                             "uicontextmenu"}, 2);
   endif
 
   obj = get (h);
--- a/scripts/plot/util/hggroup.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/hggroup.m	Sun May 16 09:44:35 2021 +0200
@@ -68,7 +68,7 @@
 %!test
 %! hf = figure ("visible", "off");
 %! unwind_protect
-%!   h = hggroup;
+%!   h = hggroup ();
 %!   assert (findobj (hf, "type", "hggroup"), h);
 %!   assert (get (h, "type"), "hggroup");
 %! unwind_protect_cleanup
--- a/scripts/plot/util/hgload.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/hgload.m	Sun May 16 09:44:35 2021 +0200
@@ -45,7 +45,7 @@
 function [h, old_prop] = hgload (filename, prop_struct = struct ())
 
   ## Check number of input arguments
-  if (nargin == 0 || nargin > 2)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -133,8 +133,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error hgload ()
-%!error hgload (1, 2, 3)
+%!error <Invalid call> hgload ()
 %!error <PROP_STRUCT must be a struct> hgload (1, {})
 %!error <unable to locate file> hgload ("%%_A_REALLY_UNLIKELY_FILENAME_%%")
 %!error <unable to locate file> hgload ("%%_A_REALLY_UNLIKELY_FILENAME_%%.fig")
--- a/scripts/plot/util/hgsave.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/hgsave.m	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
 
 function hgsave (h, filename, fmt = "-binary")
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -130,8 +130,7 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error hgsave ()
-%!error hgsave (1, 2, 3, 4)
+%!error <Invalid call> hgsave ()
 %!error <no current figure to save>
 %! unwind_protect
 %!  old_fig = get (0, "currentfigure");
--- a/scripts/plot/util/isaxes.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/isaxes.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function retval = isaxes (h)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -66,5 +66,4 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error isaxes ()
-%!error isaxes (1, 2)
+%!error <Invalid call> isaxes ()
--- a/scripts/plot/util/isfigure.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/isfigure.m	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
 
 function retval = isfigure (h)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -65,5 +65,4 @@
 %!   close (hf);
 %! end_unwind_protect
 
-%!error isfigure ()
-%!error isfigure (1, 2)
+%!error <Invalid call> isfigure ()
--- a/scripts/plot/util/isgraphics.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/isgraphics.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function retval = isgraphics (h, type = "")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -61,8 +61,8 @@
 %!   assert (isgraphics (hf, "figure"));
 %!   assert (! isgraphics (-hf));
 %!   assert (! isgraphics (hf, "foo"));
-%!   l = line;
-%!   ax = gca;
+%!   l = line ();
+%!   ax = gca ();
 %!   assert (isgraphics (ax));
 %!   assert (isgraphics (ax, "axes"));
 %!   assert (! isgraphics (-ax));
@@ -71,17 +71,17 @@
 %!   assert (isgraphics (l, "line"));
 %!   assert (! isgraphics (-l));
 %!   assert (! isgraphics (l, "foo"));
-%!   p = patch;
+%!   p = patch ();
 %!   assert (isgraphics (p));
 %!   assert (isgraphics (p, "patch"));
 %!   assert (! isgraphics (-p));
 %!   assert (! isgraphics (p, "foo"));
-%!   s = surface;
+%!   s = surface ();
 %!   assert (isgraphics (s));
 %!   assert (isgraphics (s, "surface"));
 %!   assert (! isgraphics (-s));
 %!   assert (! isgraphics (s, "foo"));
-%!   t = text;
+%!   t = text ();
 %!   assert (isgraphics (t));
 %!   assert (isgraphics (t, "text"));
 %!   assert (! isgraphics (-t));
@@ -91,7 +91,7 @@
 %!   assert (isgraphics (i, "image"));
 %!   assert (! isgraphics (-i));
 %!   assert (! isgraphics (i, "foo"));
-%!   hg = hggroup;
+%!   hg = hggroup ();
 %!   assert (isgraphics (hg));
 %!   assert (isgraphics (hg, "hggroup"));
 %!   assert (! isgraphics (-hg));
@@ -106,7 +106,6 @@
 %! assert (isgraphics ([-1 0], "foobar"), [false false]);
 
 ## Test input validation
-%!error isgraphics ()
-%!error isgraphics (1, 2, 3)
+%!error <Invalid call> isgraphics ()
 %!error <TYPE must be a string> isgraphics (0, 1)
 %!error <TYPE must be a string> isgraphics (0, {1})
--- a/scripts/plot/util/ishandle.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/ishandle.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function retval = ishandle (h)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -55,8 +55,8 @@
 %! unwind_protect
 %!   assert (ishandle (hf));
 %!   assert (! ishandle (-hf));
-%!   ax = gca;
-%!   l = line;
+%!   ax = gca ();
+%!   l = line ();
 %!   assert (ishandle (ax));
 %!   assert (! ishandle (-ax));
 %!   assert (ishandle ([l, -1, ax, hf]), logical ([1, 0, 1, 1]));
@@ -72,5 +72,4 @@
 %! assert (ishandle (jobj));
 
 ## Test input validation
-%!error ishandle ()
-%!error ishandle (1, 2)
+%!error <Invalid call> ishandle ()
--- a/scripts/plot/util/ishold.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/ishold.m	Sun May 16 09:44:35 2021 +0200
@@ -37,10 +37,6 @@
 
 function retval = ishold (h)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     fig = gcf ();
     ax = get (fig, "currentaxes");
--- a/scripts/plot/util/isprop.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/isprop.m	Sun May 16 09:44:35 2021 +0200
@@ -30,34 +30,43 @@
 ## @var{obj} may also be an array of objects in which case @var{res} will be a
 ## logical array indicating whether each handle has the property @var{prop}.
 ##
-## For plotting, @var{obj} is a handle to a graphics object.
-##
-## Programming Note: There is no support in Octave versions 6.X.X for @var{obj}
-## to be an instance of a class (i.e., a classdef object).  This functionality
-## has already been added on the development branch which will become Octave
-## 7.1.0.
-## @seealso{get, set, ismethod, isobject}
+## For plotting, @var{obj} is a handle to a graphics object.  Otherwise,
+## @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
 
@@ -67,7 +76,11 @@
 %!assert (isprop (zeros (2, 3), "visible"), true (2, 3))
 %!assert (isprop ([-2, -1, 0], "visible"), [false, false, true])
 
-%!error isprop ()
-%!error isprop (1)
-%!error isprop (1,2,3)
+%!test
+%! m = containers.Map ();
+%! assert (isprop (m, "KeyType"));
+%! assert (! isprop (m, "FooBar"));
+
+%!error <Invalid call> isprop ()
+%!error <Invalid call> isprop (1)
 %!error <PROP name must be a string> isprop (0, {"visible"})
--- a/scripts/plot/util/linkaxes.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/linkaxes.m	Sun May 16 09:44:35 2021 +0200
@@ -59,7 +59,7 @@
 
 function linkaxes (hax, optstr = "xy")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -165,6 +165,5 @@
 %!  end_unwind_protect
 
 ## Test input validation
-%!error linkaxes ()
-%!error linkaxes (1,2,3)
+%!error <Invalid call> linkaxes ()
 %!error <HAX must be a vector of axes handles> linkaxes ([pi, e])
--- a/scripts/plot/util/linkprop.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/linkprop.m	Sun May 16 09:44:35 2021 +0200
@@ -175,9 +175,8 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error linkprop ()
-%!error linkprop (1)
-%!error linkprop (1,2,3)
+%!error <Invalid call> linkprop ()
+%!error <Invalid call> linkprop (1)
 %!error <H must contain at least 2 handles> linkprop (1, "color")
 %!error <invalid graphic handle in input H> linkprop ([pi, e], "color")
 %!error <PROP must be a string or cell string array> linkprop ([0, 0], 1)
--- a/scripts/plot/util/meshgrid.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/meshgrid.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 
 function [xx, yy, zz] = meshgrid (x, y, z)
 
-  if (nargin == 0 || nargin > 3)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -144,8 +144,7 @@
 %! assert (XX(end) * YY(end), x(end) * y(end));
 
 ## Test input validation
-%!error meshgrid ()
-%!error meshgrid (1,2,3,4)
+%!error <Invalid call> meshgrid ()
 %!error <X and Y must be vectors> meshgrid (ones (2,2), 1:3)
 %!error <X and Y must be vectors> meshgrid (1:3, ones (2,2))
 %!error <X, Y, and Z must be vectors> [X,Y,Z] = meshgrid (1:3, 1:3, ones (2,2))
--- a/scripts/plot/util/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -24,6 +24,7 @@
   %reldir%/private/__set_default_mouse_modes__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__actual_axis_position__.m \
   %reldir%/__default_plot_options__.m \
   %reldir%/__gnuplot_drawnow__.m \
--- a/scripts/plot/util/ndgrid.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/ndgrid.m	Sun May 16 09:44:35 2021 +0200
@@ -95,8 +95,8 @@
 %! x = 1:3;
 %! [XX, YY] = ndgrid (x);
 %! assert (size_equal (XX, YY));
-%! assert (isequal (XX, repmat(x(:), 1, numel(x))));
-%! assert (isequal (YY, repmat(x, numel(x), 1)));
+%! assert (isequal (XX, repmat (x(:), 1, numel (x))));
+%! assert (isequal (YY, repmat (x, numel (x), 1)));
 
 %!test
 %! x = 1:2;
@@ -124,10 +124,10 @@
 %! assert (XX1, XX2.');
 %! assert (YY1, YY2.');
 
-%!assert (ndgrid ([]), zeros(0,1))
+%!assert (ndgrid ([]), zeros (0,1))
 %!assert (ndgrid ([], []), zeros(0,0))
 
 ## Test input validation
-%!error ndgrid ()
+%!error <Invalid call> ndgrid ()
 %!error <wrong number of input arguments> [a,b,c] = ndgrid (1:3,1:3)
 %!error <arguments must be vectors> ndgrid (ones (2,2))
--- a/scripts/plot/util/newplot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/newplot.m	Sun May 16 09:44:35 2021 +0200
@@ -89,10 +89,6 @@
 
 function hax = newplot (hsave = [])
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   cf = [];
   ca = [];
 
@@ -199,7 +195,8 @@
         kids(kids == hkid) = [];
         delete (kids);
       else
-        if (isprop (ca, "__plotyy_axes__"))
+        if (isprop (ca, "__plotyy_axes__") ...
+            && ! any (strcmp({dbstack().name}, "plotyy")))
           ## Hack for bug #44246.  There is no way to reset or remove a
           ## property created with addproperty short of deleting the object.
           delete (ca);
--- a/scripts/plot/util/pan.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/pan.m	Sun May 16 09:44:35 2021 +0200
@@ -46,35 +46,31 @@
 ## @seealso{rotate3d, zoom}
 ## @end deftypefn
 
-function pan (varargin)
-
-  hfig = NaN;
-
-  nargs = nargin;
+function h = pan (hfig, option)
 
-  if (nargs > 2)
-    print_usage ();
-  endif
-
-  if (nargin == 1 && nargout > 0 && isfigure (varargin{1}))
+  ## FIXME: Presumably should implement this for Matlab compatibility.
+  if (nargin == 1 && nargout > 0 && isfigure (hfig))
     error ("pan: syntax 'handle = pan (hfig)' not implemented");
   endif
 
-  if (nargs == 2)
-    hfig = varargin{1};
-    if (isfigure (hfig))
-      varargin(1) = [];
-      nargs -= 1;
+  if (nargin == 0)
+    hfig = gcf ();
+  else
+    if (nargin == 1)
+      option = hfig;
+      hfig = gcf ();
     else
-      error ("pan: invalid figure handle HFIG");
+      if (! isfigure (hfig))
+        error ("pan: invalid figure handle HFIG");
+      endif
+    endif
+
+    if (! ischar (option))
+      error ("pan: OPTION must be a string");
     endif
   endif
 
-  if (isnan (hfig))
-    hfig = gcf ();
-  endif
-
-  if (nargs == 0)
+  if (nargin == 0)
     pm = get (hfig, "__pan_mode__");
     if (strcmp (pm.Enable, "on"))
       pm.Enable = "off";
@@ -83,31 +79,26 @@
     endif
     set (hfig, "__pan_mode__", pm);
     update_mouse_mode (hfig, pm.Enable);
-  elseif (nargs == 1)
-    arg = varargin{1};
-    if (ischar (arg))
-      switch (arg)
-        case {"on", "off", "xon", "yon"}
-          pm = get (hfig, "__pan_mode__");
-          switch (arg)
-            case {"on", "off"}
-              pm.Enable = arg;
-              pm.Motion = "both";
-            case "xon"
-              pm.Enable = "on";
-              pm.Motion = "horizontal";
-            case "yon"
-              pm.Enable = "on";
-              pm.Motion = "vertical";
-          endswitch
-          set (hfig, "__pan_mode__", pm);
-          update_mouse_mode (hfig, arg);
-        otherwise
-          error ("pan: unrecognized OPTION '%s'", arg);
-      endswitch
-    else
-      error ("pan: wrong type argument '%s'", class (arg));
-    endif
+  else
+    switch (option)
+      case {"on", "off", "xon", "yon"}
+        pm = get (hfig, "__pan_mode__");
+        switch (option)
+          case {"on", "off"}
+            pm.Enable = option;
+            pm.Motion = "both";
+          case "xon"
+            pm.Enable = "on";
+            pm.Motion = "horizontal";
+          case "yon"
+            pm.Enable = "on";
+            pm.Motion = "vertical";
+        endswitch
+        set (hfig, "__pan_mode__", pm);
+        update_mouse_mode (hfig, option);
+      otherwise
+        error ("pan: unrecognized OPTION '%s'", option);
+    endswitch
   endif
 
 endfunction
@@ -119,8 +110,8 @@
   else
     ## FIXME: Is there a better way other than calling these functions
     ##        to set the other mouse mode Enable fields to "off"?
-    rotate3d ("off");
-    zoom ("off");
+    rotate3d (hfig, "off");
+    zoom (hfig, "off");
     set (hfig, "__mouse_mode__", "pan");
   endif
 
--- a/scripts/plot/util/print.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/print.m	Sun May 16 09:44:35 2021 +0200
@@ -132,8 +132,13 @@
 ##
 ## @table @asis
 ## @item Font handling:
-## The actual font is embedded in the output file which allows for printing
-## arbitrary characters and fonts in all vector formats.
+## For interpreters "none" and "tex", the actual font is embedded in the output
+## file which allows for printing arbitrary characters and fonts in all vector
+## formats.
+##
+## Strings using the @qcode{"latex"} interpreter, are rendered using path
+## objects. This looks good but note that textual info (font, characters@dots{})
+## are lost.
 ##
 ## @item Output Simplification:
 ## By default, the option @option{-painters} renders patch and surface objects
@@ -472,12 +477,21 @@
     set (opts.figure, "__printing__", "on");
     nfig += 1;
 
-    ## print() requires children of axes to have units = "normalized", or "data"
-    hobj = findall (opts.figure, "-not", "type", "figure", ...
-                    "-not", "type", "axes", "-property", "units", ...
+    ## print() requires children of axes to have units = "normalized" or "data"
+    ## FIXME: Bug #59015.  The only graphics object type to which this
+    ## requirement applies seems to be 'text' objects.  It is simpler, and
+    ## clearer, to just select those objects.  The old code is left commented
+    ## out until sufficient testing has been done.
+    ## Change made: 2020/09/02.
+    ##hobj = findall (opts.figure, "-not", "type", "figure", ...
+    ##                "-not", "type", "axes", "-not", "type", "hggroup", ...
+    ##                "-property", "units", ...
+    ##                "-not", "units", "normalized", "-not", "units", "data");
+    ##hobj(strncmp (get (hobj, "type"), "ui", 2)) = [];
+
+    hobj = findall (opts.figure, "type", "text",
                     "-not", "units", "normalized", "-not", "units", "data");
-    hobj(strncmp (get (hobj, "type"), "ui", 2)) = [];
-    for n = 1:numel(hobj)
+    for n = 1:numel (hobj)
       props(end+1).h = hobj(n);
       props(end).name = "units";
       props(end).value = {get(hobj(n), "units")};
@@ -791,6 +805,7 @@
   if (isfigure (orig_figure))
     set (0, "currentfigure", orig_figure);
   endif
+
 endfunction
 
 function cmd = epstool (opts, filein, fileout)
@@ -801,7 +816,7 @@
 
   ## DOS Shell:
   ##   gs.exe [...] -sOutputFile=<filein> - & epstool -bbox -preview-tiff <filein> <fileout> & del <filein>
-  ## Unix Shell;
+  ## Unix Shell:
   ##   cat > <filein> ; epstool -bbox -preview-tiff <filein> <fileout> ; rm <filein>
 
   dos_shell = (ispc () && ! isunix ());
@@ -1004,13 +1019,10 @@
   switch (opts.devopt)
     case {"pdflatexstandalone"}
       packages = "\\usepackage{graphicx,color}";
-      graphicsfile = [opts.name "-inc.pdf"];
     case {"pslatexstandalone"}
       packages = "\\usepackage{epsfig,color}";
-      graphicsfile = [opts.name "-inc.ps"];
     otherwise
       packages = "\\usepackage{epsfig,color}";
-      graphicsfile = [opts.name "-inc.eps"];
   endswitch
 
   packages = {packages "\\usepackage[utf8]{inputenc}"};
@@ -1033,9 +1045,6 @@
     error ("Octave:print:errorclosingfile",
            "print: error closing file '%s'", latexfile);
   endif
-  ## FIXME: should this be fixed in GL2PS?
-  latex = strrep (latex, "\\includegraphics{}",
-                  sprintf ("\\includegraphics{%s}", graphicsfile));
 
   fid = fopen (latexfile, "w");
   if (fid >= 0)
--- a/scripts/plot/util/private/__add_default_menu__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/private/__add_default_menu__.m	Sun May 16 09:44:35 2021 +0200
@@ -24,10 +24,14 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn  {} {} __add_default_menu__ (@var{hfig})
-## @deftypefnx {} {} __add_default_menu__ (@var{hfig}, @var{hmenu})
+## @deftypefn  {} {} __add_default_menu__ (@var{hf})
+## @deftypefnx {} {} __add_default_menu__ (@var{hf}, @var{hmenu})
+## @deftypefnx {} {} __add_default_menu__ (@var{hf}, @var{hmenu}, @var{htb})
 ## Add default menu and listeners to figure.
 ##
+## @var{hf} is a figure handle.
+## @var{hmenu} is a uimenu handle.
+## @var{htb} is a uitoolbar handle.
 ##
 ## All uimenu handles have their @qcode{"HandleVisibility"} property set to
 ## @qcode{"off"}.
@@ -37,7 +41,7 @@
 
   ## Gnuplot doesn't handle uimenu and uitoolbar objects
   if (strcmp (graphics_toolkit (), "gnuplot"))
-    return
+    return;
   endif
 
   ## Create
@@ -45,11 +49,11 @@
     ## File menu
     hui = uimenu (hf, "label", "&File", "tag", "__default_menu__File", ...
                       "handlevisibility", "off");
-    uimenu (hui, "label", "&Open", "callback", @open_cb, ...
+    uimenu (hui, "label", "&Open...", "callback", @open_cb, ...
             "accelerator", "o");
     uimenu (hui, "label", "&Save", "callback", {@save_cb, "save"}, ...
             "accelerator", "s");
-    uimenu (hui, "label", "Save &As", "callback", {@save_cb, "saveas"}, ...
+    uimenu (hui, "label", "Save &As...", "callback", {@save_cb, "saveas"}, ...
             "accelerator", "S");
     uimenu (hui, "label", "&Close", "callback", @close_cb, ...
             "accelerator", "w", "separator", "on");
@@ -173,17 +177,16 @@
   set (htb, "visible", toolbar_state);
 endfunction
 
-function open_cb (h, e)
-  [filename, filedir] = uigetfile ({"*.ofig", "Octave Figure File"}, ...
+function open_cb (~, ~)
+  [filename, filedir] = uigetfile ({"*.ofig;*.fig", "Figure Files"}, ...
                                    "Open Figure");
   if (filename != 0)
     fname = fullfile (filedir, filename);
-    tmphf = hgload (fname);
-    set (tmphf, "filename", fname);
+    openfig (fname);
   endif
 endfunction
 
-function save_cb (h, e, action)
+function save_cb (h, ~, action)
   hfig = gcbf ();
   fname = get (hfig, "filename");
 
@@ -198,34 +201,54 @@
   endif
 endfunction
 
+function __save_as__ (hf, fname = "")
+  if (! isempty (fname))
+    def = fname;
+  else
+    def = fullfile (pwd (), "untitled.ofig");
+  endif
+  filter = {"*.ofig", "Octave Figure";
+            "*.eps",  "Encapsulated PostScript";
+            "*.pdf",  "Portable Document Format";
+            "*.ps",   "PostScript";
+            "*.svg",  "Scalable Vector Graphics";
+            "*.gif",  "GIF Image";
+            "*.jpg",  "JPEG Image";
+            "*.png",  "Portable Network Graphics Image";
+            "*.tiff", "TIFF Image"};
+  ## Reorder filters to have current first
+  [~, ~, ext] = fileparts (def);
+  idx = strcmp (filter(:,1), ["*" tolower(ext)]);
+  filter = [filter(idx,:); filter(! idx,:)];
 
-function __save_as__ (hf, fname = "")
-  filter = ifelse (! isempty (fname), fname, ...
-                   {"*.ofig", "Octave Figure File";
-                    "*.eps;*.pdf;*.svg;*.ps", "Vector Image Formats";
-                    "*.gif;*.jpg;*.png;*.tiff", "Bitmap Image Formats"});
-  def = ifelse (! isempty (fname), fname, fullfile (pwd, "untitled.ofig"));
-
-  [filename, filedir] = uiputfile (filter, "Save Figure", def);
+  [filename, filedir, filteridx] = uiputfile (filter, "Save Figure", def);
 
   if (filename != 0)
     fname = fullfile (filedir, filename);
-    set (gcbf, "filename", fname);
-    flen = numel (fname);
-    if (flen > 5 && strcmp (fname(flen-4:end), ".ofig"))
-      hgsave (hf, fname);
+    [~, ~, ext] = fileparts (fname);
+    if (filteridx > rows (filter))
+      ## "All Files" option
+      if (isempty (ext))
+        fmt = "";
+      else
+        fmt = ext(2:end);
+      endif
     else
-      saveas (hf, fname);
+      fmt = filter{filteridx,1}(3:end);
+      if (isempty (ext))
+        fname = [fname "." fmt];
+      endif
     endif
+    set (hf, "filename", fname);
+    saveas (hf, fname, fmt);
   endif
+
 endfunction
 
-
-function close_cb (h, e)
-  close (gcbf);
+function close_cb (~, ~)
+  close (gcbf ());
 endfunction
 
-
 function [hax, fig] = __get_axes__ (h)
   ## Get parent figure
   fig = ancestor (h, "figure");
@@ -234,7 +257,7 @@
   hax = findobj (fig, "type", "axes", "-not", "tag", "legend");
 endfunction
 
-function autoscale_cb (h, e)
+function autoscale_cb (h, ~)
   hax = __get_axes__ (h);
   arrayfun (@(h) axis (h, "auto"), hax);
   drawnow ();
@@ -253,7 +276,8 @@
                                     "FigureHandle", hf));
 endfunction
 
-function guimode_cb (h, e)
+function guimode_cb (h, ~)
+
   [hax, fig] = __get_axes__ (h);
   id = get (h, "tag");
   switch (id)
@@ -273,9 +297,10 @@
     case "zoom_off"
       arrayfun (@(h) set (h, "mousewheelzoom", 0.0), hax);
   endswitch
+
 endfunction
 
-function mouse_tools_cb (h, ev, htools, typ = "")
+function mouse_tools_cb (h, ~, htools, typ = "")
 
   persistent recursion = false;
 
@@ -290,7 +315,7 @@
       mode = get (hf, "__mouse_mode__");
       state = "on";
 
-      switch mode
+      switch (mode)
         case "zoom"
           zm = get (hf, "__zoom_mode__");
           if (strcmp (zm.Direction, "in"))
@@ -318,7 +343,7 @@
       ## Update the mouse mode according to the button state
       state = get (h, "state");
 
-      switch typ
+      switch (typ)
         case {"zoomin", "zoomout"}
           prop = "__zoom_mode__";
           val = get (hf, prop);
@@ -329,7 +354,7 @@
             else
               val.Direction = "out";
             endif
-            set (hf, "__mouse_mode__" , "zoom");
+            set (hf, "__mouse_mode__", "zoom");
           endif
           val.Enable = state;
           set (hf, prop, val);
@@ -338,21 +363,21 @@
           prop = ["__", typ, "_mode__"];
           val = get (hf, prop);
           if (strcmp (state, "on"))
-            set (hf, "__mouse_mode__" , typ);
+            set (hf, "__mouse_mode__", typ);
           endif
           val.Enable = state;
           set (hf, prop, val);
 
         case {"text", "select"}
           if (strcmp (state, "on"))
-            set (hf, "__mouse_mode__" , typ);
+            set (hf, "__mouse_mode__", typ);
           endif
       endswitch
 
       if (strcmp (state, "on"))
         set (htools(htools != h), "state", "off");
       elseif (! any (strcmp (get (htools, "state"), "on")))
-        set (hf, "__mouse_mode__" , "none");
+        set (hf, "__mouse_mode__", "none");
       endif
     endif
 
@@ -361,7 +386,7 @@
 
 endfunction
 
-function axes_cb (h)
+function axes_cb (h, ~)
   hax = get (gcbf (), "currentaxes");
   if (! isempty (hax))
     if (strcmp (get (hax, "visible"), "on"))
@@ -372,7 +397,7 @@
   endif
 endfunction
 
-function grid_cb (h)
+function grid_cb (h, ~)
   hax = get (gcbf (), "currentaxes");
   if (! isempty (hax))
     if (strcmp (get (hax, "xgrid"), "on") && strcmp (get (hax, "ygrid"), "on"))
@@ -383,14 +408,15 @@
   endif
 endfunction
 
-function auto_cb (h)
+function auto_cb (h, ~)
   hax = get (gcbf (), "currentaxes");
   if (! isempty (hax))
     axis (hax, "auto");
   endif
 endfunction
 
-function clipboard_cb (h)
+function clipboard_cb (h, ~)
+
   hf = gcbf ();
   fname = tempname ();
   props = {"inverthardcopy", "paperposition", "paperpositionmode"};
@@ -402,4 +428,5 @@
   unwind_protect_cleanup
     set (hf, props, values);
   end_unwind_protect
+
 endfunction
--- a/scripts/plot/util/private/__gnuplot_draw_axes__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/private/__gnuplot_draw_axes__.m	Sun May 16 09:44:35 2021 +0200
@@ -56,6 +56,10 @@
   endif
 
   nd = __calc_dimensions__ (h);
+  if (nd == 2 && (any (get (h, "view") != [0, 90])))
+    ## view() only works correctly on 3-D axes in gnuplot (bug #58526).
+    nd = 3;
+  endif
 
   if (strcmp (axis_obj.dataaspectratiomode, "manual")
       && strcmp (axis_obj.xlimmode, "manual")
@@ -87,7 +91,7 @@
     dr = 1;
   endif
 
-  if (strcmp (axis_obj.activepositionproperty, "position"))
+  if (strcmp (axis_obj.positionconstraint, "innerposition"))
     if (nd == 2 || all (mod (axis_obj.view, 90) == 0))
       x = [1, 1];
     else
@@ -103,7 +107,7 @@
     fprintf (plot_stream, "set rmargin screen %.15g;\n",
              pos(1)+pos(3)/2+x(1)*pos(3)/2);
     sz_str = "";
-  else ## activepositionproperty == outerposition
+  else  # positionconstraint == outerposition
     fprintf (plot_stream, "unset tmargin;\n");
     fprintf (plot_stream, "unset bmargin;\n");
     fprintf (plot_stream, "unset lmargin;\n");
@@ -148,13 +152,13 @@
     fputs (plot_stream, "unset title;\n");
   else
     if (nd == 2)
-      t = get(axis_obj.title);
+      t = get (axis_obj.title);
       colorspec = get_text_colorspec (t.color);
-      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", t.interpreter);
+      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
+                                         t.interpreter, gnuplot_term);
       fontspec = create_fontspec (f, s, gnuplot_term);
       fprintf (plot_stream, ['set title "%s" %s %s %s;' "\n"],
-               undo_string_escapes (tt), fontspec, colorspec,
-               __do_enhanced_option__ (enhanced, t));
+               tt, fontspec, colorspec, __do_enhanced_option__ (enhanced, t));
     else
       ## Change meaning of "normalized", but it at least gives user some control
       if (! strcmp (get (axis_obj.title, "units"), "normalized"))
@@ -164,7 +168,7 @@
         unwind_protect_cleanup
         end_unwind_protect
       endif
-      t = get(axis_obj.title);
+      t = get (axis_obj.title);
       axispos = axis_obj.position;
       screenpos = t.position;
       screenpos(1) = axispos(1)+screenpos(1)*axispos(3);
@@ -182,16 +186,15 @@
       fprintf (plot_stream, "unset xlabel;\n");
       fprintf (plot_stream, "unset x2label;\n");
     else
-      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", t.interpreter);
+      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
+                                         t.interpreter, gnuplot_term);
       fontspec = create_fontspec (f, s, gnuplot_term);
       if (strcmp (axis_obj.xaxislocation, "top"))
         fprintf (plot_stream, 'set x2label "%s" %s %s %s',
-                 undo_string_escapes (tt), colorspec, fontspec,
-                 __do_enhanced_option__ (enhanced, t));
+                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       else
         fprintf (plot_stream, 'set xlabel "%s" %s %s %s',
-                 undo_string_escapes (tt), colorspec, fontspec,
-                 __do_enhanced_option__ (enhanced, t));
+                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       endif
       fprintf (plot_stream, " rotate by %f;\n", angle);
       if (strcmp (axis_obj.xaxislocation, "top"))
@@ -210,16 +213,15 @@
       fprintf (plot_stream, "unset ylabel;\n");
       fprintf (plot_stream, "unset y2label;\n");
     else
-      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", t.interpreter);
+      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
+                                         t.interpreter, gnuplot_term);
       fontspec = create_fontspec (f, s, gnuplot_term);
       if (strcmp (axis_obj.yaxislocation, "right"))
         fprintf (plot_stream, 'set y2label "%s" %s %s %s',
-                 undo_string_escapes (tt), colorspec, fontspec,
-                 __do_enhanced_option__ (enhanced, t));
+                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       else
         fprintf (plot_stream, 'set ylabel "%s" %s %s %s',
-                 undo_string_escapes (tt), colorspec, fontspec,
-                 __do_enhanced_option__ (enhanced, t));
+                 tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       endif
       fprintf (plot_stream, " rotate by %f;\n", angle);
       if (strcmp (axis_obj.yaxislocation, "right"))
@@ -237,11 +239,11 @@
     if (isempty (t.string))
       fputs (plot_stream, "unset zlabel;\n");
     else
-      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", t.interpreter);
+      [tt, f, s] = __maybe_munge_text__ (enhanced, t, "string", ...
+                                         t.interpreter, gnuplot_term);
       fontspec = create_fontspec (f, s, gnuplot_term);
       fprintf (plot_stream, 'set zlabel "%s" %s %s %s',
-               undo_string_escapes (tt), colorspec, fontspec,
-               __do_enhanced_option__ (enhanced, t));
+               tt, colorspec, fontspec, __do_enhanced_option__ (enhanced, t));
       fprintf (plot_stream, " rotate by %f;\n", angle);
     endif
   endif
@@ -625,13 +627,12 @@
             have_3d_patch(data_idx) = false;
             tmpdispname = obj.displayname;
             obj.displayname = get (obj.parent, "displayname");
-            tmp = undo_string_escapes (
-                    __maybe_munge_text__ (enhanced, obj, "displayname", hlgndntrp)
-                  );
+            tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
+                                        hlgndntrp, gnuplot_term);
             titlespec{data_idx} = ['title "' tmp '"'];
             obj.displayname = tmpdispname;
             if (! isempty (findobj (obj.parent, "-property", "format", "-depth", 0)))
-              # Place phantom errorbar data for legend
+              ## Place phantom errorbar data for legend
               data{data_idx} = NaN (4,1);
               usingclause{data_idx} = sprintf ("record=1 using ($1):($2):($3):($4)");
               switch (get (obj.parent, "format"))
@@ -646,15 +647,15 @@
                 otherwise
                   errbars = "xerrorbars";
               endswitch
-              withclause{data_idx} = sprintf ("with %s linestyle %d",
+              withclause{data_idx} = sprintf ("with %s linestyle %d", ...
                                               errbars, sidx(1));
             else
               ## Place phantom stemseries data for legend
               data{data_idx} = NaN (2,1);
               usingclause{data_idx} = sprintf ("record=1 using ($1):($2)");
               hgobj = get (obj.parent);
-              [hgstyle, hgsidx] = do_linestyle_command (hgobj, hgobj.color, data_idx,
-                                                        plot_stream);
+              [hgstyle, hgsidx] = do_linestyle_command (hgobj, hgobj.color, ...
+                                                        data_idx, plot_stream);
               withclause{data_idx} = sprintf ("with %s linestyle %d",
                                               hgstyle{1}, hgsidx(1));
             endif
@@ -675,9 +676,8 @@
         if (isempty (obj.displayname))
           titlespec{data_idx} = 'title ""';
         else
-          tmp = undo_string_escapes (
-                  __maybe_munge_text__ (enhanced, obj, "displayname", hlgndntrp)
-                );
+          tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
+                                      hlgndntrp, gnuplot_term);
           titlespec{data_idx} = ['title "' tmp '"'];
         endif
         usingclause{data_idx} = sprintf ("record=%d", numel (obj.xdata));
@@ -798,9 +798,8 @@
               if (i > 1 || isempty (obj.displayname))
                 titlespec{local_idx} = 'title ""';
               else
-                tmp = undo_string_escapes (
-                        __maybe_munge_text__ (enhanced, obj, "displayname", hlgndntrp)
-                      );
+                tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
+                                            hlgndntrp, gnuplot_term);
                 titlespec{local_idx} = ['title "' tmp '"'];
               endif
               if (isfield (obj, "facecolor"))
@@ -865,7 +864,7 @@
 
               if (nd == 3 && numel (xcol) == 3)
                 if (isnan (ccdat))
-                  ccdat = (cmap_sz + rows (addedcmap) + 1) * ones(3, 1);
+                  ccdat = (cmap_sz + rows (addedcmap) + 1) * ones (3, 1);
                   addedcmap = [addedcmap; reshape(color, 1, 3)];
                 elseif (numel (ccdat) == 1)
                   ccdat = ccdat * ones (size (zcol));
@@ -1001,7 +1000,7 @@
                 colorspec = "palette";
               elseif (columns (ccol) == 3)
                 colorspec = "lc rgb variable";
-                ccol = 255*ccol*[0x1; 0x100; 0x10000];
+                ccol = 255*ccol*double ([0x00_00_01; 0x00_01_00; 0x01_00_00]);
               endif
             else
               colorspec = sprintf ('lc rgb "#%02x%02x%02x"',
@@ -1211,9 +1210,8 @@
           parametric(data_idx) = false;
           have_cdata(data_idx) = false;
           have_3d_patch(data_idx) = false;
-          tmp = undo_string_escapes (
-                  __maybe_munge_text__ (enhanced, obj, "displayname", hlgndntrp)
-                );
+          tmp = __maybe_munge_text__ (enhanced, obj, "displayname", ...
+                                      hlgndntrp, gnuplot_term);
           titlespec{data_idx} = ['title "' tmp '"'];
           data{data_idx} = NaN (3,1);
           usingclause{data_idx} = sprintf ("record=1 using ($1):($2):($3)");
@@ -1976,7 +1974,7 @@
       endif
     endif
   endif
-  if (! isempty(pt) && isfield (obj, "markeredgecolor")
+  if (! isempty (pt) && isfield (obj, "markeredgecolor")
       && ! strcmp (obj.markeredgecolor, "none"))
     if (facesame && (strcmp (obj.markeredgecolor, "auto")
         || (isnumeric (obj.markeredgecolor)
@@ -2007,7 +2005,7 @@
           edgecolor = obj.markeredgecolor;
         else
           edgecolor = obj.color;
-        end
+        endif
         fprintf (plot_stream, ' linecolor rgb "#%02x%02x%02x"',
                  round (255*edgecolor));
       else
@@ -2264,7 +2262,8 @@
   endif
   if (strcmp (interpreter, "tex"))
     for n = 1 : numel (labels)
-      labels{n} = __tex2enhanced__ (labels{n}, fontname, false, false);
+      labels{n} = __tex2enhanced__ (labels{n}, fontname, false, false, ...
+                                    gnuplot_term);
     endfor
   elseif (strcmp (interpreter, "latex"))
     if (! warned_latex)
@@ -2295,7 +2294,7 @@
   fprintf (plot_stream, ['set format %s "%s";' "\n"], ax, fmt);
   if (strcmp (ticmode, "manual") && isempty (tics))
     fprintf (plot_stream, "unset %stics;\nunset m%stics;\n", ax, ax);
-    return
+    return;
   else
     k = 1;
     ntics = numel (tics);
@@ -2305,7 +2304,7 @@
              tickdir, ticklength, axispos, mirror);
     labels = strrep (labels, "%", "%%");
     for i = 1:ntics
-      fprintf (plot_stream, ' "%s" %.15g', labels{k++}, tics(i));
+      fprintf (plot_stream, ' "%s" %.15f', labels{k++}, tics(i));
       if (i < ntics)
         fputs (plot_stream, ", ");
       endif
@@ -2395,7 +2394,8 @@
 
 endfunction
 
-function [str, f, s] = __maybe_munge_text__ (enhanced, obj, fld, ntrp)
+function [str, f, s] = __maybe_munge_text__ (enhanced, obj, fld, ntrp, ...
+                                             gnuplot_term)
   persistent warned_latex = false;
 
   if (strcmp (fld, "string"))
@@ -2432,10 +2432,10 @@
     if (strcmp (ntrp, "tex"))
       if (iscellstr (str))
         for n = 1:numel (str)
-          str{n} = __tex2enhanced__ (str{n}, fnt, it, bld);
+          str{n} = __tex2enhanced__ (str{n}, fnt, it, bld, gnuplot_term);
         endfor
       else
-        str = __tex2enhanced__ (str, fnt, it, bld);
+        str = __tex2enhanced__ (str, fnt, it, bld, gnuplot_term);
       endif
     elseif (strcmp (ntrp, "latex"))
       if (! warned_latex)
@@ -2451,20 +2451,26 @@
 
 endfunction
 
-function str = __tex2enhanced__ (str, fnt, it, bld)
+function str = __tex2enhanced__ (str, fnt, it, bld, gnuplot_term)
   persistent sym = __setup_sym_table__ ();
   persistent flds = fieldnames (sym);
 
+  if (any (strcmp (gnuplot_term, {"postscript", "epscairo"})))
+    symtype = 1;
+  else
+    symtype = 2;
+  endif
+
   [s, e, m] = regexp (str, "\\\\([a-zA-Z]+|0)", "start", "end", "matches");
 
   for i = length (s) : -1 : 1
-    ## special case for "\0"  and replace with empty set "{/Symbol \306}'
+    ## special case for "\0"  and replace with empty set equivalent
     if (strncmp (m{i}, '\0', 2))
-      str = [str(1:s(i) - 1) '{/Symbol \306}' str(s(i) + 2:end)];
+      str = [str(1:s(i) - 1) sym.emptyset{symtype} str(s(i) + 2:end)];
     else
       f = m{i}(2:end);
       if (isfield (sym, f))
-        g = getfield (sym, f);
+        g = sym.(f){symtype};
         ## FIXME: The symbol font doesn't seem to support bold or italic
         ##if (bld)
         ##  if (it)
@@ -2528,8 +2534,8 @@
                  '{}', str(e(i) + b2(1) + 1:end)];
         endif
       elseif (strcmp (f, "fontsize"))
-        b1 = strfind (str(e(i) + 1:end),'{');
-        b2 = strfind (str(e(i) + 1:end),'}');
+        b1 = strfind (str(e (i) + 1:end),'{');
+        b2 = strfind (str(e (i) + 1:end),'}');
         if (isempty (b1) || isempty (b2))
           warning ('syntax error in \fontname argument');
         else
@@ -2541,7 +2547,7 @@
         ## like \pix, that should be translated to the symbol Pi and x
         for j = 1 : length (flds)
           if (strncmp (flds{j}, f, length (flds{j})))
-            g = getfield (sym, flds{j});
+            g = sym.(flds{j}){symtype};
             ## FIXME: The symbol font doesn't seem to support bold or italic
             ##if (bld)
             ##  if (it)
@@ -2564,7 +2570,7 @@
   ## But need to put the shorter of the two arguments first.
   ## Careful of nested {} and unprinted characters when defining
   ## shortest..  Don't have to worry about things like ^\theta as they
-  ## are already converted to ^{/Symbol q}.
+  ## are already converted.
 
   ## FIXME: This is a mess.  Is it worth it just for a "@" character?
 
@@ -2653,118 +2659,122 @@
 endfunction
 
 function sym = __setup_sym_table__ ()
+
   ## Setup the translation table for TeX to gnuplot enhanced mode.
-  sym.forall = '{/Symbol \042}';
-  sym.exists = '{/Symbol \044}';
-  sym.ni = '{/Symbol \047}';
-  sym.cong = '{/Symbol \100}';
-  sym.Delta = '{/Symbol D}';
-  sym.Phi = '{/Symbol F}';
-  sym.Gamma = '{/Symbol G}';
-  sym.vartheta = '{/Symbol J}';
-  sym.Lambda = '{/Symbol L}';
-  sym.Pi = '{/Symbol P}';
-  sym.Theta = '{/Symbol Q}';
-  sym.Sigma = '{/Symbol S}';
-  sym.varsigma = '{/Symbol V}';
-  sym.Omega = '{/Symbol W}';
-  sym.Xi = '{/Symbol X}';
-  sym.Psi = '{/Symbol Y}';
-  sym.perp = '{/Symbol \136}';
-  sym.alpha = '{/Symbol a}';
-  sym.beta = '{/Symbol b}';
-  sym.chi = '{/Symbol c}';
-  sym.delta = '{/Symbol d}';
-  sym.epsilon = '{/Symbol e}';
-  sym.phi = '{/Symbol f}';
-  sym.gamma = '{/Symbol g}';
-  sym.eta = '{/Symbol h}';
-  sym.iota = '{/Symbol i}';
-  sym.varphi = '{/Symbol j}';              # Not in OpenGL
-  sym.kappa = '{/Symbol k}';
-  sym.lambda = '{/Symbol l}';
-  sym.mu = '{/Symbol m}';
-  sym.nu = '{/Symbol n}';
-  sym.o = '{/Symbol o}';
-  sym.pi = '{/Symbol p}';
-  sym.theta = '{/Symbol q}';
-  sym.rho = '{/Symbol r}';
-  sym.sigma = '{/Symbol s}';
-  sym.tau = '{/Symbol t}';
-  sym.upsilon = '{/Symbol u}';
-  sym.varpi = '{/Symbol v}';
-  sym.omega = '{/Symbol w}';
-  sym.xi = '{/Symbol x}';
-  sym.psi = '{/Symbol y}';
-  sym.zeta = '{/Symbol z}';
-  sym.sim = '{/Symbol \176}';
-  sym.Upsilon = '{/Symbol \241}';
-  sym.prime = '{/Symbol \242}';
-  sym.leq = '{/Symbol \243}';
-  sym.infty = '{/Symbol \245}';
-  sym.clubsuit = '{/Symbol \247}';
-  sym.diamondsuit = '{/Symbol \250}';
-  sym.heartsuit = '{/Symbol \251}';
-  sym.spadesuit = '{/Symbol \252}';
-  sym.leftrightarrow = '{/Symbol \253}';
-  sym.leftarrow = '{/Symbol \254}';
-  sym.uparrow = '{/Symbol \255}';
-  sym.rightarrow = '{/Symbol \256}';
-  sym.downarrow = '{/Symbol \257}';
-  sym.circ = '{/Symbol \260}';         # degree symbol, not circ as in FLTK
-  sym.deg = '{/Symbol \260}';
-  sym.ast = '{/Symbol *}';
-  sym.pm = '{/Symbol \261}';
-  sym.geq = '{/Symbol \263}';
-  sym.times = '{/Symbol \264}';
-  sym.propto = '{/Symbol \265}';
-  sym.partial = '{/Symbol \266}';
-  sym.bullet = '{/Symbol \267}';
-  sym.div = '{/Symbol \270}';
-  sym.neq = '{/Symbol \271}';
-  sym.equiv = '{/Symbol \272}';
-  sym.approx = '{/Symbol \273}';
-  sym.ldots = '{/Symbol \274}';
-  sym.mid = '{/Symbol \275}';
-  sym.aleph = '{/Symbol \300}';
-  sym.Im = '{/Symbol \301}';
-  sym.Re = '{/Symbol \302}';
-  sym.wp = '{/Symbol \303}';
-  sym.otimes = '{/Symbol \304}';
-  sym.oplus = '{/Symbol \305}';
+  sym.forall = {'{/Symbol \042}', '∀'};
+  sym.exists = {'{/Symbol \044}', '∃'};
+  sym.ni = {'{/Symbol \047}', '∋'};
+  sym.cong = {'{/Symbol \100}', '≅'};
+  sym.Delta = {'{/Symbol D}', 'Δ'};
+  sym.Phi = {'{/Symbol F}', 'Φ'};
+  sym.Gamma = {'{/Symbol G}', 'Γ'};
+  sym.vartheta = {'{/Symbol J}', 'ϑ'};
+  sym.Lambda = {'{/Symbol L}', 'Λ'};
+  sym.Pi = {'{/Symbol P}', 'Π'};
+  sym.Theta = {'{/Symbol Q}', 'Θ'};
+  sym.Sigma = {'{/Symbol S}', 'Σ'};
+  sym.varsigma = {'{/Symbol V}', 'ς'};
+  sym.Omega = {'{/Symbol W}', 'Ω'};
+  sym.Xi = {'{/Symbol X}', 'Ξ'};
+  sym.Psi = {'{/Symbol Y}', 'Ψ'};
+  sym.perp = {'{/Symbol \136}', '⊥'};
+  sym.alpha = {'{/Symbol a}', 'α'};
+  sym.beta = {'{/Symbol b}', 'β'};
+  sym.chi = {'{/Symbol c}', 'χ'};
+  sym.delta = {'{/Symbol d}', 'δ'};
+  sym.epsilon = {'{/Symbol e}', 'ε'};
+  sym.phi = {'{/Symbol f}', 'ϕ'};
+  sym.gamma = {'{/Symbol g}', 'γ'};
+  sym.eta = {'{/Symbol h}', 'η'};
+  sym.iota = {'{/Symbol i}', 'ι'};
+  sym.varphi = {'{/Symbol j}', 'φ'};              # Not in OpenGL
+  sym.kappa = {'{/Symbol k}', 'κ'};
+  sym.lambda = {'{/Symbol l}', 'λ'};
+  sym.mu = {'{/Symbol m}', 'μ'};
+  sym.nu = {'{/Symbol n}', 'ν'};
+  sym.o = {'{/Symbol o}', 'ο'};
+  sym.pi = {'{/Symbol p}', 'π'};
+  sym.theta = {'{/Symbol q}', 'θ'};
+  sym.rho = {'{/Symbol r}', 'ρ'};
+  sym.sigma = {'{/Symbol s}', 'σ'};
+  sym.tau = {'{/Symbol t}', 'τ'};
+  sym.upsilon = {'{/Symbol u}', 'υ'};
+  sym.varpi = {'{/Symbol v}', 'ϖ'};
+  sym.omega = {'{/Symbol w}', 'ω'};
+  sym.xi = {'{/Symbol x}', 'ξ'};
+  sym.psi = {'{/Symbol y}', 'ψ'};
+  sym.zeta = {'{/Symbol z}', 'ζ'};
+  sym.sim = {'{/Symbol \176}', '∼'};
+  sym.Upsilon = {'{/Symbol \241}', 'Υ'};
+  sym.prime = {'{/Symbol \242}', '′'};
+  sym.leq = {'{/Symbol \243}', '≤'};
+  sym.infty = {'{/Symbol \245}', '∞'};
+  sym.clubsuit = {'{/Symbol \247}', '♣'};
+  sym.diamondsuit = {'{/Symbol \250}', '♢'};
+  sym.heartsuit = {'{/Symbol \251}', '♡'};
+  sym.spadesuit = {'{/Symbol \252}', '♠'};
+  sym.leftrightarrow = {'{/Symbol \253}', '↔'};
+  sym.leftarrow = {'{/Symbol \254}', '←'};
+  sym.uparrow = {'{/Symbol \255}', '↑'};
+  sym.rightarrow = {'{/Symbol \256}', '→'};
+  sym.downarrow = {'{/Symbol \257}', '↓'};
+  sym.circ = {'{/Symbol \260}', '∘'};
+  ## degree symbol, not circ as in FLTK
+  sym.deg = {'{/Symbol \260}', '°'};
+  sym.ast = {'{/Symbol *}', '∗'};
+  sym.pm = {'{/Symbol \261}', '±'};
+  sym.geq = {'{/Symbol \263}', '≥'};
+  sym.times = {'{/Symbol \264}', '×'};
+  sym.propto = {'{/Symbol \265}', '∝'};
+  sym.partial = {'{/Symbol \266}', '∂'};
+  sym.bullet = {'{/Symbol \267}', '∙'};
+  sym.div = {'{/Symbol \270}', '÷'};
+  sym.neq = {'{/Symbol \271}', '≠'};
+  sym.equiv = {'{/Symbol \272}', '≡'};
+  sym.approx = {'{/Symbol \273}', '≈'};
+  sym.ldots = {'{/Symbol \274}', '…'};
+  sym.mid = {'{/Symbol \275}', '∣'};
+  sym.aleph = {'{/Symbol \300}', 'ℵ'};
+  sym.Im = {'{/Symbol \301}', 'ℑ'};
+  sym.Re = {'{/Symbol \302}', 'ℜ'};
+  sym.wp = {'{/Symbol \303}', '℘'};
+  sym.otimes = {'{/Symbol \304}', '⊗'};
+  sym.oplus = {'{/Symbol \305}', '⊕'};
   ## empty set, not circled slash division operator as in FLTK.
-  sym.oslash = '{/Symbol \306}';
-  sym.cap = '{/Symbol \307}';
-  sym.cup = '{/Symbol \310}';
-  sym.supset = '{/Symbol \311}';
-  sym.supseteq = '{/Symbol \312}';
-  sym.subset = '{/Symbol \314}';
-  sym.subseteq = '{/Symbol \315}';
-  sym.in = '{/Symbol \316}';
-  sym.notin = '{/Symbol \317}';            # Not in OpenGL
-  sym.angle = '{/Symbol \320}';
-  sym.bigtriangledown = '{/Symbol \321}';  # Not in OpenGL
-  sym.langle = '{/Symbol \341}';
-  sym.rangle = '{/Symbol \361}';
-  sym.nabla = '{/Symbol \321}';
-  sym.prod = '{/Symbol \325}';             # Not in OpenGL
-  sym.surd = '{/Symbol \326}';
-  sym.cdot = '{/Symbol \327}';
-  sym.neg = '{/Symbol \330}';
-  sym.wedge = '{/Symbol \331}';
-  sym.vee = '{/Symbol \332}';
-  sym.Leftrightarrow = '{/Symbol \333}';   # Not in OpenGL
-  sym.Leftarrow = '{/Symbol \334}';
-  sym.Uparrow = '{/Symbol \335}';          # Not in OpenGL
-  sym.Rightarrow = '{/Symbol \336}';
-  sym.Downarrow = '{/Symbol \337}';        # Not in OpenGL
-  sym.diamond = '{/Symbol \340}';          # Not in OpenGL
-  sym.copyright = '{/Symbol \343}';
-  sym.lfloor = '{/Symbol \353}';
-  sym.lceil = '{/Symbol \351}';
-  sym.rfloor = '{/Symbol \373}';
-  sym.rceil = '{/Symbol \371}';
-  sym.int = '{/Symbol \362}';
+  sym.oslash = {'{/Symbol \306}', '⊘'};
+  sym.emptyset = {'{/Symbol \306}', '∅'};
+  sym.cap = {'{/Symbol \307}', '∩'};
+  sym.cup = {'{/Symbol \310}', '∪'};
+  sym.supset = {'{/Symbol \311}', '⊃'};
+  sym.supseteq = {'{/Symbol \312}', '⊇'};
+  sym.subset = {'{/Symbol \314}', '⊂'};
+  sym.subseteq = {'{/Symbol \315}', '⊑'};
+  sym.in = {'{/Symbol \316}', '∈'};
+  sym.notin = {'{/Symbol \317}', '∋'};            # Not in OpenGL
+  sym.angle = {'{/Symbol \320}', '∠'};
+  sym.bigtriangledown = {'{/Symbol \321}', '▽'};  # Not in OpenGL
+  sym.langle = {'{/Symbol \341}', '〈'};
+  sym.rangle = {'{/Symbol \361}', '〉'};
+  sym.nabla = {'{/Symbol \321}', '∇'};
+  sym.prod = {'{/Symbol \325}', '∏'};             # Not in OpenGL
+  sym.surd = {'{/Symbol \326}', '√'};
+  sym.cdot = {'{/Symbol \327}', '⋅'};
+  sym.neg = {'{/Symbol \330}', '¬'};
+  sym.wedge = {'{/Symbol \331}', '∧'};
+  sym.vee = {'{/Symbol \332}', '∨'};
+  sym.Leftrightarrow = {'{/Symbol \333}', '⇔'};   # Not in OpenGL
+  sym.Leftarrow = {'{/Symbol \334}', '⇐'};
+  sym.Uparrow = {'{/Symbol \335}', '⇑'};          # Not in OpenGL
+  sym.Rightarrow = {'{/Symbol \336}', '⇒'};
+  sym.Downarrow = {'{/Symbol \337}', '⇓'};        # Not in OpenGL
+  sym.diamond = {'{/Symbol \340}', '⋄'};          # Not in OpenGL
+  sym.copyright = {'{/Symbol \343}', '©'};
+  sym.lfloor = {'{/Symbol \353}', '⌊'};
+  sym.lceil = {'{/Symbol \351}', '⌈'};
+  sym.rfloor = {'{/Symbol \373}', '⌋'};
+  sym.rceil = {'{/Symbol \371}', '⌉'};
+  sym.int = {'{/Symbol \362}', '∫'};
+
 endfunction
 
 function retval = __do_enhanced_option__ (enhanced, obj)
@@ -2782,7 +2792,8 @@
 
 function do_text (stream, gpterm, enhanced, obj, hax, screenpos)
 
-  [label, f, s] = __maybe_munge_text__ (enhanced, obj, "string", obj.interpreter);
+  [label, f, s] = __maybe_munge_text__ (enhanced, obj, "string", ...
+                                        obj.interpreter, gpterm);
   fontspec = create_fontspec (f, s, gpterm);
   lpos = obj.position;
   halign = obj.horizontalalignment;
@@ -2840,13 +2851,13 @@
   endif
   fprintf (stream,
            ['set label "%s" at %s %.15e,%.15e%s %s rotate by %f offset character %f,%f %s %s front %s;' "\n"],
-           undo_string_escapes (label), units, lpos(1),
-           lpos(2), zstr, halign, angle, dx_and_dy, fontspec,
-           __do_enhanced_option__ (enhanced, obj), colorspec);
+           label, units, lpos(1), lpos(2), zstr, halign, angle, dx_and_dy,
+           fontspec, __do_enhanced_option__ (enhanced, obj), colorspec);
 
 endfunction
 
 function cdata = mapcdata (cdata, mode, clim, cmap_sz)
+
   if (ndims (cdata) == 3)
     ## True Color, clamp data to 8-bit
     clim = double (clim);
@@ -2877,4 +2888,5 @@
     endif
     cdata = max (1, min (cdata, cmap_sz));
   endif
+
 endfunction
--- a/scripts/plot/util/private/__opengl_print__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/private/__opengl_print__.m	Sun May 16 09:44:35 2021 +0200
@@ -100,7 +100,7 @@
         cmd_pstoedit = opts.pstoedit_cmd (opts, "fig", false);
         [~, ~, ext] = fileparts (opts.name);
         if (any (strcmpi (ext, {".ps", ".tex", "."})))
-          opts.name = opts.name(1:end-numel(ext));
+          opts.name = opts.name(1:end-numel (ext));
         endif
         opts.name = [opts.name ".ps"];
         cmd = sprintf ('%s | %s > "%s"', cmd_pstoedit, cmd_fig2dev, opts.name);
@@ -109,7 +109,7 @@
         cmd_fig2dev = opts.fig2dev_cmd (opts, "pstex_t");
         gl2ps_device{2} = "eps";
         pipeline{2} = sprintf ('%s | %s > "%s"', cmd_pstoedit,
-                               cmd_fig2dev, strrep(opts.name, ".ps", ".tex"));
+                               cmd_fig2dev, strrep (opts.name, ".ps", ".tex"));
       else
         ## Using svgconvert
         tmp = tempname ();
--- a/scripts/plot/util/private/__print_parse_opts__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/private/__print_parse_opts__.m	Sun May 16 09:44:35 2021 +0200
@@ -248,14 +248,7 @@
 
   if (strcmp (arg_st.renderer, "auto"))
     if (opengl_ok && strcmp (graphics_toolkit (arg_st.figure), "qt"))
-      ## "opengl" renderer only does text rotations of 0°, 90°, 180°, 270°, ...
-      ht = findall (arg_st.figure, "type", "text");
-      angles = [get(ht, "rotation"){:}];
-      if (any (mod (angles, 90)))
-        arg_st.renderer = "painters";
-      else
-        arg_st.renderer = "opengl";
-      endif
+      arg_st.renderer = "opengl";
     else
       arg_st.renderer = "painters";
     endif
@@ -424,7 +417,7 @@
     if (! (arg_st.send_to_printer || arg_st.formatted_for_printing
            || strncmp (arg_st.devopt, "pdf", 3)
            || strncmp (arg_st.devopt, "ps", 2)))
-      error ("print: the '%s' option is only valid for page formats and printers.", arg_st.resize_flag);
+      error ("print: the '%s' option is only valid for page formats and printers", arg_st.resize_flag);
     endif
   endif
 
@@ -638,21 +631,36 @@
 
   persistent binary = "";
 
+  if (isempty (binary) && ispc ())
+    ## On Windows, prefer the executable in the bin directory
+    ## (linking issue, see bug #59546)
+    bindir = getenv ("OCTAVE_BINDIR");
+    if (isempty (bindir))
+      bindir = __octave_config_info__ ("bindir");
+    endif
+
+    binary = fullfile (bindir, ...
+                       ["octave-svgconvert", ...
+                        __octave_config_info__("EXEEXT")]);
+
+    if (! exist (binary, "file"))
+      binary = "";
+    endif
+  endif
+
   if (isempty (binary))
+    ## default installation location is the archlib directory
     bindir = getenv ("OCTAVE_ARCHLIBDIR");
     if (isempty (bindir))
       bindir = __octave_config_info__ ("archlibdir");
     endif
 
-    binary = fullfile (bindir, "octave-svgconvert");
+    binary = fullfile (bindir, ...
+                       ["octave-svgconvert", ...
+                        __octave_config_info__("EXEEXT")]);
 
     if (! exist (binary, "file"))
-      if (! isunix () && exist ([binary, ".exe"], "file"))
-        ## Unix - Includes Mac OSX and Cygwin.
-        binary = [binary, ".exe"];
-      else
-        binary = "";
-      endif
+      binary = "";
     endif
   endif
 
--- a/scripts/plot/util/refresh.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/refresh.m	Sun May 16 09:44:35 2021 +0200
@@ -35,9 +35,7 @@
 
 function refresh (h)
 
-  if (nargin > 1)
-    print_usage ();
-  elseif (nargin == 1)
+  if (nargin == 1)
     if (! isfigure (h))
       error ("refresh: H must be a valid figure handle");
     endif
--- a/scripts/plot/util/refreshdata.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/refreshdata.m	Sun May 16 09:44:35 2021 +0200
@@ -74,14 +74,12 @@
     endif
     if (nargin == 1)
       workspace = "base";
-    elseif (nargin == 2)
+    else
       if (! ischar (workspace)
           || ! any (strcmpi (workspace, {"base", "caller"})))
         error ('refreshdata: WORKSPACE must be "base" or "caller"');
       endif
       workspace = tolower (workspace);
-    else
-      print_usage ();
     endif
   endif
 
--- a/scripts/plot/util/rotate.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/rotate.m	Sun May 16 09:44:35 2021 +0200
@@ -45,7 +45,7 @@
   ## default origin due to possible differences in the auto-scaling
   ## algorithm between Octave and Matlab.
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   endif
 
@@ -65,7 +65,7 @@
   endif
 
   if (! (isnumeric (direction) && numel (direction) == 3))
-    error ("rotate: invalid direction");
+    error ("rotate: invalid DIRECTION");
   endif
 
   if (! (isnumeric (alpha) && isscalar (alpha)))
@@ -181,11 +181,12 @@
 %! h2 = figure ("visible", "off");
 %! o2 = line ();
 %! o3 = text (0, 0, "foobar");
-%!error rotate ()
-%!error rotate (o1)
-%!error rotate (o1, [0,0,0])
+
+%!error <Invalid call> rotate ()
+%!error <Invalid call> rotate (o1)
+%!error <Invalid call> rotate (o1, [0,0,0])
 %!error <all handles must be children of the same axes object> rotate ([o1, o2], [0,0,0], 90)
-%!error <invalid direction> rotate (o1, "foo", 90)
+%!error <invalid DIRECTION> rotate (o1, "foo", 90)
 %!error <invalid rotation angle> rotate (o1, [0,0,0], "foo")
 %!error <invalid ORIGIN> rotate (o1, [0,0,0], 90, "foo")
 %!error rotate (o1, [0,0,0], 90, [0,0,0], 1)
--- a/scripts/plot/util/rotate3d.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/rotate3d.m	Sun May 16 09:44:35 2021 +0200
@@ -41,35 +41,31 @@
 ## @seealso{pan, zoom}
 ## @end deftypefn
 
-function rotate3d (varargin)
-
-  hfig = NaN;
-
-  nargs = nargin;
+function h = rotate3d (hfig, option)
 
-  if (nargs > 2)
-    print_usage ();
-  endif
-
-  if (nargin == 1 && nargout > 0 && isfigure (varargin{1}))
+  ## FIXME: Presumably should implement this for Matlab compatibility.
+  if (nargin == 1 && nargout > 0 && isfigure (hfig))
     error ("rotate3d: syntax 'handle = rotate3d (hfig)' not implemented");
   endif
 
-  if (nargs == 2)
-    hfig = varargin{1};
-    if (isfigure (hfig))
-      varargin(1) = [];
-      nargs -= 1;
+  if (nargin == 0)
+    hfig = gcf ();
+  else
+    if (nargin == 1)
+      option = hfig;
+      hfig = gcf ();
     else
-      error ("rotate3d: invalid figure handle HFIG");
+      if (! isfigure (hfig))
+        error ("rotate3d: invalid figure handle HFIG");
+      endif
+    endif
+
+    if (! ischar (option))
+      error ("rotate3d: OPTION must be a string");
     endif
   endif
 
-  if (isnan (hfig))
-    hfig = gcf ();
-  endif
-
-  if (nargs == 0)
+  if (nargin == 0)
     rm = get (hfig, "__rotate_mode__");
     if (strcmp (rm.Enable, "on"))
       rm.Enable = "off";
@@ -78,25 +74,17 @@
     endif
     set (hfig, "__rotate_mode__", rm);
     update_mouse_mode (hfig, rm.Enable);
-  elseif (nargs == 1)
-    arg = varargin{1};
-    if (ischar (arg))
-      switch (arg)
-        case {"on", "off"}
-          rm = get (hfig, "__rotate_mode__");
-          switch (arg)
-            case {"on", "off"}
-              rm.Enable = arg;
-              rm.Motion = "both";
-          endswitch
-          set (hfig, "__rotate_mode__", rm);
-          update_mouse_mode (hfig, arg);
-        otherwise
-          error ("rotate3d: unrecognized OPTION '%s'", arg);
-      endswitch
-    else
-      error ("rotate3d: wrong type argument '%s'", class (arg));
-    endif
+  else
+    switch (option)
+      case {"on", "off"}
+        rm = get (hfig, "__rotate_mode__");
+        rm.Enable = option;
+        rm.Motion = "both";
+        set (hfig, "__rotate_mode__", rm);
+        update_mouse_mode (hfig, option);
+      otherwise
+        error ("rotate3d: unrecognized OPTION '%s'", option);
+    endswitch
   endif
 
 endfunction
@@ -106,11 +94,10 @@
   if (strcmp (arg, "off"))
     set (hfig, "__mouse_mode__", "none");
   else
-    ## FIXME: Is there a better way other than calling these
-    ## functions to set the other mouse mode Enable fields to
-    ## "off"?
-    pan ("off");
-    zoom ("off");
+    ## FIXME: Is there a better way other than calling these functions
+    ##        to set the other mouse mode Enable fields to "off"?
+    pan (hfig, "off");
+    zoom (hfig, "off");
     set (hfig, "__mouse_mode__", "rotate");
   endif
 
--- a/scripts/plot/util/saveas.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/saveas.m	Sun May 16 09:44:35 2021 +0200
@@ -33,6 +33,14 @@
 ## are:
 ##
 ## @table @code
+##
+##   @item ofig
+##     Octave figure file format (default)
+##
+##   @item mfig
+##     Two files: Octave m-file @file{filename.m} containing code
+##     to open Octave figure file @file{filename.ofig}
+##
 ##   @item ps
 ##     PostScript
 ##
@@ -58,7 +66,7 @@
 ##
 ## If @var{fmt} is omitted it is extracted from the extension of
 ## @var{filename}.  The default format when there is no extension is
-## @qcode{"pdf"}.
+## @qcode{"ofig"}.
 ##
 ## @example
 ## @group
@@ -68,12 +76,12 @@
 ## @end group
 ## @end example
 ##
-## @seealso{print, hgsave, orient}
+## @seealso{print, savefig, hgsave, orient}
 ## @end deftypefn
 
 function saveas (h, filename, fmt)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -90,36 +98,60 @@
     fig = ancestor (h, "figure");
   endif
 
+  default_fmt = "ofig";
+
   if (nargin == 2)
     ## Attempt to infer format from filename
     [~, ~, ext] = fileparts (filename);
-    if (! isempty (ext))
-      fmt = ext(2:end);
-    else
-      fmt = "pdf";
+    if (isempty (ext))
+      ext = ["." default_fmt];
+      filename = [filename ext];
     endif
+    fmt = ext(2:end);
   endif
 
   if (nargin == 3)
     if (! ischar (fmt))
       error ("saveas: FMT must be a string");
+    elseif (isempty (fmt))
+      fmt = default_fmt;
     endif
     [~, ~, ext] = fileparts (filename);
     if (isempty (ext))
-      filename = [filename "." fmt];
+      ext = ["." fmt];
+      filename = [filename ext];
     endif
   endif
 
-  prt_opt = ["-d" tolower(fmt)];
+  fmt = tolower (fmt);
+
+  if (any (strcmp (fmt, {"ofig", "fig"})))
+    savefig (fig, filename);
+  elseif (any (strcmp (fmt, {"m", "mfig"})))
+    [d, n] = fileparts (filename);
+    mfilename = fullfile (d, [n ".m"]);
+    figfilename = fullfile (d, [n ".ofig"]);
+
+    savefig (fig, figfilename);
 
-  print (fig, filename, prt_opt);
+    fid = fopen (mfilename, "wt");
+    if (fid < 0)
+      error ("saveas: could not open '%s' for writing", mfilename);
+    endif
+    fprintf (fid, ['h = openfig ("' figfilename '");' "\n"]);
+    fclose (fid);
+  else
+    prt_opt = ["-d" fmt];
+
+    print (fig, filename, prt_opt);
+  endif
 
 endfunction
 
+
 ## Test input validation
-%!error saveas ()
-%!error saveas (1)
-%!error saveas (1,2,3,4)
+%!error <Invalid call> saveas ()
+%!error <Invalid call> saveas (1)
 %!error <H must be a graphics handle> saveas (Inf, "tst.pdf")
 %!error <FILENAME must be a string> saveas (0, 1)
 %!error <FMT must be a string> saveas (0, "tst.pdf", 1)
--- a/scripts/plot/util/struct2hdl.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/struct2hdl.m	Sun May 16 09:44:35 2021 +0200
@@ -45,12 +45,16 @@
 
 function [h, pout] = struct2hdl (s, p=[], hilev = false)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   fields = {"handle", "type", "children", "properties", "special"};
   partypes = {"root", "figure", "axes", "hggroup"};
-  othertypes = {"line", "patch", "surface", "image", "text"};
+  othertypes = {"line", "patch", "scatter", "surface", "image", "text"};
   alltypes = [partypes othertypes];
 
-  if (nargin > 3 || ! isstruct (s))
+  if (! isstruct (s))
     print_usage ();
   elseif (! all (isfield (s, fields)))
     print_usage ();
@@ -108,16 +112,22 @@
   ## change the mode to "manual" when the value is "auto".
   names = fieldnames (s.properties);
   n = strncmp (cellfun (@fliplr, names, "uniformoutput", false), "edom", 4);
-  n = (n | strcmp (names, "activepositionproperty"));
+  n = (n | strcmp (names, "positionconstraint"));
   names = [names(! n); names(n)];
   n_pos = find (strcmp (names, "position") | strcmp (names, "outerposition"));
   if (strcmp (s.type, "axes") && numel (n_pos) == 2)
-    if (strcmp (s.properties.activepositionproperty, "position"))
+    if (isfield (s.properties, "positionconstraint"))
+      positionconstraint = s.properties.positionconstraint;
+    else
+      ## loading old figure file before "positionconstraint" property was added
+      positionconstraint = s.properties.activepositionproperty;
+    endif
+    if (strcmp (positionconstraint, "outerposition"))
+      names{n_pos(1)} = "position";
+      names{n_pos(2)} = "outerposition";
+    else
       names{n_pos(1)} = "outerposition";
       names{n_pos(2)} = "position";
-    else
-      names{n_pos(1)} = "position";
-      names{n_pos(2)} = "outerposition";
     endif
   endif
   ## Set "units" property early
@@ -131,7 +141,7 @@
 
   ## Translate field names for Matlab .fig files
   ## FIXME: Is it ok to do this unconditionally?
-  if isfield (s.properties, "applicationdata")
+  if (isfield (s.properties, "applicationdata"))
     s.properties.__appdata__ = s.properties.applicationdata;
     s.properties = rmfield (s.properties, "applicationdata");
   endif
@@ -153,21 +163,29 @@
       if (strcmp (s.properties.tag, "legend"))
         s.properties.tag = "";
         s.properties.userdata = [];
-        par = gcf;
+        par = gcf ();
       elseif (strcmp (s.properties.tag, "colorbar"))
         s.properties.tag = "";
         s.properties.userdata = [];
-        par = gcf;
+        par = gcf ();
       endif
     endif
-    if (isfield (s.properties, "tightinset"))
-      s.properties = rmfield (s.properties, {"tightinset"});
+    ## remove read only properties
+    ## FIXME: Remove "interactions", "layout", "legend", "toolbar", "xaxis",
+    ## "yaxis", and "zaxis" from this list once they are implemented.
+    ro_props = {"interactions", "layout", "legend", "nextseriesindex", ...
+                "tightinset", "toolbar", "xaxis", "yaxis", "zaxis"};
+    has_ro_props = cellfun (@(x) isfield (s.properties, x), ro_props);
+    if (any (has_ro_props))
+      s.properties = rmfield (s.properties, ro_props(has_ro_props));
     endif
     [h, s] = createaxes (s, p, par);
   elseif (strcmp (s.type, "line"))
     h = createline (s, par);
   elseif (strcmp (s.type, "patch"))
     [h, s] = createpatch (s, par);
+  elseif (strcmp (s.type, "scatter"))
+    [h, s] = createscatter (s, par);
   elseif (strcmp (s.type, "text"))
     if (isfield (s.properties, "extent"))
       s.properties = rmfield (s.properties, "extent");
@@ -183,7 +201,8 @@
     [h, s, p] = createhg (s, p, par, hilev);
   elseif (any (strcmp (s.type, {"uimenu", "uicontextmenu",...
                                 "uicontrol", "uipanel", "uibuttongroup",...
-                                "uitoolbar", "uipushtool", "uitable"})))
+                                "uitoolbar", "uipushtool", "uitoggletool"...
+                                "uitable"})))
     if (isfield (s.properties, "extent"))
       s.properties = rmfield (s.properties, "extent");
     endif
@@ -216,6 +235,7 @@
 endfunction
 
 function [h, sout] = createfigure (s)
+
   ## Create figure initially invisible to speed up loading.
   opts = {"visible", "off"};
   if (isfield (s.properties, "integerhandle"))  # see also bug #53342.
@@ -232,6 +252,7 @@
   endif
   addmissingprops (h, s.properties);
   sout = s;
+
 endfunction
 
 function [h, sout] = createaxes (s, p, par)
@@ -254,10 +275,10 @@
       plty = s.properties.__plotyy_axes__;
       addproperty ("__plotyy_axes__", h, "data");
       tmp = [p [s.handle; h]];
-      tst = ismember (tmp(1:2:end), plty);
+      tst = ismember (tmp(1,:), plty);
       if (sum (tst) == numel (plty))
         for ii = 1:numel (plty)
-          plty(ii) = tmp(find (tmp == plty(ii)) + 1);
+          plty(ii) = tmp(2, find (tmp(1,:) == plty(ii)));
         endfor
         for ii = 1:numel (plty)
           set (plty(ii), "__plotyy_axes__", plty);
@@ -371,6 +392,24 @@
 
 endfunction
 
+function [h, sout] = createscatter (s, par)
+
+  if (isempty (s.properties.zdata))
+    ## 2D scatter
+    h = scatter (s.properties.xdata, s.properties.ydata);
+  else
+    ## 3D scatter
+    h = scatter3 (s.properties.xdata, s.properties.ydata, s.properties.zdata);
+  endif
+
+  set (h, "parent", par);
+  s.properties = rmfield (s.properties,
+                          {"xdata", "ydata", "zdata"});
+  addmissingprops (h, s.properties);
+  sout = s;
+
+endfunction
+
 function h = createtext (s, par)
   h = text ("parent", par);
   addmissingprops (h, s.properties);
--- a/scripts/plot/util/subplot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/subplot.m	Sun May 16 09:44:35 2021 +0200
@@ -239,7 +239,7 @@
     set (cf, "units", "pixels");
 
     ## FIXME: At the moment we force gnuplot to use the aligned mode
-    ##        which will set "activepositionproperty" to "position".
+    ##        which will set "positionconstraint" to "innerposition".
     ##        This can yield to text overlap between labels and titles.
     ##        See bug #31610.
     if (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot"))
@@ -329,7 +329,7 @@
         set (hsubplot, varargin{:});
       endif
     else
-      pval = [{"activepositionproperty", "position", ...
+      pval = [{"positionconstraint", "innerposition", ...
                "position", pos, "looseinset", li} varargin];
       if (! make_subplot)
         hsubplot = axes (pval{:});
@@ -435,7 +435,7 @@
 
 endfunction
 
-function subplot_align (h, d, rmupdate = false)
+function subplot_align (h, ~, rmupdate = false)
   persistent updating = false;
 
   if (! updating)
@@ -446,7 +446,7 @@
         rmappdata (h, "__subplotposition__");
         rmappdata (h, "__subplotouterposition__");
       endif
-      return
+      return;
     endif
 
     unwind_protect
@@ -461,7 +461,7 @@
         do_align = ! cellfun (@isempty, pos);
         pos = cell2mat (pos(do_align));
       else
-        return
+        return;
       endif
       hsubplots = children(do_align);
 
@@ -476,7 +476,7 @@
         hsubplots(! do_align) = [];
         pos(! do_align,:) = [];
       else
-        return
+        return;
       endif
 
       ## Reset outerpositions to their default value
@@ -486,7 +486,7 @@
       endif
       for ii = 1:numel (hsubplots)
         set (hsubplots(ii), "outerposition", opos(ii,:), ...
-             "activepositionproperty", "position");
+             "positionconstraint", "innerposition");
       endfor
 
       ## Compare current positions to default and compute the new ones
--- a/scripts/plot/util/zoom.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/plot/util/zoom.m	Sun May 16 09:44:35 2021 +0200
@@ -64,33 +64,27 @@
 ## Eventually we need to also support these features:
 ## @deftypefnx {} {zoom_object_handle =} zoom (@var{hfig})
 
-function zoom (varargin)
+function h = zoom (hfig, option)
 
-  nargs = nargin;
-  if (nargs > 2)
-    print_usage ();
-  endif
-
-  if (nargs == 1 && nargout > 0 && isfigure (varargin{1}))
+  ## FIXME: Presumably should implement this for Matlab compatibility.
+  if (nargin == 1 && nargout > 0 && isfigure (hfig))
     error ("zoom: syntax 'handle = zoom (hfig)' not implemented");
   endif
 
-  hfig = NaN;
-  if (nargs == 2)
-    hfig = varargin{1};
-    if (isfigure (hfig))
-      varargin(1) = [];
-      nargs -= 1;
+  if (nargin == 0)
+    hfig = gcf ();
+  else
+    if (nargin == 1)
+      option = hfig;
+      hfig = gcf ();
     else
-      error ("zoom: invalid figure handle HFIG");
+      if (! isfigure (hfig))
+        error ("zoom: invalid figure handle HFIG");
+      endif
     endif
   endif
 
-  if (isnan (hfig))
-    hfig = gcf ();
-  endif
-
-  if (nargs == 0)
+  if (nargin == 0)
     zm = get (hfig, "__zoom_mode__");
     if (strcmp (zm.Enable, "on"))
       zm.Enable = "off";
@@ -99,10 +93,9 @@
     endif
     set (hfig, "__zoom_mode__", zm);
     update_mouse_mode (hfig, zm.Enable);
-  elseif (nargs == 1)
-    arg = varargin{1};
-    if (isnumeric (arg))
-      factor = arg;
+  else
+    if (isnumeric (option))
+      factor = option;
       switch (numel (factor))
         case 2
           xfactor = factor(1);
@@ -110,10 +103,10 @@
         case 1
           xfactor = yfactor = factor;
         otherwise
-          error ("zoom: invalid FACTOR");
+          error ("zoom: FACTOR must be a 1- or 2-element vector");
       endswitch
-      if (xfactor < 0 || yfactor < 0)
-        error ("zoom: FACTOR must be greater than 1");
+      if (xfactor <= 0 || yfactor <= 0)
+        error ("zoom: FACTOR must be greater than 0");
       elseif (xfactor == 1 && yfactor == 1)
         return;
       endif
@@ -132,13 +125,13 @@
         endif
         __zoom__ (cax, mode, factor);
       endif
-    elseif (ischar (arg))
-      switch (arg)
+    elseif (ischar (option))
+      switch (option)
         case {"on", "off", "xon", "yon"}
           zm = get (hfig, "__zoom_mode__");
-          switch (arg)
+          switch (option)
             case {"on", "off"}
-              zm.Enable = arg;
+              zm.Enable = option;
               zm.Motion = "both";
             case "xon"
               zm.Enable = "on";
@@ -148,7 +141,7 @@
               zm.Motion = "vertical";
           endswitch
           set (hfig, "__zoom_mode__", zm);
-          update_mouse_mode (hfig, arg);
+          update_mouse_mode (hfig, option);
         case "out"
           cax = get (hfig, "currentaxes");
           if (! isempty (cax))
@@ -160,10 +153,10 @@
             __zoom__ (cax, "reset");
           endif
         otherwise
-          error ("zoom: unrecognized OPTION '%s'", arg);
+          error ("zoom: unrecognized OPTION '%s'", option);
       endswitch
     else
-      error ("zoom: wrong type argument '%s'", class (arg));
+      error ("zoom: OPTION must be a number or a string");
     endif
   endif
 
@@ -176,8 +169,8 @@
   else
     ## FIXME: Is there a better way other than calling these functions
     ##        to set the other mouse mode Enable fields to "off"?
-    pan ("off");
-    rotate3d ("off");
+    pan (hfig, "off");
+    rotate3d (hfig, "off");
     set (hfig, "__mouse_mode__", "zoom");
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/polynomial/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/polynomial/compan.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/compan.m	Sun May 16 09:44:35 2021 +0200
@@ -63,7 +63,7 @@
 
 function A = compan (c)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/conv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/conv.m	Sun May 16 09:44:35 2021 +0200
@@ -54,7 +54,7 @@
 
 function y = conv (a, b, shape = "full")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -128,8 +128,7 @@
 
 
 ## Test input validation
-%!error conv (1)
-%!error conv (1,2,3,4)
+%!error <Invalid call> conv (1)
 %!error <A and B must be vectors> conv ([1, 2; 3, 4], 3)
 %!error <A and B must be vectors> conv (3, [1, 2; 3, 4])
 %!error <SHAPE argument must be> conv (2, 3, "INVALID_SHAPE")
--- a/scripts/polynomial/deconv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/deconv.m	Sun May 16 09:44:35 2021 +0200
@@ -80,6 +80,7 @@
 
 endfunction
 
+
 %!test
 %! [b, r] = deconv ([3, 6, 9, 9], [1, 2, 3]);
 %! assert (b, [3, 0]);
@@ -117,22 +118,22 @@
 %! y = (10:-1:1);
 %! a = (4:-1:1);
 %! [b, r] = deconv (y, a);
-%! assert (conv (a, b) + r, y, eps)
+%! assert (conv (a, b) + r, y, eps);
 
 %!test <*51221>
 %! a = [1.92306958582241e+15, 3.20449986572221e+24, 1.34271290136344e+32, ...
 %!     2.32739765751038e+38];
 %! b = [7.33727670161595e+27, 1.05919311870816e+36, 4.56169848520627e+42];
 %! [div, rem] = deconv (a, b);
-%! assert (rem, [0, 0, -2.89443678763879e+32  -1.58695290534499e+39], -10*eps)
+%! assert (rem, [0, 0, -2.89443678763879e+32  -1.58695290534499e+39], -10*eps);
 %! a(2) = 3.204499865722215e+24;
 %! [div, rem] = deconv (a, b);
-%! assert (rem, [0, 0, -2.89443678763879e+32  -1.58695290534499e+39], -10*eps)
+%! assert (rem, [0, 0, -2.89443678763879e+32  -1.58695290534499e+39], -10*eps);
 
 %!test
 %! [b, r] = deconv ([1, 1], 1);
-%! assert (r, [0, 0])
+%! assert (r, [0, 0]);
 
 %!test
 %! [b, r] = deconv ([1; 1], 1);
-%! assert (r, [0; 0])
+%! assert (r, [0; 0]);
--- a/scripts/polynomial/mkpp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/mkpp.m	Sun May 16 09:44:35 2021 +0200
@@ -56,30 +56,26 @@
 ## @seealso{unmkpp, ppval, spline, pchip, ppder, ppint, ppjumps}
 ## @end deftypefn
 
-function pp = mkpp (x, P, d)
+function pp = mkpp (breaks, coefs, d)
 
-  ## check number of arguments
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
-  ## check x
-  if (length (x) < 2)
-    error ("mkpp: at least one interval is needed");
-  endif
-
-  if (! isvector (x))
-    error ("mkpp: x must be a vector");
+  ## Check BREAKS
+  if (! isvector (breaks))
+    error ("mkpp: BREAKS must be a vector");
+  elseif (length (breaks) < 2)
+    error ("mkpp: BREAKS must have at least one interval");
   endif
 
-  len = length (x) - 1;
-  dP = length (size (P));
+  len = length (breaks) - 1;
 
   pp = struct ("form", "pp",
-               "breaks", x(:).',
+               "breaks", breaks(:).',
                "coefs", [],
                "pieces", len,
-               "order", prod (size (P)) / len,
+               "order", prod (size (coefs)) / len,
                "dim", 1);
 
   if (nargin == 3)
@@ -88,7 +84,7 @@
   endif
 
   dim_vec = [pp.pieces * prod(pp.dim), pp.order];
-  pp.coefs = reshape (P, dim_vec);
+  pp.coefs = reshape (coefs, dim_vec);
 
 endfunction
 
--- a/scripts/polynomial/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -6,6 +6,7 @@
   %reldir%/private/__splinefit__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/compan.m \
   %reldir%/conv.m \
   %reldir%/deconv.m \
--- a/scripts/polynomial/mpoles.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/mpoles.m	Sun May 16 09:44:35 2021 +0200
@@ -58,7 +58,7 @@
 
 function [multp, indx] = mpoles (p, tol, reorder)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/padecoef.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/padecoef.m	Sun May 16 09:44:35 2021 +0200
@@ -91,7 +91,7 @@
 
 function [num, den] = padecoef (T, N = 1)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -163,7 +163,7 @@
 %! x = A \ b';
 %! k = N : -1 : 0;
 %! d_exp = [flipud(x(N + 2 : 2 * N + 1)); 1]';
-%! n_exp = flipud(x(1 : N + 1))';
+%! n_exp = flipud (x(1 : N + 1))';
 %! n_exp ./= d_exp(1);
 %! d_exp ./= d_exp(1);
 %! [n_obs, d_obs] = padecoef (T, N);
@@ -173,8 +173,7 @@
 ## PadeApproximant[Exp[-x * T], {x, 0, {n, n}}]
 
 ## Test input validation
-%!error padecoef ()
-%!error padecoef (1,2,3)
+%!error <Invalid call> padecoef ()
 %!error <T must be a non-negative scalar> padecoef ([1,2])
 %!error <T must be a non-negative scalar> padecoef ({1})
 %!error <T must be a non-negative scalar> padecoef (-1)
--- a/scripts/polynomial/pchip.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/pchip.m	Sun May 16 09:44:35 2021 +0200
@@ -75,7 +75,7 @@
 
 function ret = pchip (x, y, xi)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -177,5 +177,5 @@
 %!assert (size (yi2), [3,2,5,4])
 %!assert (squeeze (yi2(1,2,3,:)), [1/sqrt(2); 0; -1/sqrt(2);-1], 1e-14)
 
-%!error (pchip (1,2))
-%!error (pchip (1,2,3))
+%!error pchip (1,2)
+%!error pchip (1,2,3)
--- a/scripts/polynomial/poly.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/poly.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
 
 function y = poly (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -112,6 +112,5 @@
 %! y = poly (x);
 %! assert (y, [1 + 0i, -9 - 3i, 25 + 24i, -17 - 57i, -12 + 36i]);
 
-%!error poly ()
-%!error poly (1,2)
+%!error <Invalid call> poly ()
 %!error poly ([1, 2, 3; 4, 5, 6])
--- a/scripts/polynomial/polyder.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/polyder.m	Sun May 16 09:44:35 2021 +0200
@@ -41,57 +41,57 @@
 
 function [q, d] = polyder (p, a)
 
-  if (nargin == 1 || nargin == 2)
-    if (! isvector (p))
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (! isvector (p))
+    error ("polyder: argument must be a vector");
+  endif
+  if (nargin == 2)
+    if (! isvector (a))
       error ("polyder: argument must be a vector");
     endif
-    if (nargin == 2)
-      if (! isvector (a))
-        error ("polyder: argument must be a vector");
-      endif
-      if (nargout == 1)
-        ## derivative of p*a returns a single polynomial
-        q = polyder (conv (p, a));
+    if (nargout == 1)
+      ## derivative of p*a returns a single polynomial
+      q = polyder (conv (p, a));
+    else
+      ## derivative of p/a returns numerator and denominator
+      d = conv (a, a);
+      if (numel (p) == 1)
+        q = -p * polyder (a);
+      elseif (numel (a) == 1)
+        q = a * polyder (p);
       else
-        ## derivative of p/a returns numerator and denominator
-        d = conv (a, a);
-        if (numel (p) == 1)
-          q = -p * polyder (a);
-        elseif (numel (a) == 1)
-          q = a * polyder (p);
-        else
-          q = conv (polyder (p), a) - conv (p, polyder (a));
-          q = polyreduce (q);
-        endif
-
-        ## remove common factors from numerator and denominator
-        x = polygcd (q, d);
-        if (length (x) != 1)
-          q = deconv (q, x);
-          d = deconv (d, x);
-        endif
-
-        ## move all the gain into the numerator
-        q /= d(1);
-        d /= d(1);
-      endif
-    else
-      lp = numel (p);
-      if (lp == 1)
-        q = 0;
-        return;
-      elseif (lp == 0)
-        q = [];
-        return;
+        q = conv (polyder (p), a) - conv (p, polyder (a));
+        q = polyreduce (q);
       endif
 
-      ## Force P to be a row vector.
-      p = p(:).';
+      ## remove common factors from numerator and denominator
+      x = polygcd (q, d);
+      if (length (x) != 1)
+        q = deconv (q, x);
+        d = deconv (d, x);
+      endif
 
-      q = p(1:(lp-1)) .* [(lp-1):-1:1];
+      ## move all the gain into the numerator
+      q /= d(1);
+      d /= d(1);
     endif
   else
-    print_usage ();
+    lp = numel (p);
+    if (lp == 1)
+      q = 0;
+      return;
+    elseif (lp == 0)
+      q = [];
+      return;
+    endif
+
+    ## Force P to be a row vector.
+    p = p(:).';
+
+    q = p(1:(lp-1)) .* [(lp-1):-1:1];
   endif
 
 endfunction
--- a/scripts/polynomial/polyeig.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/polyeig.m	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 
 function [z, v] = polyeig (varargin)
 
-  if (nargin < 1 || nargout > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -105,8 +105,7 @@
 %! assert (norm (d), 0.0);
 
 ## Test input validation
-%!error polyeig ()
-%!error [a,b,c] = polyeig (1)
+%!error <Invalid call> polyeig ()
 %!error <coefficients must be square matrices> polyeig (ones (3,2))
 %!error <coefficients must have the same dimensions>
 %! polyeig (ones (3,3), ones (2,2))
--- a/scripts/polynomial/polyfit.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/polyfit.m	Sun May 16 09:44:35 2021 +0200
@@ -27,25 +27,33 @@
 ## @deftypefn  {} {@var{p} =} polyfit (@var{x}, @var{y}, @var{n})
 ## @deftypefnx {} {[@var{p}, @var{s}] =} polyfit (@var{x}, @var{y}, @var{n})
 ## @deftypefnx {} {[@var{p}, @var{s}, @var{mu}] =} polyfit (@var{x}, @var{y}, @var{n})
-## Return the coefficients of a polynomial @var{p}(@var{x}) of degree
-## @var{n} that minimizes the least-squares-error of the fit to the points
-## @code{[@var{x}, @var{y}]}.
+## Return the coefficients of a polynomial @var{p}(@var{x}) of degree @var{n}
+## that minimizes the least-squares-error of the fit to the points
+## @code{[@var{x}(:), @var{y}(:)]}.
 ##
-## If @var{n} is a logical vector, it is used as a mask to selectively force
-## the corresponding polynomial coefficients to be used or ignored.
+## @var{n} is typically an integer @geq{} 0 specifying the degree of the
+## approximating polynomial.  If @var{n} is a logical vector, it is used as a
+## mask to selectively force the corresponding polynomial coefficients to be
+## used or ignored.
 ##
-## The polynomial coefficients are returned in a row vector.
+## The polynomial coefficients are returned in the row vector @var{p}.  The
+## output @var{p} may be directly used with @code{polyval} to estimate values
+## using the fitted polynomial.
 ##
 ## The optional output @var{s} is a structure containing the following fields:
 ##
 ## @table @samp
-## @item R
-## Triangular factor R from the QR@tie{}decomposition.
+##
+## @item yf
+## The values of the polynomial for each value of @var{x}.
 ##
 ## @item X
 ## The @nospell{Vandermonde} matrix used to compute the polynomial
 ## coefficients.
 ##
+## @item R
+## Triangular factor R from the QR@tie{}decomposition.
+##
 ## @item C
 ## The unscaled covariance matrix, formally equal to the inverse of
 ## @var{x'}*@var{x}, but computed in a way minimizing roundoff error
@@ -56,121 +64,158 @@
 ##
 ## @item normr
 ## The norm of the residuals.
-##
-## @item yf
-## The values of the polynomial for each value of @var{x}.
 ## @end table
 ##
-## The second output may be used by @code{polyval} to calculate the
-## statistical error limits of the predicted values.  In particular, the
-## standard deviation of @var{p} coefficients is given by
+## The second output may be used by @code{polyval} to calculate the statistical
+## error limits of the predicted values.  In particular, the standard deviation
+## of @var{p} coefficients is given by
 ##
-## @code{sqrt (diag (s.C)/s.df)*s.normr}.
+## @code{sqrt (diag (@var{s.C})/@var{s.df}) * @var{s.normr}}.
 ##
-## When the third output, @var{mu}, is present the coefficients, @var{p}, are
-## associated with a polynomial in
+## When the third output, @var{mu}, is present the original data is centered
+## and scaled which can improve the numerical stability of the fit.  The
+## coefficients @var{p} are associated with a polynomial in
 ##
 ## @code{@var{xhat} = (@var{x} - @var{mu}(1)) / @var{mu}(2)} @*
 ## where @var{mu}(1) = mean (@var{x}), and @var{mu}(2) = std (@var{x}).
 ##
-## This linear transformation of @var{x} improves the numerical stability of
-## the fit.
+## Example 1 : logical @var{n} and integer @var{n}
+##
+## @example
+## @group
+## f = @@(x) x.^2 + 5;   # data-generating function
+## x = 0:5;
+## y = f (x);
+## ## Fit data to polynomial A*x^3 + B*x^1
+## p = polyfit (x, y, logical ([1, 0, 1, 0]))
+## @result{} p = [ 0.0680, 0, 4.2444, 0 ]
+## ## Fit data to polynomial using all terms up to x^3
+## p = polyfit (x, y, 3)
+## @result{} p = [ -4.9608e-17, 1.0000e+00, -3.3813e-15, 5.0000e+00 ]
+## @end group
+## @end example
+##
 ## @seealso{polyval, polyaffine, roots, vander, zscore}
 ## @end deftypefn
 
 function [p, s, mu] = polyfit (x, y, n)
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   endif
 
+  y_is_row_vector = isrow (y);
+
+  ## Reshape x & y into column vectors.
+  x = x(:);
+  y = y(:);
+
+  nx = numel (x);
+  ny = numel (y);
+  if (nx != ny)
+    error ("polyfit: X and Y must have the same number of points");
+  endif
+
   if (nargout > 2)
-    ## Normalized the x values.
+    ## Center and scale the x values.
     mu = [mean(x), std(x)];
     x = (x - mu(1)) / mu(2);
   endif
 
-  if (! size_equal (x, y))
-    error ("polyfit: X and Y must be vectors of the same size");
-  endif
-
+  ## n is the polynomial degree (an input, or deduced from the polymask size)
+  ## m is the effective number of coefficients.
   if (islogical (n))
-    polymask = n;
-    ## n is the polynomial degree as given the polymask size; m is the
-    ## effective number of used coefficients.
-    n = length (polymask) - 1; m = sum (polymask) - 1;
+    polymask = n(:).';          # force to row vector
+    n = numel (polymask) - 1;
+    m = sum (polymask) - 1;
+    pad_output = true;
   else
     if (! (isscalar (n) && n >= 0 && ! isinf (n) && n == fix (n)))
       error ("polyfit: N must be a non-negative integer");
     endif
-    polymask = logical (ones (1, n+1)); m = n;
+    polymask = true (1, n+1);
+    m = n;
+    pad_output = false;
   endif
 
-  y_is_row_vector = (rows (y) == 1);
-
-  ## Reshape x & y into column vectors.
-  l = numel (x);
-  x = x(:);
-  y = y(:);
+  if (m >= nx)
+    warning ("polyfit: degree of polynomial N is >= number of data points; solution is not unique");
+    m = nx;
+    pad_output = true;
+    ## Keep the lowest m entries in polymask
+    idx = find (polymask);
+    idx((end-m+1):end) = [];
+    polymask(idx) = false;
+  endif
 
   ## Construct the Vandermonde matrix.
-  v = vander (x, n+1);
+  X = vander (x, n+1);
+  v = X(:, polymask);
 
   ## Solve by QR decomposition.
-  [q, r, k] = qr (v(:, polymask), 0);
+  [q, r, k] = qr (v, 0);
   p = r \ (q' * y);
   p(k) = p;
 
-  if (n != m)
-    q = p; p = zeros (n+1, 1);
-    p(polymask) = q;
-  endif
-
-  if (nargout > 1)
+  if (isargout (2))
     yf = v*p;
-
     if (y_is_row_vector)
       s.yf = yf.';
     else
       s.yf = yf;
     endif
-    s.X = v;
+
+    s.X = X;
 
-    ## r.'*r is positive definite if X(:, polymask) is of full rank.
-    ## Invert it by cholinv to avoid taking the square root of squared
-    ## quantities.  If cholinv fails, then X(:, polymask) is rank deficient
-    ## and not invertible.
+    ## r.'*r is positive definite if matrix v is of full rank.  Invert it by
+    ## cholinv to avoid taking the square root of squared quantities.
+    ## If cholinv fails, then v is rank deficient and not invertible.
     try
       C = cholinv (r.'*r)(k, k);
     catch
-      C = NaN (m+1, m+1);
+      C = NaN (m, m);
     end_try_catch
 
-    if (n != m)
-      ## fill matrices if required
+    if (pad_output)
       s.X(:, ! polymask) = 0;
-      s.R = zeros (n+1, n+1); s.R(polymask, polymask) = r;
-      s.C = zeros (n+1, n+1); s.C(polymask, polymask) = C;
+      s.R = zeros (rows (r), n+1); s.R(:, polymask) = r;
+      s.C = zeros (rows (C), n+1); s.C(:, polymask) = C;
     else
       s.R = r;
       s.C = C;
     endif
-    s.df = l - m - 1;
+
+    s.df = max (0, nx - m - 1);
     s.normr = norm (yf - y);
   endif
 
-  ## Return a row vector.
-  p = p.';
+  if (pad_output)
+    ## Zero pad output
+    q = p;
+    p = zeros (n+1, 1);
+    p(polymask) = q;
+  endif
+  p = p.';  # Return a row vector.
 
 endfunction
 
 
 %!shared x
 %! x = [-2, -1, 0, 1, 2];
-%!assert (polyfit (x, x.^2+x+1, 2), [1, 1, 1], sqrt (eps))
-%!assert (polyfit (x, x.^2+x+1, 3), [0, 1, 1, 1], sqrt (eps))
-%!fail ("polyfit (x, x.^2+x+1)")
-%!fail ("polyfit (x, x.^2+x+1, [])")
+
+%!assert (polyfit (x, 3*x.^2 + 2*x + 1, 2), [3, 2, 1], 10*eps)
+%!assert (polyfit (x, 3*x.^2 + 2*x + 1, logical ([1 1 1])), [3, 2, 1], 10*eps)
+%!assert (polyfit (x, x.^2 + 2*x + 3, 3), [0, 1, 2, 3], 10*eps)
+%!assert (polyfit (x, x.^2 + 2*x + 3, logical ([0 1 1 1])), [0 1 2 3], 10*eps)
+
+## Test logical input N
+%!test
+%! x = [0:5];
+%! y = 3*x.^3 + 2*x.^2 + 4;
+%! [p, s] = polyfit (x, y, logical ([1, 0, 1, 1]));
+%! assert (p(2), 0);
+%! assert (all (p([1, 3, 4])));
+%! assert (s.df, 3);
 
 ## Test difficult case where scaling is really needed.  This example
 ## demonstrates the rather poor result which occurs when the dependent
@@ -188,25 +233,29 @@
 %! assert (s2.normr < s1.normr);
 
 %!test
-%! x = 1:4;
-%! p0 = [1i, 0, 2i, 4];
-%! y0 = polyval (p0, x);
-%! p = polyfit (x, y0, numel (p0) - 1);
-%! assert (p, p0, 1000*eps);
-
-%!test
 %! warning ("off", "Octave:nearly-singular-matrix", "local");
 %! x = 1000 + (-5:5);
 %! xn = (x - mean (x)) / std (x);
 %! pn = ones (1,5);
 %! y = polyval (pn, xn);
-%! [p, s, mu] = polyfit (x, y, numel (pn) - 1);
-%! [p2, s2] = polyfit (x, y, numel (pn) - 1);
+%! n = numel (pn) - 1;
+%! [p, s, mu] = polyfit (x, y, n);
+%! [p2, s2] = polyfit (x, y, n);
 %! assert (p, pn, s.normr);
 %! assert (s.yf, y, s.normr);
 %! assert (mu, [mean(x), std(x)]);
 %! assert (s.normr/s2.normr < sqrt (eps));
 
+## Complex polynomials
+%!test
+%! x = 1:4;
+%! p0 = [1i, 0, 2i, 4];
+%! y = polyval (p0, x);
+%! n = numel (p0) - 1;
+%! p = polyfit (x, y, n);
+%! assert (p, p0, 1000*eps);
+
+## Matrix input
 %!test
 %! x = [1, 2, 3; 4, 5, 6];
 %! y = [0, 0, 1; 1, 0, 0];
@@ -214,4 +263,88 @@
 %! expected = [0, 1, -14, 65, -112, 60] / 12;
 %! assert (p, expected, sqrt (eps));
 
-%!error <vectors of the same size> polyfit ([1, 2; 3, 4], [1, 2, 3, 4], 2)
+## Orientation of output
+%!test
+%! x = 0:5;
+%! y = x.^4 + 2*x + 5;
+%! [p, s] = polyfit (x, y, 3);
+%! assert (isrow (s.yf));
+%! [p, s] = polyfit (x, y.', 3);
+%! assert (iscolumn (s.yf));
+
+## Insufficient data for fit
+%!test
+%! x = [1, 2];
+%! y = [3, 4];
+%! ## Disable warnings entirely because there is not a specific ID to disable.
+%! wstate = warning ();
+%! unwind_protect
+%!   warning ("off", "all");
+%!   p0 = polyfit (x, y, 4);
+%!   [p1, s, mu] = polyfit (x, y, 4);
+%! unwind_protect_cleanup
+%!   warning (wstate);
+%! end_unwind_protect
+%! assert (p0, [0, 0, 0, 1, 2], 10*eps);
+%! assert (p1, [0, 0, 0, sqrt(2)/2, 3.5], 10*eps);
+%! assert (size (s.X), [2, 5]);
+%! assert (s.X(:,1:3), zeros (2,3));
+%! assert (size (s.R), [2, 5]);
+%! assert (s.R(:,1:3), zeros (2,3));
+%! assert (size (s.C), [2, 5]);
+%! assert (s.C(:,1:3), zeros (2,3));
+%! assert (s.df, 0);
+%! assert (mu, [1.5, sqrt(2)/2]);
+
+%!test
+%! x = [1, 2, 3];
+%! y = 2*x + 1;
+%! ## Disable warnings entirely because there is not a specific ID to disable.
+%! wstate = warning ();
+%! unwind_protect
+%!   warning ("off", "all");
+%!   p0 = polyfit (x, y, logical ([1, 1, 1, 0 1]));
+%!   [p1, s, mu] = polyfit (x, y, logical ([1, 1, 1, 0 1]));
+%! unwind_protect_cleanup
+%!   warning (wstate);
+%! end_unwind_protect
+%! assert (p0, [0, -2/11, 12/11, 0, 23/11], 10*eps);
+%! assert (p1, [0, 2, 0, 0, 5], 10*eps);
+%! assert (size (s.X), [3, 5]);
+%! assert (s.X(:,[1,4]), zeros (3,2));
+%! assert (size (s.R), [3, 5]);
+%! assert (s.R(:,[1,4]), zeros (3,2));
+%! assert (size (s.C), [3, 5]);
+%! assert (s.C(:,[1,4]), zeros (3,2));
+%! assert (s.df, 0);
+%! assert (mu, [2, 1]);
+
+%!test <*57964>
+%! ## Disable warnings entirely because there is not a specific ID to disable.
+%! wstate = warning ();
+%! unwind_protect
+%!   warning ("off", "all");
+%!   [p, s] = polyfit ([1,2], [3,4], 2);
+%! unwind_protect_cleanup
+%!   warning (wstate);
+%! end_unwind_protect
+%! assert (size (p), [1, 3]);
+%! assert (size (s.X), [2, 3]);
+%! assert (s.X(:,1), [0; 0]);
+%! assert (size (s.R), [2, 3]);
+%! assert (s.R(:,1), [0; 0]);
+%! assert (size (s.C), [2, 3]);
+%! assert (s.C(:,1), [0; 0]);
+
+## Test input validation
+%!error <Invalid call> polyfit ()
+%!error <Invalid call> polyfit (1)
+%!error <Invalid call> polyfit (1,2)
+%!error <X and Y must have the same number of points> polyfit ([1, 2], 1, 1)
+%!error <X and Y must have the same number of points> polyfit (1, [1, 2], 1)
+%!error <N must be a non-negative integer> polyfit (1, 2, [1,2])
+%!error <N must be a non-negative integer> polyfit (1, 2, -1)
+%!error <N must be a non-negative integer> polyfit (1, 2, Inf)
+%!error <N must be a non-negative integer> polyfit (1, 2, 1.5)
+%!test <*57964>
+%! fail ("p = polyfit ([1,2], [3,4], 4)", "warning", "solution is not unique");
--- a/scripts/polynomial/polygcd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/polygcd.m	Sun May 16 09:44:35 2021 +0200
@@ -53,39 +53,42 @@
 
 function x = polygcd (b, a, tol)
 
-  if (nargin == 2 || nargin == 3)
-    if (nargin == 2)
-      if (isa (a, "single") || isa (b, "single"))
-        tol = sqrt (eps ("single"));
-      else
-        tol = sqrt (eps);
-      endif
+  if (nargin < 2)
+    print_usage ();
+  endif
+
+  if (nargin == 2)
+    if (isa (a, "single") || isa (b, "single"))
+      tol = sqrt (eps ("single"));
+    else
+      tol = sqrt (eps);
     endif
-    if (length (a) == 1 || length (b) == 1)
-      if (a == 0)
-        x = b;
-      elseif (b == 0)
-        x = a;
-      else
-        x = 1;
-      endif
+  endif
+  ## FIXME: No input validation of tol if it was user-supplied
+
+
+  if (length (a) == 1 || length (b) == 1)
+    if (a == 0)
+      x = b;
+    elseif (b == 0)
+      x = a;
     else
-      a /= a(1);
-      while (1)
-        [d, r] = deconv (b, a);
-        nz = find (abs (r) > tol);
-        if (isempty (nz))
-          x = a;
-          break;
-        else
-          r = r(nz(1):length(r));
-        endif
-        b = a;
-        a = r / r(1);
-      endwhile
+      x = 1;
     endif
   else
-    print_usage ();
+    a /= a(1);
+    while (1)
+      [d, r] = deconv (b, a);
+      nz = find (abs (r) > tol);
+      if (isempty (nz))
+        x = a;
+        break;
+      else
+        r = r(nz(1):length (r));
+      endif
+      b = a;
+      a = r / r(1);
+    endwhile
   endif
 
 endfunction
--- a/scripts/polynomial/polyint.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/polyint.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function retval = polyint (p, k)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -79,5 +79,5 @@
 %! B = [length(A):-1:1];
 %! assert (polyint (A), [1./B, 0]);
 
-%!error polyint ()
+%!error <Invalid call> polyint ()
 %!error polyint (ones (2,2))
--- a/scripts/polynomial/polyout.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/polyout.m	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 
 function y = polyout (c, x)
 
-  if (nargin < 1) || (nargin > 2) || (nargout < 0) || (nargout > 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/polyreduce.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/polyreduce.m	Sun May 16 09:44:35 2021 +0200
@@ -32,7 +32,7 @@
 
 function p = polyreduce (c)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! isvector (c) || isempty (c))
     error ("polyreduce: C must be a non-empty vector");
@@ -54,7 +54,6 @@
 %!assert (polyreduce ([1, 0, 3]), [1, 0, 3])
 %!assert (polyreduce ([0, 0, 0]), 0)
 
-%!error polyreduce ()
-%!error polyreduce (1, 2)
+%!error <Invalid call> polyreduce ()
 %!error <C must be a non-empty vector> polyreduce ([1, 2; 3, 4])
 %!error <C must be a non-empty vector> polyreduce ([])
--- a/scripts/polynomial/polyval.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/polyval.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
 
 function [y, dy] = polyval (p, x, s = [], mu)
 
-  if (nargin < 2 || nargin > 4 || (nargout == 2 && nargin < 3))
+  if (nargin < 2 || (nargout == 2 && nargin < 3))
     print_usage ();
   endif
 
@@ -175,10 +175,9 @@
 %!assert (class (polyval ([], single ([]))), "single")
 
 ## Test input validation
-%!error polyval ()
-%!error polyval (1)
-%!error polyval (1,2,3,4,5)
-%!error [y, dy] = polyval (1, 2)
+%!error <Invalid call> polyval ()
+%!error <Invalid call> polyval (1)
+%!error <Invalid call> [y, dy] = polyval (1, 2)
 %!error <P must be a numeric floating point vector> polyval ({1, 0}, 0:10)
 %!error <P must be a numeric floating point vector> polyval (int8 ([1]), 0:10)
 %!error <P must be a numeric floating point vector> polyval ([1,0;0,1], 0:10)
--- a/scripts/polynomial/ppder.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/ppder.m	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
 
 function ppd = ppder (pp, m = 1)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/ppint.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/ppint.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function ppi = ppint (pp, c)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
   if (! (isstruct (pp) && strcmp (pp.form, "pp")))
--- a/scripts/polynomial/ppjumps.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/ppjumps.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function jumps = ppjumps (pp)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/polynomial/ppval.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/ppval.m	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
   P = reshape (P, [d, n * k]);
   P = shiftdim (P, nd);
   P = reshape (P, [n, k, d]);
-  Pidx = P(idx(:), :);  # 2D matrix size: x = coefs*prod(d), y = prod(sxi)
+  Pidx = P(idx(:), :);  # 2D matrix size: x = coefs*prod (d), y = prod (sxi)
 
   if (isvector (xi))
     Pidx = reshape (Pidx, [xn, k, d]);
@@ -139,9 +139,8 @@
 %! assert (ppval (pp, [breaks',breaks']), ret);
 
 ## Test input validation
-%!error ppval ()
-%!error ppval (1)
-%!error ppval (1,2,3)
+%!error <Invalid call> ppval ()
+%!error <Invalid call> ppval (1)
 %!error <argument must be a pp-form structure> ppval (1,2)
 %!error <argument must be a pp-form structure> ppval (struct ("a", 1), 2)
 %!error <argument must be a pp-form structure> ppval (struct ("form", "ab"), 2)
--- a/scripts/polynomial/private/__splinefit__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/private/__splinefit__.m	Sun May 16 09:44:35 2021 +0200
@@ -334,7 +334,7 @@
 
 % Return
 if isempty(constr)
-    return
+    return;
 end
 
 % Unpack constraints
--- a/scripts/polynomial/residue.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/residue.m	Sun May 16 09:44:35 2021 +0200
@@ -297,13 +297,13 @@
     pn = 1;
     for j = 1:n - 1
       pn = conv (pn, [1, -p(j)]);
-    end
+    endfor
     for j = n + 1:numel (p)
       pn = conv (pn, [1, -p(j)]);
-    end
+    endfor
     for j = 1:e(n) - 1
       pn = deconv (pn, p1);
-    end
+    endfor
     pn = r(n) * pn;
     pnum += prepad (pn, N+1, 0, 2);
   endfor
--- a/scripts/polynomial/roots.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/roots.m	Sun May 16 09:44:35 2021 +0200
@@ -84,7 +84,7 @@
 
 function r = roots (c)
 
-  if (nargin != 1 || (! isvector (c) && ! isempty (c)))
+  if (nargin < 1 || (! isvector (c) && ! isempty (c)))
     print_usage ();
   elseif (any (! isfinite (c)))
     error ("roots: inputs must not contain Inf or NaN");
@@ -135,8 +135,7 @@
 %!assert (roots ([1e-200, -1e200, 1]), 1e-200)
 %!assert (roots ([1e-200, -1e200 * 1i, 1]), -1e-200 * 1i)
 
-%!error roots ()
-%!error roots (1,2)
+%!error <Invalid call> roots ()
 %!error roots ([1, 2; 3, 4])
 %!error <inputs must not contain Inf or NaN> roots ([1 Inf 1])
 %!error <inputs must not contain Inf or NaN> roots ([1 NaN 1])
--- a/scripts/polynomial/spline.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/spline.m	Sun May 16 09:44:35 2021 +0200
@@ -228,7 +228,7 @@
 %! x = 0:10; y = sin (x);
 %! xspline = 0:0.1:10;  yspline = spline (x,y,xspline);
 %! title ("spline fit to points from sin (x)");
-%! plot (xspline,sin(xspline),"r", xspline,yspline,"g-", x,y,"b+");
+%! plot (xspline,sin (xspline),"r", xspline,yspline,"g-", x,y,"b+");
 %! legend ("original", "interpolation", "interpolation points");
 %! %--------------------------------------------------------
 %! % confirm that interpolated function matches the original
--- a/scripts/polynomial/unmkpp.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/polynomial/unmkpp.m	Sun May 16 09:44:35 2021 +0200
@@ -29,7 +29,7 @@
 ## Extract the components of a piecewise polynomial structure @var{pp}.
 ##
 ## This function is the inverse of @code{mkpp}: it extracts the inputs to
-## @code{mkpp} needed to create the piecewise polynomial structure @var{PP}.
+## @code{mkpp} needed to create the piecewise polynomial structure @var{pp}.
 ## The code below makes this relation explicit:
 ##
 ## @example
@@ -74,7 +74,7 @@
 
 function [x, P, n, k, d] = unmkpp (pp)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
   if (! (isstruct (pp) && isfield (pp, "form") && strcmp (pp.form, "pp")))
@@ -101,8 +101,7 @@
 %! assert (d, 1);
 
 ## Test input validation
-%!error unmkpp ()
-%!error unmkpp (1,2)
+%!error <Invalid call> unmkpp ()
 %!error <piecewise polynomial structure> unmkpp (1)
 %!error <piecewise polynomial structure> unmkpp (struct ("field1", "pp"))
 %!error <piecewise polynomial structure> unmkpp (struct ("form", "not_a_pp"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/prefs/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/prefs/addpref.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/prefs/addpref.m	Sun May 16 09:44:35 2021 +0200
@@ -109,9 +109,9 @@
 %!   endif
 %! end_unwind_protect
 
-%!error addpref ()
-%!error addpref (1)
-%!error addpref (1,2)
-%!error addpref (1,2,3,4)
+## Test input validation
+%!error <Invalid call> addpref ()
+%!error <Invalid call> addpref (1)
+%!error <Invalid call> addpref (1,2)
 %!error <GROUP must be a string> addpref (1, "pref1", 2)
 %!error <PREF must be a string> addpref ("group1", 1, 2)
--- a/scripts/prefs/getpref.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/prefs/getpref.m	Sun May 16 09:44:35 2021 +0200
@@ -55,10 +55,6 @@
 
 function retval = getpref (group, pref, default)
 
-  if (nargin > 3)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     retval = loadprefs ();
   elseif (nargin == 1)
@@ -151,9 +147,7 @@
 %!
 %! unwind_protect_cleanup
 %!   unlink (fullfile (tmp_home, ".octave_prefs"));
-%!   if (isfolder (tmp_home))
-%!     rmdir (tmp_home);
-%!   endif
+%!   sts = rmdir (tmp_home);
 %!   if (isempty (HOME))
 %!     unsetenv ("HOME");
 %!   else
@@ -161,6 +155,5 @@
 %!   endif
 %! end_unwind_protect
 
-%!error getpref (1,2,3,4)
 %!error <GROUP must be a string> getpref (1)
 %!error <PREF must be a string> getpref ("group1", 1, 2)
--- a/scripts/prefs/ispref.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/prefs/ispref.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function retval = ispref (group, pref = "")
 
-  if (nargin == 0 || nargin > 2)
+  if (nargin == 0)
     print_usage ();
   endif
 
@@ -98,7 +98,6 @@
 %!   endif
 %! end_unwind_protect
 
-%!error ispref ()
-%!error ispref (1,2,3)
+%!error <Invalid call> ispref ()
 %!error <GROUP must be a string> ispref (1, "pref1")
 %!error <PREF must be a string> ispref ("group1", 1)
--- a/scripts/prefs/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/prefs/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -8,6 +8,7 @@
   %reldir%/private/saveprefs.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/addpref.m \
   %reldir%/getpref.m \
   %reldir%/ispref.m \
--- a/scripts/prefs/rmpref.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/prefs/rmpref.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
 
 function rmpref (group, pref)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! ischar (group))
     error ("rmpref: GROUP must be a string");
@@ -113,7 +113,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error rmpref ()
-%!error rmpref (1,2,3)
+%!error <Invalid call> rmpref ()
 %!error <GROUP must be a string> rmpref (1)
 %!error <PREF must be a string> rmpref ("group1", 1)
--- a/scripts/prefs/setpref.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/prefs/setpref.m	Sun May 16 09:44:35 2021 +0200
@@ -96,9 +96,7 @@
 %!         "size mismatch for PREF and VAL");
 %! unwind_protect_cleanup
 %!   unlink (fullfile (tmp_home, ".octave_prefs"));
-%!   if (isfolder (tmp_home))
-%!     rmdir (tmp_home);
-%!   endif
+%!   sts = rmdir (tmp_home);
 %!   if (isempty (HOME))
 %!     unsetenv ("HOME");
 %!   else
@@ -106,9 +104,9 @@
 %!   endif
 %! end_unwind_protect
 
-%!error setpref ()
-%!error setpref (1)
-%!error setpref (1,2)
-%!error setpref (1,2,3,4)
+## Test input validation
+%!error <Invalid call> setpref ()
+%!error <Invalid call> setpref (1)
+%!error <Invalid call> setpref (1,2)
 %!error <GROUP must be a string> setpref (1, "pref1", 2)
 %!error <PREF must be a string> setpref ("group1", 1, 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/profiler/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/profiler/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/profiler/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/profexplore.m \
   %reldir%/profexport.m \
   %reldir%/profile.m \
--- a/scripts/profiler/profexplore.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/profiler/profexplore.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
   if (nargin == 0)
     data = profile ("info");
-  elseif (nargin != 1)
+  elseif (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/profiler/profexport.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/profiler/profexport.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 ## Built-in profiler.
 function profexport (dir, name = "", data)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -77,7 +77,7 @@
   endif
 
   if (! copyfile (__dataFilename ("style.css"), dir))
-    error ("profexport: failed to copy data file to directory '%s'", dir)
+    error ("profexport: failed to copy data file to directory '%s'", dir);
   endif
 
   if (isempty (name))
@@ -207,18 +207,18 @@
   template = __readTemplate ("hierarchical.html");
   entryTemplate = __readTemplate ("hierarchical_entry.html");
 
-  % Fill in basic data and parent breadcrumbs.
+  ## Fill in basic data and parent breadcrumbs.
   res = template;
   res = strrep (res, "%title", name);
   parentsStr = __hierarchicalParents (parents);
   res = strrep (res, "%parents", parentsStr);
 
-  % Set this page's counter and update parents struct with it.
+  ## Set this page's counter and update parents struct with it.
   mine = cnt++;
   parents{end}.cnt = mine;
   file = sprintf ("%s/hierarchy-%d.html", dir, mine);
 
-  % Sort children by time.
+  ## Sort children by time.
   times = -[ children.TotalTime ];
   [~, p] = sort (times);
   children = children(p);
@@ -314,7 +314,7 @@
 %! open (fullfile (dir, "index.html"));
 
 ## Test input validation
-%!error profexport ()
+%!error <Invalid call> profexport ()
 %!error profexport (1)
 %!error profexport (1, 2, 3, 4)
 %!error <DIR must be a string> profexport (5)
--- a/scripts/profiler/profile.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/profiler/profile.m	Sun May 16 09:44:35 2021 +0200
@@ -68,7 +68,7 @@
 ## Built-in profiler.
 function retval = profile (option)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -151,6 +151,6 @@
 %! assert (fieldnames (hier), {"Index"; "SelfTime"; "TotalTime"; "NumCalls"; "Children"});
 
 ## Test input validation
-%!error profile ()
+%!error <Invalid call> profile ()
 %!error profile ("on", 2)
 %!error profile ("INVALID_OPTION")
--- a/scripts/profiler/profshow.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/profiler/profshow.m	Sun May 16 09:44:35 2021 +0200
@@ -46,10 +46,6 @@
 ## Built-in profiler.
 function profshow (data, n = 20)
 
-  if (nargin > 2)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     data = profile ("info");
   elseif (nargin == 1 && ! isstruct (data))
@@ -113,7 +109,7 @@
 %! profile off;
 %! profshow (profile ("info"), 5);
 
-%!error profshow (1, 2, 3)
+## Test input validation
 %!error <N must be a positive integer> profshow (struct (), ones (2))
 %!error <N must be a positive integer> profshow (struct (), 1+i)
 %!error <N must be a positive integer> profshow (struct (), -1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/set/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/set/ismember.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/set/ismember.m	Sun May 16 09:44:35 2021 +0200
@@ -92,7 +92,7 @@
       s_idx = zeros (size (real_argout{2}));
       s_idx(tf) = min (real_argout{2}(tf), imag_argout{2}(tf));
     endif
-    return
+    return;
   endif
 
   ## lookup() does not handle logical values
@@ -294,7 +294,7 @@
 %! assert (s_idx, 2);
 %!
 %! tf = ismember ([5, 4-3j, 3+4j], 5);
-%! assert (tf, logical ([1, 0, 0]))
+%! assert (tf, logical ([1, 0, 0]));
 %! [~, s_idx] = ismember ([5, 4-3j, 3+4j], 5);
 %! assert (s_idx, [1, 0, 0]);
 %!
@@ -303,8 +303,8 @@
 %! assert (s_idx, 1);
 
 ## Test input validation
-%!error ismember ()
-%!error ismember (1)
-%!error ismember (1,2,3,4)
+%!error <Invalid call> ismember ()
+%!error <Invalid call> ismember (1)
+%!error <Invalid call> ismember (1,2,3,4)
 %!error <"stable" or "sorted" are not valid options> ismember (1,2, "sorted")
 %!error <"stable" or "sorted" are not valid options> ismember (1,2, "stable")
--- a/scripts/set/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/set/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -6,13 +6,15 @@
   %reldir%/private/validsetargs.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/intersect.m \
   %reldir%/ismember.m \
   %reldir%/powerset.m \
   %reldir%/setdiff.m \
   %reldir%/setxor.m \
   %reldir%/union.m \
-  %reldir%/unique.m
+  %reldir%/unique.m \
+  %reldir%/uniquetol.m
 
 %canon_reldir%dir = $(fcnfiledir)/set
 
--- a/scripts/set/powerset.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/set/powerset.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function p = powerset (a, byrows_arg)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -113,8 +113,7 @@
 %!assert (powerset([]), {});  # always return a cell array
 
 ## Test input validation
-%!error powerset ()
-%!error powerset (1,2,3)
+%!error <Invalid call> powerset ()
 %!error <second argument must be "rows"> powerset (1, "cols")
 %!error <"rows" not valid for cell arrays> powerset ({1}, "rows")
 %!error <cell arrays can only be used for character> powerset ({1})
--- a/scripts/set/union.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/set/union.m	Sun May 16 09:44:35 2021 +0200
@@ -91,7 +91,7 @@
       na = rows (a);
     else
       na = numel (a);
-    end
+    endif
     ia = idx(idx <= na);
     ib = idx(idx > na) - na;
   endif
@@ -211,12 +211,12 @@
 %!error <cells not supported with "rows"> union ({"a"}, {"b"}, "rows","legacy")
 %!error <A and B must be arrays or cell arrays> union (@sin, 1, "rows")
 %!error <A and B must be arrays or cell arrays> union (@sin,1,"rows","legacy")
-%!error <A and B must be 2-dimensional matrices> union (rand(2,2,2), 1, "rows")
-%!error <A and B must be 2-dimensional matrices> union (1, rand(2,2,2), "rows")
+%!error <A and B must be 2-dimensional matrices> union (rand (2,2,2), 1, "rows")
+%!error <A and B must be 2-dimensional matrices> union (1, rand (2,2,2), "rows")
 %!error <A and B must be 2-dimensional matrices>
-%! union (rand(2,2,2), 1, "rows", "legacy");
+%! union (rand (2,2,2), 1, "rows", "legacy");
 %!error <A and B must be 2-dimensional matrices>
-%! union (1, rand(2,2,2), "rows", "legacy");
+%! union (1, rand (2,2,2), "rows", "legacy");
 %!error <number of columns in A and B must match> union ([1 2], 1, "rows")
 %!error <number of columns in A and B must match> union (1, [1 2], "rows")
 %!error <number of columns in A and B must match>
--- a/scripts/set/unique.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/set/unique.m	Sun May 16 09:44:35 2021 +0200
@@ -354,7 +354,7 @@
 %! assert (j, [4; 1; 4; 3; 2]);
 
 ## Test input validation
-%!error unique ()
+%!error <Invalid call> unique ()
 %!error <X must be an array or cell array of strings> unique ({1})
 %!error <options must be strings> unique (1, 2)
 %!error <cannot specify both "first" and "last"> unique (1, "first", "last")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/set/uniquetol.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,359 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 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{c} =} uniquetol (@var{A})
+## @deftypefnx {} {@var{c} =} uniquetol (@var{A}, @var{tol})
+## @deftypefnx {} {@var{c} =} uniquetol (@dots{}, @var{property}, @var{value})
+## @deftypefnx {} {[@var{c}, @var{ia}, @var{ic}] =} uniquetol (@dots{})
+## Return the unique elements of @var{A} within tolerance @var{tol}.
+##
+## Two values, @var{x} and @var{y}, are within relative tolerance if
+## @code{abs (@var{x} - @var{y}) <= @var{tol} * max (abs (@var{A}(:)))}.
+##
+## The input @var{A} must be a floating point type (double or single).
+##
+## If @var{tol} is unspecified, the default tolerance is 1e-12 for double
+## precision input or 1e-6 for single precision input.
+##
+## The function may also be called with the following optional property/value
+## pairs.  Property/value pairs must be passed after other input arguments:
+##
+## @table @asis
+## @item @qcode{"ByRows"} (default: @code{false})
+## When true, return the unique rows of @var{A}.  @var{A} must be a 2-D array
+## to use this option.  For rows, the criteria for uniqueness is changed to
+## @code{all (abs (@var{x} - @var{y}) <= @var{tol}*max (abs (@var{A}),[],1))}
+## which compares each column component of a row against a column-specific
+## tolerance.
+##
+## @item @qcode{"DataScale"}
+## The tolerance test is changed to
+## @code{abs (@var{x} - @var{y}) <= @var{tol}*@var{DS}} where @var{DS} is a
+## scalar unless the property @qcode{"ByRows"} is true.  In that case, @var{DS}
+## can either be a scalar or a vector with a length equal to the number of
+## columns in @var{A}.  Using a value of @code{1.0} for @var{DS} will change
+## the tolerance from a relative one to an absolute tolerance.  Using a value
+## of @code{Inf} will disable testing.
+##
+## @item @qcode{"OutputAllIndices"} (default: @code{false})
+## When true, @var{ia} is a cell array (not a vector) that contains the indices
+## for @emph{all} elements in @var{A} that are within tolerance of a value in
+## @var{C}.  That is, each cell in @var{ia} corresponds to a single unique
+## value in @var{C}, and the values in each cell correspond to locations in
+## @var{A}.
+## @end table
+##
+## The output @var{c} is a row vector if the input @var{A} is a row vector.
+## For all other cases, a column vector is returned.
+##
+## The optional output @var{ia} is a column index vector such that
+## @code{@var{c} = @var{A}(@var{ia})}.  If the @qcode{"ByRows"} property is
+## true, the condition is @code{@var{c} = @var{A}(@var{ia}, :)}.  If the
+## @qcode{"OutputAllIndices"} property is true, then the values
+## @code{@var{A}(@var{ia}@{@var{i}@})} are all within tolerance of the unique
+## value @code{@var{c}(@var{i})}.
+##
+## The optional output @var{ic} is a column index vector such that
+## @code{@var{A} = @var{c}(@var{ic})} when @var{A} is a vector.  When @var{A}
+## is a matrix, @code{@var{A}(:) = @var{c}(@var{ic})}.  If the @qcode{"ByRows"}
+## property is true then @code{@var{A} = @var{c}(@var{ic},:)}.
+##
+## Example: small round-off errors require @code{uniquetol}, not @code{unique}
+##
+## @example
+## @group
+## x = [1:5];
+## ## Inverse_Function (Function (x)) should return exactly x
+## y = exp (log (x));
+## D = unique ([x, y])
+## @result{} [1.0000   2.0000   3.0000   3.0000   4.0000   5.0000   5.0000]
+## C = uniquetol ([x, y])
+## @result{} [1   2   3   4   5]
+## @end group
+## @end example
+##
+## @seealso{unique, union, intersect, setdiff, setxor, ismember}
+## @end deftypefn
+
+
+function [c, ia, ic] = uniquetol (A, varargin)
+
+  if (nargin < 1)
+    print_usage ();
+  endif
+
+  if (isempty (A))
+    c = A;
+    ia = [];
+    ic = [];
+    return;
+  endif
+
+  if (! isfloat (A))
+    error ("Octave:uniquetol:unsupported-type",
+           "uniquetol: A must be a double or single precision array");
+  endif
+
+  if (nargin == 1 || ischar (varargin{1}))
+    tol = ifelse (isa (A, "double"), 1e-12, 1e-6);
+  elseif (! (isfloat (varargin{1}) && isscalar (varargin{1})))
+    error ("Octave:uniquetol:unsupported-type",
+           "uniquetol: TOL must be a double or single precision scalar");
+  else
+    tol = varargin{1};
+    varargin(1) = [];
+  endif
+
+  if (mod (numel (varargin), 2))
+    error ("uniquetol: PROPERTY/VALUE arguments must be passed in pairs");
+  endif
+
+  by_rows = false;
+  output_all_indices = false;
+  data_scale = [];
+
+  for k = 1:2:numel (varargin)
+    if (! ischar (varargin{k}))
+      error ("uniquetol: PROPERTY must be a string");
+    endif
+
+    if (strcmpi (varargin{k}, "ByRows"))
+      by_rows = logical (varargin{k+1});
+      if (by_rows && ndims (A) > 2)
+        error ('uniquetol: A must be a 2-D array when "ByRows" is true');
+      endif
+    elseif (strcmpi (varargin{k}, "OutputAllIndices"))
+      output_all_indices = logical (varargin{k+1});
+    elseif (strcmpi (varargin{k}, "DataScale"))
+      data_scale = varargin{k+1}(:).';
+      if (! isfloat (data_scale) || any (data_scale(:) < 0)
+          || any (isnan (data_scale(:))))
+        error ("uniquetol: DataScale must be a non-NaN, positive floating point scalar or vector");
+      endif
+      cols_data_scale = columns (data_scale);
+      if (cols_data_scale != 1 && cols_data_scale != columns (A))
+        error ("uniquetol: invalid DataScale size");
+      endif
+    else
+      error ("uniquetol: unknown property '%s'", varargin{k});
+    endif
+  endfor
+
+  if (isempty (data_scale))
+    data_scale = max (abs (A(! isinf (A))(:)));
+  endif
+
+  tol *= data_scale;
+
+  if (by_rows)
+
+    nr = rows (A);
+    nc = columns (A);
+    Iall = zeros (nr, 1);
+    I = NaN (nc, 1);
+    ia = {};
+    J = NaN (nc, 1);
+    j = 1;
+    ii = 0;
+
+    for i = 1:nr
+      if (any (Iall == i))
+        continue;
+      else
+        equ = all (abs (A - A(i,:)) <= tol, 2);
+        equ(i,1) = equ(i,1) || any (! isfinite (A(i,:)), 2);
+        sumeq = sum (equ);
+        ia_tmp = find (equ);
+        if (output_all_indices)
+          ia{end+1} = ia_tmp;
+        endif
+        Iall(ii+(1:sumeq)) = ia_tmp;
+        I(j) = ia_tmp(1);
+        J(equ) = j;
+        ii += sumeq;
+        j += 1;
+      endif
+    endfor
+
+    I(isnan (I)) = [];
+    J(isnan (J)) = [];
+    c = A(I,:);
+
+    if (! output_all_indices)
+      ia = I(1:j-1);
+    endif
+    ic = J;
+
+  else
+    isrowvec = isrow (A);
+    A = A(:);
+    nr = rows (A);
+    isnanA = isnan (A);
+    anyisnanA = any (isnanA);
+    [sortA, sAi] = sort (A);
+    diffsortA = diff (sortA);
+    isinfsortA = isinf (sortA);
+    isnansortA = isnan (sortA);
+    numnan = sum (isnansortA);
+    if (any (isinfsortA))
+      sAnin = sortA(! (isinfsortA | isnansortA));
+      diffsortA(isinf (diffsortA)) = abs (sAnin(end) - sAnin(1)) + 10;
+    endif
+    csdx = cumsum (diffsortA);
+    ue = [true; diff([0; csdx-mod(csdx,tol)]) > eps(max(csdx))];
+    ueold = NaN;
+    while (any (ueold != ue))
+      ueold = ue;
+      belowtol = [false; diff(sortA(ue)) < tol];
+      if (any (belowtol))
+        needstomove = find (ue)(belowtol);
+        ue(needstomove) = false;
+        needstomove(needstomove >= nr-numnan) = [];
+        ue(needstomove+1) = true;
+      endif
+    endwhile
+    c = sortA(ue);
+    [~, sortsAi] = sort (sAi);
+    cumsumue = cumsum (ue);
+    ic = cumsumue(sortsAi);
+    if (anyisnanA)
+      findisnanA = find (isnanA);
+    else
+      findisnanA = [];
+    endif
+    if (output_all_indices)
+      nu = cumsumue(end);
+      ia = cell (1, nu);
+      for k = 1:nu
+        ia{k} = setdiff (sAi(cumsumue==k), findisnanA);
+      endfor
+    else
+      ia = sAi(ue);
+    endif
+
+    if (anyisnanA)
+      rowsc1 = rows (c) + (1:sum (isnanA));
+      c(rowsc1) = NaN;
+      ia(rowsc1) = findisnanA;
+      ic(isnanA) = rowsc1;
+    endif
+
+    ## FIXME: Matlab-compatible orientation of output
+    ## Actually, Matlab prefers row vectors (2021/03/24), but this is different
+    ## from all the other set functions which prefer column vectors.  Assume
+    ## that this is a bug in Matlab's implementation and prefer column vectors.
+    if (isrowvec)
+      c = c.';
+    endif
+
+  endif
+
+endfunction
+
+
+%!assert (uniquetol ([1 1 2; 1 2 1; 1 1 2+10*eps]), [1;2])
+%!assert (uniquetol ([1 1 2; 1 0 1; 1 1 2+10*eps], "byrows", true),
+%!        [1 1 2; 1 0 1])
+%!assert (uniquetol ([]), [])
+%!assert (uniquetol ([1]), [1])
+%!assert (uniquetol ([2, 1]), [1, 2]);
+%!assert (uniquetol ([1; 2]), [1; 2])
+%!assert (uniquetol ([-Inf, 1, NaN, Inf, NaN, Inf]), [-Inf, 1, Inf, NaN, NaN]);
+%!assert (uniquetol (zeros (1, 0)), zeros (1, 0));
+%!assert (uniquetol (zeros (1, 0), "byrows", true), zeros (1, 0))
+%!assert (uniquetol ([1,2,2,3,2,4], "byrows", true), [1,2,2,3,2,4])
+%!assert (uniquetol ([1,2,2,3,2,4]), [1,2,3,4])
+%!assert (uniquetol ([1,2,2,3,2,4].', "byrows", true), [1;2;3;4])
+%!assert (uniquetol (sparse ([2,0;2,0])), sparse ([0;2]))
+%!assert (uniquetol (sparse ([1,2;2,3])), sparse ([1;2;3]))
+%!assert (uniquetol (single ([1,2,2,3,2,4]), "byrows", true),
+%!        single ([1,2,2,3,2,4]))
+%!assert (uniquetol (single ([1,2,2,3,2,4])), single ([1,2,3,4]))
+%!assert (uniquetol (single ([1,2,2,3,2,4].'), "byrows", true),
+%!        single ([1;2;3;4]))
+
+## Matlab compatibility of output
+%!test
+%! x = 1:0.045:3;
+%! y = uniquetol (x, 0.1, "datascale", 1);
+%! assert (y(1:4), [1, 1.135, 1.27, 1.405]);
+
+## Test index vector return arguments
+%!test
+%! [c, ia, ic] = uniquetol ([1,1,2,3,3,3,4]);
+%! assert (c, [1,2,3,4]);
+%! assert (ia, [1;3;4;7]);
+%! assert (ic, [1;1;2;3;3;3;4]);
+
+## Test index vector return arguments with "ByRows"
+%!test
+%! A = [2, 3, 4; 2, 3, 4];
+%! [c, ia, ic] = uniquetol (A, "byrows", true);
+%! assert (c, [2, 3, 4]);
+%! assert (A(ia,:), c);
+%! assert (c(ic,:), A);
+
+%!test
+%! x = (2:7)'*pi;
+%! y = exp (log (x));
+%! C = uniquetol ([x; y]);
+%! assert (C, x, 1e-12);
+
+## Test "ByRows" Property
+%!test
+%! A = [0.06, 0.21, 0.38; 0.38, 0.21, 0.39; 0.54, 0.56, 0.41; 0.46, 0.52, 0.95];
+%! B = log (exp (A));
+%! C = uniquetol ([A; B], "ByRows", true);
+%! assert (C, A);
+
+## Test "DataScale" Property
+%!test
+%! x = 10^11;
+%! C = uniquetol ([x, exp(log(x))], 1e-6, "DataScale", 1);
+%! assert (C, [x, exp(log(x))]);
+
+## Test "OutputAllIndices" Property
+%!test
+%! A = [.1 .2 .3 10];
+%! [C, ia, ic] = uniquetol (A, .1, "OutputAllIndices", true);
+%! assert (C, [.1, 10]);
+%! assert (ia, {(1:3)', 4});
+%! assert (ic, [1; 1; 1; 2]);
+
+## Test input validation
+%!error <Invalid call> uniquetol ()
+%!error <A must be a double or single precision array> uniquetol (int8 (1))
+%!error <TOL must be a double .* precision> uniquetol (1, int8 (1))
+%!error <TOL must be a .* scalar> uniquetol (1, [1, 2])
+%!error <arguments must be passed in pairs> uniquetol (1, 2, "byrows")
+%!error <PROPERTY must be a string> uniquetol (1, 2, 3, "bar")
+%!error <A must be a 2-D array> uniquetol (ones(2,2,2), "byrows", true)
+%!error <DataScale must be a .* floating point> uniquetol (1, "DataScale", '1')
+%!error <DataScale must be a .* positive> uniquetol (1, "DataScale", -1)
+%!error <DataScale must be a non-NaN> uniquetol (1, "DataScale", NaN)
+%!error <invalid DataScale size> uniquetol (1, "DataScale", [1 2])
+%!error <unknown property 'foo'> uniquetol (1, "foo", "bar")
+%!error <unknown property 'foo'> uniquetol (1, 2, "foo", "bar")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/signal/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/signal/__parse_movargs__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/__parse_movargs__.m	Sun May 16 09:44:35 2021 +0200
@@ -24,10 +24,12 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{args} =} __parse_movargs__ (@var{varargin})
+## @deftypefn {} {@var{args} =} __parse_movargs__ (@var{caller}, @var{varargin})
 ##
 ## Parse arguments for movXXX functions before passing to @code{movfun}.
 ##
+## The input @var{caller} is a string with the name of the calling function
+## and is used to personalize any error messages.
 ## @seealso{movfun}
 ## @end deftypefn
 
@@ -57,7 +59,6 @@
     else
       error ("Octave:invalid-input-arg",
              [caller ": invalid input at position %d"], i);
-      args(end+1) = arg;
     endif
 
     i += 1;  # Advance to next element
--- a/scripts/signal/arch_fit.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/arch_fit.m	Sun May 16 09:44:35 2021 +0200
@@ -58,7 +58,7 @@
 
 function [a, b] = arch_fit (y, x, p, iter, gamma, a0, b0)
 
-  if (nargin < 3 || nargin == 6 || nargin > 7)
+  if (nargin < 3 || nargin == 6)
     print_usage ();
   endif
 
--- a/scripts/signal/arch_rnd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/arch_rnd.m	Sun May 16 09:44:35 2021 +0200
@@ -83,13 +83,13 @@
   y = zeros (t, 1);
 
   h(1) = a(1);
-  e(1) = sqrt (h(1)) * randn;
+  e(1) = sqrt (h(1)) * randn ();
   y(1) = b(1) + e(1);
 
   for t = 2:m
     ta   = min ([t, la]);
     h(t) = a(1) + a(2:ta) * e(t-ta+1:t-1).^2;
-    e(t) = sqrt (h(t)) * randn;
+    e(t) = sqrt (h(t)) * randn ();
     tb   = min ([t, lb]);
     y(t) = b(1) + b(2:tb) * y(t-tb+1:t-1) + e(t);
   endfor
@@ -97,7 +97,7 @@
   if (t > m)
     for t = m+1:t
       h(t) = a(1) + a(2:la) * e(t-la+1:t-1).^2;
-      e(t) = sqrt (h(t)) * randn;
+      e(t) = sqrt (h(t)) * randn ();
       y(t) = b(1) + b(2:lb) * y(t-tb+1:t-1) + e(t);
     endfor
   endif
--- a/scripts/signal/arma_rnd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/arma_rnd.m	Sun May 16 09:44:35 2021 +0200
@@ -47,15 +47,9 @@
 ## is omitted, @var{n} = 100 is used.
 ## @end deftypefn
 
-function x = arma_rnd (a, b, v, t, n)
+function x = arma_rnd (a, b, v, t, n = 100)
 
-  if (nargin == 4)
-    n = 100;
-  elseif (nargin == 5)
-    if (! isscalar (n))
-      error ("arma_rnd: N must be a scalar");
-    endif
-  else
+  if (nargin < 4)
     print_usage ();
   endif
 
@@ -67,6 +61,10 @@
     error ("arma_rnd: T must be a scalar");
   endif
 
+  if (! isscalar (n))
+    error ("arma_rnd: N must be a scalar");
+  endif
+
   ar = length (a);
   br = length (b);
 
--- a/scripts/signal/autoreg_matrix.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/autoreg_matrix.m	Sun May 16 09:44:35 2021 +0200
@@ -63,6 +63,6 @@
 %! B(:,1) = 1;
 %! assert (autoreg_matrix (A,K), B);
 
-%!error autoreg_matrix ()
-%!error autoreg_matrix (1)
+%!error <Invalid call> autoreg_matrix ()
+%!error <Invalid call> autoreg_matrix (1)
 %!error autoreg_matrix (ones (4,1), 5)
--- a/scripts/signal/bartlett.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/bartlett.m	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
 
 function c = bartlett (m)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -63,7 +63,7 @@
 %! A = bartlett (N);
 %! assert (A(ceil (N/2)), 1);
 
-%!error bartlett ()
+%!error <Invalid call> bartlett ()
 %!error bartlett (0.5)
 %!error bartlett (-1)
 %!error bartlett (ones (1,4))
--- a/scripts/signal/blackman.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/blackman.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
 
 function c = blackman (m, opt)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -90,7 +90,7 @@
 %! A = blackman (N, "periodic");
 %! assert (A(N/2 + 1), 1, 1e-6);
 
-%!error blackman ()
+%!error <Invalid call> blackman ()
 %!error blackman (0.5)
 %!error blackman (-1)
 %!error blackman (ones (1,4))
--- a/scripts/signal/detrend.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/detrend.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
 
 function y = detrend (x, p = 1)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -101,8 +101,7 @@
 %! assert (abs (y(:)) < 20*eps);
 
 ## Test input validation
-%!error detrend ()
-%!error detrend (1, 2, 3)
+%!error <Invalid call> detrend ()
 %!error detrend ("a")
 %!error detrend (true)
 %!error detrend (1, "invalid")
--- a/scripts/signal/diffpara.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/diffpara.m	Sun May 16 09:44:35 2021 +0200
@@ -46,7 +46,7 @@
 
 function [d, dd] = diffpara (x, a, b)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/fftconv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/fftconv.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function c = fftconv (x, y, n)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -102,8 +102,7 @@
 %! assert (size (conv (b,a)), [1, numel(a)+numel(b)-1]);
 
 ## Test input validation
-%!error fftconv (1)
-%!error fftconv (1,2,3,4)
+%!error <Invalid call> fftconv (1)
 %!error fftconv ([1, 2; 3, 4], 3)
 %!error fftconv (2, [])
 %!error fftconv ([1,1], [2,2] , [3, 4])
--- a/scripts/signal/fftfilt.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/fftfilt.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
   ## of two larger than N and length(b).  This could result in length
   ## one blocks, but if the user knows better ...
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -187,8 +187,7 @@
 %! assert (y0, y, 55*eps);
 
 ## Test input validation
-%!error fftfilt (1)
-%!error fftfilt (1, 2, 3, 4)
+%!error <Invalid call> fftfilt (1)
 %!error fftfilt (ones (2), 1)
 %!error fftfilt (2, ones (3,3,3))
 %!error fftfilt (2, 1, ones (2))
--- a/scripts/signal/fftshift.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/fftshift.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 
 function retval = fftshift (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -151,7 +151,6 @@
 %! assert (fftshift (y), x);
 
 ## Test input validation
-%!error fftshift ()
-%!error fftshift (1, 2, 3)
+%!error <Invalid call> fftshift ()
 %!error fftshift (0:3, -1)
 %!error fftshift (0:3, 0:3)
--- a/scripts/signal/filter2.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/filter2.m	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 
 function y = filter2 (b, x, shape)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
   if (nargin < 3)
--- a/scripts/signal/freqz.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/freqz.m	Sun May 16 09:44:35 2021 +0200
@@ -82,7 +82,7 @@
 
 function [h_r, f_r] = freqz (b, a, n, region, Fs)
 
-  if (nargin < 1 || nargin > 5)
+  if (nargin < 1)
     print_usage ();
   elseif (nargin == 1)
     ## Response of an FIR filter.
--- a/scripts/signal/freqz_plot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/freqz_plot.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function freqz_plot (w, h, freq_norm = false)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/signal/hamming.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/hamming.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function c = hamming (m, opt)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -87,7 +87,7 @@
 %! A = hamming (N, "periodic");
 %! assert (A(N/2 + 1), 1);
 
-%!error hamming ()
+%!error <Invalid call> hamming ()
 %!error hamming (0.5)
 %!error hamming (-1)
 %!error hamming (ones (1,4))
--- a/scripts/signal/hanning.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/hanning.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function c = hanning (m, opt)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -87,7 +87,7 @@
 %! A = hanning (N, "periodic");
 %! assert (A(N/2 + 1), 1);
 
-%!error hanning ()
+%!error <Invalid call> hanning ()
 %!error hanning (0.5)
 %!error hanning (-1)
 %!error hanning (ones (1,4))
--- a/scripts/signal/hurst.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/hurst.m	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 function H = hurst (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/ifftshift.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/ifftshift.m	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
 
 function retval = ifftshift (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -134,7 +134,6 @@
 %! assert (ifftshift (y), x);
 
 ## Test input validation
-%!error ifftshift ()
-%!error ifftshift (1, 2, 3)
+%!error <Invalid call> ifftshift ()
 %!error ifftshift (0:3, -1)
 %!error ifftshift (0:3, 0:3)
--- a/scripts/signal/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -9,6 +9,7 @@
   %reldir%/private/triangle_sw.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__parse_movargs__.m \
   %reldir%/arch_fit.m \
   %reldir%/arch_rnd.m \
--- a/scripts/signal/movfun.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/movfun.m	Sun May 16 09:44:35 2021 +0200
@@ -311,6 +311,7 @@
 ## Apply "shrink" boundary conditions
 ## Function is not applied to any window elements outside the original data.
 function y = shrink_bc (fcn, x, idxp, win, wlen, odim)
+
   N   = length (x);
   idx = idxp + win;
   tf  = (idx > 0) & (idx <= N);  # idx inside boundaries
@@ -324,11 +325,12 @@
     k      = idx(tf(:,i),i);
     y(i,:) = fcn (x(k));
   endfor
+
 endfunction
 
 ## Apply replacement value boundary conditions
 ## Window is padded at beginning and end with user-specified value.
-function y = replaceval_bc (fcn, x, idxp, win, wlen)
+function y = replaceval_bc (fcn, x, idxp, win, wlen, ~)
 
   persistent substitute;
 
@@ -359,7 +361,7 @@
 ## Apply "same" boundary conditions
 ## 'y' values outside window are replaced by value of 'x' at the window
 ## boundary.
-function y = same_bc (fcn, x, idxp, win)
+function y = same_bc (fcn, x, idxp, win, ~, ~)
   idx          = idxp + win;
   idx(idx < 1) = 1;
   N            = length (x);
@@ -370,7 +372,7 @@
 ## Apply "periodic" boundary conditions
 ## Window wraps around.  Window values outside data array are replaced with
 ## data from the other end of the array.
-function y = periodic_bc (fcn, x, idxp, win)
+function y = periodic_bc (fcn, x, idxp, win, ~, ~)
   N       = length (x);
   idx     = idxp + win;
   tf      = idx < 1;
@@ -600,12 +602,12 @@
 %!assert (size( movfun (@(x) [min(x), max(x)], cumsum (ones (10,5),2), 3)),
 %!        [10 5 2])
 ## outdim > dim
-%!error (movfun (@(x) [min(x), max(x)], (1:10).', 3, "Outdim", 3))
+%!error movfun (@(x) [min(x), max(x)], (1:10).', 3, "Outdim", 3)
 
 ## Test input validation
-%!error movfun ()
-%!error movfun (@min)
-%!error movfun (@min, 1)
+%!error <Invalid call> movfun ()
+%!error <Invalid call> movfun (@min)
+%!error <Invalid call> movfun (@min, 1)
 %!error <WLEN must be .* array of integers> movfun (@min, 1, {1})
 %!error <WLEN must be .* array of integers .= 0> movfun (@min, 1, -1)
 %!error <WLEN must be .* array of integers> movfun (@min, 1, 1.5)
--- a/scripts/signal/movslice.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/movslice.m	Sun May 16 09:44:35 2021 +0200
@@ -94,9 +94,8 @@
 ## FIXME: Need functional BIST tests
 
 ## Test input validation
-%!error movslice ()
-%!error movslice (1)
-%!error movslice (1,2,3)
+%!error <Invalid call> movslice ()
+%!error <Invalid call> movslice (1)
 %!error <N must be a positive integer> movslice ([1 2], 1)
 %!error <N must be a positive integer> movslice (0, 1)
 %!error <WLEN must be .* array of integers> movslice (1, {1})
--- a/scripts/signal/periodogram.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/periodogram.m	Sun May 16 09:44:35 2021 +0200
@@ -210,8 +210,8 @@
 
 
 ## Test input validation
-%!error periodogram ()
-%!error periodogram (1,2,3,4,5,6)
+%!error <Invalid call> periodogram ()
+%!error <Invalid call> periodogram (1,2,3,4,5,6)
 %!error <X must be a real or complex vector> periodogram (ones (2,2))
 %!error <WIN must be a vector.*same length> periodogram (1:5, ones (2,2))
 %!error <WIN must be a vector.*same length> periodogram (1:5, 1:6)
--- a/scripts/signal/sinc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/sinc.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 
 function result = sinc (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,4 +58,5 @@
 %!assert (sinc (1), 0,1e-6)
 %!assert (sinc (1/2), 2/pi, 1e-6)
 
-%!error sinc()
+## Test input validation
+%!error <Invalid call> sinc ()
--- a/scripts/signal/sinetone.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/sinetone.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function retval = sinetone (freq, rate = 8000, sec = 1, ampl = 64)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/sinewave.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/sinewave.m	Sun May 16 09:44:35 2021 +0200
@@ -33,20 +33,22 @@
 ## @seealso{sinetone}
 ## @end deftypefn
 
-function x = sinewave (m, n, d)
+function x = sinewave (m, n, d = 0)
 
-  if (nargin > 0 && nargin < 4)
-    if (nargin < 3)
-      d = 0;
-    endif
-    if (nargin < 2)
-      n = m;
-    endif
-    x = sin (((1 : m) + d - 1) * 2 * pi / n);
-  else
+  if (nargin < 1)
     print_usage ();
   endif
 
+  ## FIXME: No input validation of M, N, or D
+  if (nargin < 2)
+    n = m;
+  endif
+  if (nargin < 3)
+    d = 0;
+  endif
+
+  x = sin (((1 : m) + d - 1) * 2 * pi / n);
+
 endfunction
 
 
@@ -58,4 +60,4 @@
 %!assert (sinewave (1), sinewave (1, 1,0))
 %!assert (sinewave (3, 4), sinewave (3, 4, 0))
 
-%!error sinewave ()
+%!error <Invalid call> sinewave ()
--- a/scripts/signal/spectral_adf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/spectral_adf.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function retval = spectral_adf (c, win, b)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -74,7 +74,6 @@
 
 
 ## Test input validation
-%!error spectral_adf ()
-%!error spectral_adf (1, 2, 3, 4)
-%!error spectral_adf (1, 2)
-%!error spectral_adf (1, "invalid")
+%!error <Invalid call> spectral_adf ()
+%!error <WIN must be a string> spectral_adf (1, 2)
+%!error <unable to find function for @invalid_lw> spectral_adf (1, "invalid")
--- a/scripts/signal/spectral_xdf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/spectral_xdf.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function retval = spectral_xdf (x, win, b)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -76,7 +76,6 @@
 
 
 ## Test input validation
-%!error spectral_xdf ()
-%!error spectral_xdf (1, 2, 3, 4)
-%!error spectral_xdf (1, 2)
-%!error spectral_xdf (1, "invalid")
+%!error <Invalid call> spectral_xdf ()
+%!error <WIN must be a string> spectral_xdf (1, 2)
+%!error <unable to find function for @invalid_sw> spectral_xdf (1, "invalid")
--- a/scripts/signal/spencer.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/spencer.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function retval = spencer (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/stft.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/stft.m	Sun May 16 09:44:35 2021 +0200
@@ -66,7 +66,7 @@
 
 function [y, c] = stft (x, win_size = 80, inc = 24, num_coef = 64, win_type = 1)
 
-  if (nargin < 1 || nargin > 5)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/signal/unwrap.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/unwrap.m	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,7 @@
 
 function retval = unwrap (x, tol, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -152,6 +152,5 @@
 %! assert (diff (unwrap (B), 1) < 2*pi, true (1, length (B)-1));
 
 ## Test input validation
-%!error unwrap ()
-%!error unwrap (1,2,3,4)
+%!error <Invalid call> unwrap ()
 %!error unwrap ("foo")
--- a/scripts/signal/yulewalker.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/signal/yulewalker.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function [a, v] = yulewalker (c)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/sparse/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/sparse/bicg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/bicg.m	Sun May 16 09:44:35 2021 +0200
@@ -236,7 +236,7 @@
   endif
   norm_b = norm (b, 2);
 
-  if (norm_b == 0)  # the only (only iff det(A) == 0) solution is x = 0
+  if (norm_b == 0)  # the only (only iff det (A) == 0) solution is x = 0
     if (nargout < 2)
       printf ("The right hand side vector is all zero so bicg\n")
       printf ("returned an all zero solution without iterating.\n")
@@ -258,7 +258,7 @@
   resvec(1) = norm (r0, 2);
 
   try
-    warning ("error", "Octave:singular-matrix", "local")
+    warning ("error", "Octave:singular-matrix", "local");
     prec_r0 = M1fun (r0, "notransp", varargin{:});  # r0 preconditioned
     prec_s0 = s0;
     prec_r0 = M2fun (prec_r0, "notransp", varargin{:});
@@ -276,7 +276,7 @@
     alpha = (s0' * prec_r0);
     if (abs (prod_qv) <= eps * abs (alpha))
       flag = 4;
-      break
+      break;
     endif
     alpha ./= prod_qv;
     x += alpha * p;
--- a/scripts/sparse/bicgstab.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/bicgstab.m	Sun May 16 09:44:35 2021 +0200
@@ -213,14 +213,14 @@
   ## Check consistency and  type of A, M1, M2
   [Afun, M1fun, M2fun] =  __alltohandles__ (A, b, M1, M2, "bicgstab");
 
-  # Check if input tol are empty (set them to default if necessary)
+  ## Check if input tol are empty (set them to default if necessary)
   [tol, maxit, x0] = __default__input__ ({1e-06, min(rows(b), 20), ...
-                    zeros(rows(b), 1)}, tol, maxit, x0);
+                    zeros(rows (b), 1)}, tol, maxit, x0);
 
   norm_b = norm (b, 2);
   if (norm_b == 0)
     if (nargout < 2)
-      printf("The right hand side vector is all zero so bicgstab \n")
+      printf ("The right hand side vector is all zero so bicgstab \n")
       printf ("returned an all zero solution without iterating.\n")
     endif
     x_min = zeros (numel (b), 1);
@@ -228,7 +228,7 @@
     flag = 0;
     resvec = 0;
     relres = 0;
-    return
+    return;
   endif
 
   ## Double maxit to mind also the "half iterations"
@@ -248,7 +248,7 @@
 
   ## To check if the preconditioners are singular or they have some NaN
   try
-    warning("error", "Octave:singular-matrix", "local");
+    warning ("error", "Octave:singular-matrix", "local");
     p_hat = feval (M1fun, p, varargin{:});
     p_hat = feval (M2fun, p_hat, varargin{:});
   catch
@@ -270,7 +270,7 @@
     if (resvec (iter + 1) <= real_tol) # reached the tol
       x_min = x;
       iter_min = iter;
-      break
+      break;
     elseif (resvec (iter + 1) <= resvec (iter_min + 1)) # Found min residual
       x_min = x;
       iter_min = iter;
@@ -293,7 +293,7 @@
     endif
     if (norm (x - x_pr) <= norm (x) * eps)
       flag = 3;
-      break
+      break;
     endif
     x_pr = x;
     rho_2 = rho_1;
@@ -309,7 +309,7 @@
   endwhile
   resvec = resvec (1:iter+1,1);
 
-  relres = resvec (iter_min + 1) / norm_b; ## I set the relative residual
+  relres = resvec (iter_min + 1) / norm_b;  # I set the relative residual
   iter /=  2;
   iter_min /= 2;
 
--- a/scripts/sparse/cgs.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/cgs.m	Sun May 16 09:44:35 2021 +0200
@@ -199,12 +199,12 @@
   [Afun, M1fun, M2fun] = __alltohandles__ (A, b, M1, M2, "cgs");
 
   [tol, maxit, x0] = __default__input__ ({1e-06, min( rows(b), 20), ...
-                                          zeros(size(b))}, tol, maxit, x0);
+                                          zeros(size (b))}, tol, maxit, x0);
 
   norm_b = norm (b, 2);
   if (norm_b == 0)
     if (nargout < 2)
-      printf("The right hand side vector is all zero so cgs \n")
+      printf ("The right hand side vector is all zero so cgs \n")
       printf ("returned an all zero solution without iterating.\n")
     endif
     x_min = zeros (numel (b), 1);
@@ -212,7 +212,7 @@
     flag = 0;
     resvec = 0;
     relres = 0;
-    return
+    return;
   endif
 
   resvec = zeros (maxit, 1); # Preallocation of resvec
@@ -229,7 +229,7 @@
   rho_1 = rr' * r0;
 
   try
-    warning ("error","Octave:singular-matrix","local")
+    warning ("error","Octave:singular-matrix","local");
     p_hat = feval (M1fun, p, varargin{:});
     p_hat = feval (M2fun, p_hat, varargin {:});
   catch
@@ -252,7 +252,7 @@
     r0 -= alpha* feval (Afun, u_hat, varargin{:});
     iter += 1;
     resvec (iter + 1) = norm (r0, 2);
-    if (norm (x - x_pr, 2) <= norm(x, 2) * eps) # Stagnation
+    if (norm (x - x_pr, 2) <= norm (x, 2) * eps) # Stagnation
       flag = 3;
       break;
     endif
@@ -379,7 +379,7 @@
 %! M1_fun = @(z) M1 \ z;
 %! M2_fun = @(z) M2 \ z;
 %! [x, flag] = cgs (A,b);
-%! assert(flag, 0);
+%! assert (flag, 0);
 %! [x, flag] = cgs (A, b, [], maxit, M1, M2);
 %! assert (flag, 0);
 %! [x, flag] = cgs (A, b, [], maxit, M1_fun, M2_fun);
--- a/scripts/sparse/colperm.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/colperm.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function p = colperm (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/sparse/eigs.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/eigs.m	Sun May 16 09:44:35 2021 +0200
@@ -32,23 +32,18 @@
 ## @deftypefnx {} {@var{d} =} eigs (@var{A}, @var{B}, @var{k})
 ## @deftypefnx {} {@var{d} =} eigs (@var{A}, @var{B}, @var{k}, @var{sigma})
 ## @deftypefnx {} {@var{d} =} eigs (@var{A}, @var{B}, @var{k}, @var{sigma}, @var{opts})
-## @deftypefnx {} {@var{d} =} eigs (@var{af}, @var{n})
-## @deftypefnx {} {@var{d} =} eigs (@var{af}, @var{n}, @var{B})
-## @deftypefnx {} {@var{d} =} eigs (@var{af}, @var{n}, @var{k})
-## @deftypefnx {} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k})
-## @deftypefnx {} {@var{d} =} eigs (@var{af}, @var{n}, @var{k}, @var{sigma})
-## @deftypefnx {} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k}, @var{sigma})
-## @deftypefnx {} {@var{d} =} eigs (@var{af}, @var{n}, @var{k}, @var{sigma}, @var{opts})
-## @deftypefnx {} {@var{d} =} eigs (@var{af}, @var{n}, @var{B}, @var{k}, @var{sigma}, @var{opts})
-## @deftypefnx {} {[@var{V}, @var{d}] =} eigs (@var{A}, @dots{})
-## @deftypefnx {} {[@var{V}, @var{d}] =} eigs (@var{af}, @var{n}, @dots{})
-## @deftypefnx {} {[@var{V}, @var{d}, @var{flag}] =} eigs (@var{A}, @dots{})
-## @deftypefnx {} {[@var{V}, @var{d}, @var{flag}] =} eigs (@var{af}, @var{n}, @dots{})
-## Calculate a limited number of eigenvalues and eigenvectors of @var{A},
-## based on a selection criteria.
-##
-## The number of eigenvalues and eigenvectors to calculate is given by
-## @var{k} and defaults to 6.
+## @deftypefnx {} {@var{d} =} eigs (@var{Af}, @var{n})
+## @deftypefnx {} {@var{d} =} eigs (@var{Af}, @var{n}, @var{k})
+## @deftypefnx {} {@var{d} =} eigs (@var{Af}, @var{n}, @var{k}, @var{sigma})
+## @deftypefnx {} {@var{d} =} eigs (@var{Af}, @var{n}, @var{k}, @var{sigma}, @var{opts})
+## @deftypefnx {} {@var{d} =} eigs (@var{Af}, @var{n}, @var{B})
+## @deftypefnx {} {@var{d} =} eigs (@var{Af}, @var{n}, @var{B}, @var{k})
+## @deftypefnx {} {@var{d} =} eigs (@var{Af}, @var{n}, @var{B}, @var{k}, @var{sigma})
+## @deftypefnx {} {@var{d} =} eigs (@var{Af}, @var{n}, @var{B}, @var{k}, @var{sigma}, @var{opts})
+## @deftypefnx {} {[@var{V}, @var{D}] =} eigs (@dots{})
+## @deftypefnx {} {[@var{V}, @var{D}, @var{flag}] =} eigs (@dots{})
+## Calculate a limited number of eigenvalues and eigenvectors based on a
+## selection criteria.
 ##
 ## By default, @code{eigs} solve the equation
 ## @tex
@@ -73,10 +68,20 @@
 ## @code{A * v = lambda * B * v}.
 ## @end ifinfo
 ##
+## The input @var{A} is a square matrix of dimension @var{n}-by-@var{n}.
+## Typically, @var{A} is also large and sparse.
+##
+## The input @var{B} for the generalized eigenvalue problem is a square matrix
+## with the same size as @var{A} (@var{n}-by-@var{n}).  Typically, @var{B} is
+## also large and sparse.
+##
+## The number of eigenvalues and eigenvectors to calculate is given by @var{k}
+## and defaults to 6.
+##
 ## The argument @var{sigma} determines which eigenvalues are returned.
 ## @var{sigma} can be either a scalar or a string.  When @var{sigma} is a
 ## scalar, the @var{k} eigenvalues closest to @var{sigma} are returned.  If
-## @var{sigma} is a string, it must have one of the following values.
+## @var{sigma} is a string, it must be one of the following values.
 ##
 ## @table @asis
 ## @item @nospell{@qcode{"lm"}}
@@ -85,13 +90,13 @@
 ## @item @nospell{@qcode{"sm"}}
 ## Smallest Magnitude.
 ##
-## @item @qcode{"la"}
+## @item @nospell{@qcode{"la"}}
 ## Largest Algebraic (valid only for real symmetric problems).
 ##
 ## @item @nospell{@qcode{"sa"}}
 ## Smallest Algebraic (valid only for real symmetric problems).
 ##
-## @item @qcode{"be"}
+## @item @nospell{@qcode{"be"}}
 ## Both Ends, with one more from the high-end if @var{k} is odd (valid only for
 ## real symmetric problems).
 ##
@@ -113,13 +118,14 @@
 ##
 ## @table @code
 ## @item issym
-## If @var{af} is given, then flags whether the function @var{af} defines a
-## symmetric problem.  It is ignored if @var{A} is given.  The default is
-## false.
+## If @var{Af} is given then this flag (true/false) determines whether the
+## function @var{Af} defines a symmetric problem.  It is ignored if a matrix
+## @var{A} is given.  The default is false.
 ##
 ## @item isreal
-## If @var{af} is given, then flags whether the function @var{af} defines a
-## real problem.  It is ignored if @var{A} is given.  The default is true.
+## If @var{Af} is given then this flag (true/false) determines whether the
+## function @var{Af} defines a real problem.  It is ignored if a matrix @var{A}
+## is given.  The default is true.
 ##
 ## @item tol
 ## Defines the required convergence tolerance, calculated as
@@ -135,35 +141,37 @@
 ## to @var{n}.  The default value is @code{2 * @var{k}}.
 ##
 ## @item v0
-## The starting vector for the algorithm.  An initial vector close to the
-## final vector will speed up convergence.  The default is for @sc{arpack}
-## to randomly generate a starting vector.  If specified, @code{v0} must be
-## an @var{n}-by-1 vector where @code{@var{n} = rows (@var{A})}
+## The starting vector for the algorithm.  An initial vector close to the final
+## vector will speed up convergence.  The default is for @sc{arpack} to
+## randomly generate a starting vector.  If specified, @code{v0} must be
+## an @var{n}-by-1 vector where @code{@var{n} = rows (@var{A})}.
 ##
 ## @item disp
 ## The level of diagnostic printout (0|1|2).  If @code{disp} is 0 then
 ## diagnostics are disabled.  The default value is 0.
 ##
 ## @item cholB
-## Flag if @code{chol (@var{B})} is passed rather than @var{B}.  The default is
-## false.
+## If the generalized eigenvalue problem is being calculated, this flag
+## (true/false) specifies whether the @var{B} input represents
+## @code{chol (@var{B})} or simply the matrix @var{B}.  The default is false.
 ##
 ## @item permB
-## The permutation vector of the Cholesky@tie{}factorization of @var{B} if
-## @code{cholB} is true.  It is obtained by @code{[R, ~, permB] =
-## chol (@var{B}, @qcode{"vector"})}.  The default is @code{1:@var{n}}.
+## The permutation vector of the Cholesky@tie{}factorization for @var{B} if
+## @code{cholB} is true.  It is obtained by
+## @code{[R, ~, permB] = chol (@var{B}, @qcode{"vector"})}.  The default is
+## @code{1:@var{n}}.
 ##
 ## @end table
 ##
-## It is also possible to represent @var{A} by a function denoted @var{af}.
-## @var{af} must be followed by a scalar argument @var{n} defining the length
-## of the vector argument accepted by @var{af}.  @var{af} can be a function
-## handle, an inline function, or a string.  When @var{af} is a string it
+## It is also possible to represent @var{A} by a function denoted @var{Af}.
+## @var{Af} must be followed by a scalar argument @var{n} defining the length
+## of the vector argument accepted by @var{Af}.  @var{Af} can be a function
+## handle, an inline function, or a string.  When @var{Af} is a string it
 ## holds the name of the function to use.
 ##
-## @var{af} is a function of the form @code{y = af (x)} where the required
-## return value of @var{af} is determined by the value of @var{sigma}.  The
-## four possible forms are
+## @var{Af} is a function of the form @code{y = Af (x)} where the required
+## return value of @var{Af} is determined by the value of @var{sigma}.
+## The four possible forms are
 ##
 ## @table @code
 ## @item A * x
@@ -173,26 +181,34 @@
 ## if @var{sigma} is 0 or "sm".
 ##
 ## @item (A - sigma * I) \ x
-## for the standard eigenvalue problem, where @code{I} is the identity matrix
+## if @var{sigma} is a scalar not equal to 0; @code{I} is the identity matrix
 ## of the same size as @var{A}.
 ##
 ## @item (A - sigma * B) \ x
 ## for the general eigenvalue problem.
 ## @end table
 ##
-## The return arguments of @code{eigs} depend on the number of return arguments
-## requested.  With a single return argument, a vector @var{d} of length
+## The return arguments and their form depend on the number of return arguments
+## requested.  For a single return argument, a column vector @var{d} of length
 ## @var{k} is returned containing the @var{k} eigenvalues that have been
-## found.  With two return arguments, @var{V} is a @var{n}-by-@var{k} matrix
+## found.  For two return arguments, @var{V} is an @var{n}-by-@var{k} matrix
 ## whose columns are the @var{k} eigenvectors corresponding to the returned
-## eigenvalues.  The eigenvalues themselves are returned in @var{d} in the
-## form of a @var{n}-by-@var{k} matrix, where the elements on the diagonal
+## eigenvalues.  The eigenvalues themselves are returned in @var{D} in the
+## form of a @var{k}-by-@var{k} matrix, where the elements on the diagonal
 ## are the eigenvalues.
 ##
-## Given a third return argument @var{flag}, @code{eigs} returns the status
-## of the convergence.  If @var{flag} is 0 then all eigenvalues have converged.
-## Any other value indicates a failure to converge.
+## The third return argument @var{flag} returns the status of the convergence.
+## If @var{flag} is 0 then all eigenvalues have converged.  Any other value
+## indicates a failure to converge.
 ##
+## Programming Notes: For small problems, @var{n} < 500, consider using
+## @code{eig (full (@var{A}))}.
+##
+## If ARPACK fails to converge consider increasing the number of Lanczos
+## vectors (@var{opt}.p), increasing the number of iterations
+## (@var{opt}.maxiter), or decreasing the tolerance (@var{opt}.tol).
+##
+## Reference:
 ## This function is based on the @sc{arpack} package, written by
 ## @nospell{R. Lehoucq, K. Maschhoff, D. Sorensen, and C. Yang}.  For more
 ## information see @url{http://www.caam.rice.edu/software/ARPACK/}.
@@ -200,26 +216,37 @@
 ## @seealso{eig, svds}
 ## @end deftypefn
 
-function varargout = eigs (varargin)
+## Programming Note: For compatibility with Matlab, handle small matrix cases
+## and all-zero matrices in this m-file which ARPACK can not.
 
-  ## For compatibility with Matlab, handle small matrix cases here
-  ## that ARPACK does not.
+function varargout = eigs (varargin)
 
   if (nargin == 0)
     print_usage ();
   endif
 
-  call_eig = false;
+  call_eig = false;  # flag whether to take shortcut path with eig()
+  have_A = false;
+  have_B = false;
   offset = 0;
-  b = [];
   k = 6;
   sigma = "lm";
 
+  ## FIXME: Input validation is split between eigs.m and __eigs__.cc.
+  ##        It would be simpler if all input validation was done in the m-file
+  ##        and then the internal function __eigs__ could be simplified to
+  ##        rely on having "good" inputs.
   if (isnumeric (varargin{1}) && issquare (varargin{1}))
-    a = varargin{1};
-    if (nargin > 1 && isnumeric (varargin{2}))
-      if (size_equal (a, varargin{2}))
-        b = varargin{2};
+    A = varargin{1};
+    have_A = true;
+    k = min (k, rows (A));  # reduce default k if necessary
+    if (nargin > 1)
+      if (! isnumeric (varargin{2}))
+        error ("eigs: second argument must be numeric");
+      endif
+      if (size_equal (A, varargin{2}))
+        B = varargin{2};
+        have_B = true;
         offset = 1;
       elseif (isempty (varargin{2}))
         ## Special syntax to do regular eigenvalue decomposition rather
@@ -228,11 +255,14 @@
       endif
     endif
 
-    if (rows (a) < 13)
+    if (rows (A) <= 12)  # p = 2*k criteria
       call_eig = true;
     endif
 
     if (nargin > 1 + offset)
+      ## FIXME: Input validation should recognize improper inputs.
+      ##        Code below only checks for what it expects to find.
+      ##        Sample bad input: eigs (magic (5), [], {1})
       arg = varargin{2+offset};
       if (isnumeric (arg) && isscalar (arg) && isreal (arg)
           && fix (arg) == arg)
@@ -241,11 +271,6 @@
       elseif (isfield (arg, "p"))
         p = arg.p;
       endif
-      if (p >= rows (a))
-        call_eig = true;
-      else
-        call_eig = false;
-      endif
 
       if (nargin > 2 + offset)
         arg = varargin{3+offset};
@@ -256,51 +281,70 @@
         elseif (isfield (arg, "p"))
           p = arg.p;
         endif
-        if (p >= rows (a))
-          call_eig = true;
-        else
-          call_eig = false;
+
+        if (nargin > 3 + offset)
+          arg = varargin{4+offset};
+          if (isfield (arg, "p"))
+            p = arg.p;
+          else
+            p = 2 * k;
+          endif
         endif
       endif
-      if (nargin > 3 + offset)
-        arg = varargin{4+offset};
-        if (isfield (arg, "p"))
-          p = arg.p;
-        else
-          p = 2 * k;
-        endif
-        if (p >= rows (a))
-          call_eig = true;
-        else
-          call_eig = false;
-        endif
+
+      if (p >= rows (A))
+        call_eig = true;
+      else
+        call_eig = false;
       endif
     endif
   endif
 
   if (call_eig)
+    ## Special code path for small matrices which ARPACK does not handle.
     varargout = cell (1, min (2, max (1, nargout)));
-    if (isempty (b))
-      real_valued = isreal (a);
-      symmetric = issymmetric (a);
-      [varargout{:}] = eig (a);
+    if (have_B)
+      real_valued = isreal (A) && isreal (B);
+      symmetric = issymmetric (A) && issymmetric (B);
+      [varargout{:}] = eig (A, B);
     else
-      real_valued = isreal (a) && isreal (b);
-      symmetric = issymmetric (a) && issymmetric (b);
-      [varargout{:}] = eig (a, b);
+      real_valued = isreal (A);
+      symmetric = issymmetric (A);
+      [varargout{:}] = eig (A);
     endif
-    varargout = select (varargout, k, sigma, real_valued, symmetric);
+    varargout = select_eig (varargout, k, sigma, real_valued, symmetric);
     if (nargout == 3)
-      varargout{3} = 0;
+      varargout{3} = 0;  # Flag value is always 0 (success) for eig() code path
     endif
+
   else
     varargout = cell (1, max (1, nargout));
-    [varargout{:}] = __eigs__ (varargin{:});
+    if (have_A && nnz (A) == 0)
+      ## Special case of zeros matrix which ARPACK handles badly.
+      switch (nargout)
+        case 3
+          V = diag (ones ([k,1]), rows (A), k);
+          varargout = { V, diag(zeros (k,1)), 0.0 };
+
+        case 2
+          V = diag (ones ([k,1]), rows (A), k);
+          varargout = { V, diag(zeros (k,1)) };
+
+        case {0, 1}
+          varargout = { zeros(k,1) };
+      endswitch
+    else
+      ## Call ARPACK
+      [varargout{:}] = __eigs__ (varargin{:});
+    endif
   endif
 
 endfunction
 
-function out = select (args, k, sigma, real_valued, symmetric)
+## For cases which do not go through ARPACK, but rather through eig() shortcut
+## code path, select which values to return based on input parameters and
+## number of outputs.
+function out = select_eig (args, k, sigma, real_valued, symmetric)
 
   if (numel (args) == 1)
     d = args{1};
@@ -308,6 +352,11 @@
     d = diag (args{2});
   endif
 
+  n = numel (d);
+  if (k > n)
+    error ("eigs: requested number of eigenvalues K (%d) exceeds available eigenvalues (%d)", k, n);
+  endif
+
   if (ischar (sigma))
     switch (sigma)
       case "lm"
@@ -375,15 +424,10 @@
 
   d = d(idx);
 
-  n = numel (d);
-
-  k = min (k, n);
-
   if (strcmp (sigma, "be"))
-    tmp = k / 2;
-    n1 = floor (tmp);
-    n2 = n - ceil (tmp) + 1;
-    selection = [1:floor(k/2), n2:n];
+    n1 = floor (k/2);
+    n2 = n - (k - n1) + 1;
+    selection = [1:n1, n2:n];
   else
     selection = 1:k;
   endif
@@ -395,15 +439,31 @@
   else
     out{2} = diag (d);
 
-    v = args{1};
-    v = v(:,idx);
-    out{1} = v(:,selection);
+    V = args{1};
+    V = V(:,idx);
+    out{1} = V(:,selection);
   endif
 
 endfunction
 
 
-#### SPARSE MATRIX VERSIONS ####
+### TRIVIAL TESTS ###
+
+%!test
+%! for i = 1:20
+%!   assert (eigs (i, 1), i, 1e-11);
+%!   assert (eigs (zeros (i), 1), 0, 1e-11);
+%!   assert (eigs (sparse (i), 1), i, 1e-11);
+%!   assert (eigs (sparse (i, i), 1), 0, 1e-11);
+%! endfor
+
+%!testif HAVE_ARPACK
+%! for i = 1:20
+%!   assert (eigs (ones (i), 1), i, 1e-11);
+%!   assert (eigs (sparse (ones (i)), 1), i, 1e-11);
+%! endfor
+
+### SPARSE MATRIX TESTS ###
 
 ## Real positive definite tests, n must be even
 %!shared n, k, A, d0, d2, old_state, restore_state
@@ -787,7 +847,7 @@
 %! B = toeplitz (sparse ([1, 1], [1, 2], [2, 1], 1, 10));
 %! [v, d] = eigs (A, B, 4, "lm");
 %! for i = 1:4
-%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12)
+%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12);
 %! endfor
 %! ddiag = diag (d);
 %! [ddiag, idx] = sort (ddiag);
@@ -887,7 +947,7 @@
 %! opts.cholB = true;
 %! [v, d] = eigs (A, R, 4, "lm", opts);
 %! for i = 1:4
-%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12)
+%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12);
 %! endfor
 %!testif HAVE_ARPACK, HAVE_UMFPACK, HAVE_CHOLMOD
 %! A = toeplitz (sparse (1:10));
@@ -897,11 +957,10 @@
 %! opts.permB = permB;
 %! [v, d] = eigs (A, R, 4, "lm", opts);
 %! for i = 1:4
-%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12)
+%!   assert (A * v(:,i), d(i, i) * B * v(:,i), 1e-12);
 %! endfor
 
-
-#### FULL MATRIX VERSIONS ####
+### FULL MATRIX TESTS ###
 
 ## Real positive definite tests, n must be even
 %!shared n, k, A, d0, d2, old_state, restore_state
@@ -1292,7 +1351,7 @@
 %! A(1, 1) = 0;
 %! A(1, 9) = 1;
 %! [V, L] = eigs (A, 4, -1);
-%! assert (!any (isnan (diag (L))));
+%! assert (! any (isnan (diag (L))));
 %! assert (any (abs (diag (L)) <= 2 * eps));
 %!testif HAVE_ARPACK
 %! A = diag (ones (9, 1), 1);
@@ -1370,10 +1429,6 @@
 %!assert (eigs (diag (1:5), 5, "sa"), [1;2;3;4;5]) # call_eig is true
 %!assert (eigs (diag (1:5), 5, "la"), [5;4;3;2;1]) # call_eig is true
 %!assert (eigs (diag (1:5), 3, "be"), [1;4;5]) # call_eig is true
-%!error
-%! A = rand (10);
-%! opts.v0 = ones (8, 1);
-%! eigs (A, 4, "sm", opts);
 %!testif HAVE_ARPACK
 %! A = toeplitz ([-2, 1, zeros(1, 8)]);
 %! A = kron (A, eye (10)) + kron (eye (10), A);
@@ -1488,11 +1543,11 @@
 %! i_A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 %! j_A = [1, 2, 3, 4, 5, 6, 7,  8, 9, 10];
 %! v_A = [1, 2i, 3, 4i, 5, 6i, 7, 8, 9, 10i];
-%! A = sparse(i_A, j_A, v_A);
+%! A = sparse (i_A, j_A, v_A);
 %! i_B = [1,2, 3, 4, 5, 6, 7, 8, 9, 10];
 %! j_B = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 %! v_B = [3, 10i, 1, 8i, 7, 6i, 5, 4i, 9, 7i];
-%! B = sparse(i_B, j_B, v_B); # not SPD
+%! B = sparse (i_B, j_B, v_B); # not SPD
 %! [Evectors, Evalues] = eigs(A, B, 5, "SM"); # call_eig is true
 %! ResidualVectors = A * Evectors - B * Evectors * Evalues;
 %! RelativeErrors = norm (ResidualVectors, "columns") ./ ...
@@ -1590,3 +1645,35 @@
 %! A = magic (5);
 %! d = eigs (A, [], 1);
 %! assert (d, 65, 5 * eps (65));
+
+%!testif HAVE_ARPACK <*59488>
+%! A = zeros (20);
+%! d = eigs (A, 4);
+%! assert (d, zeros (4, 1));
+%! [V, d, flag] = eigs (A, 4);
+%! Vexp = zeros (20, 4);
+%! Vexp(sub2ind (size (Vexp), 1:4, 1:4)) = 1;
+%! assert (V, Vexp);
+%! assert (d, diag (zeros (4,1)));
+%! assert (flag, 0.0);
+
+## Test input validation
+%!error <Invalid call> eigs ()
+%!error <second argument must be numeric> eigs (1, "foobar")
+%!error <requested number of eigenvalues K \(2\) exceeds available eigenvalues \(1\)>
+%! eigs (1, [], 2);
+%!error <"la" requires real symmetric problem> eigs ([i,0;0,1], 1, "la")
+%!error <"la" requires real symmetric problem> eigs ([1,1;0,1], 1, "la")
+%!error <"sa" requires real symmetric problem> eigs ([i,0;0,1], 1, "sa")
+%!error <"sa" requires real symmetric problem> eigs ([1,1;0,1], 1, "sa")
+%!error <"be" requires real symmetric problem> eigs ([i,0;0,1], 1, "be")
+%!error <"be" requires real symmetric problem> eigs ([1,1;0,1], 1, "be")
+%!error <"lr" requires complex or unsymmetric> eigs ([1,0;0,1], 1, "lr")
+%!error <"sr" requires complex or unsymmetric> eigs ([1,0;0,1], 1, "sr")
+%!error <"li" requires complex or unsymmetric> eigs ([1,0;0,1], 1, "li")
+%!error <"si" requires complex or unsymmetric> eigs ([1,0;0,1], 1, "si")
+%!error <unrecognized value for SIGMA: foobar> eigs (eye (2), 1, "foobar")
+%!testif HAVE_ARPACK
+%! A = rand (10);
+%! opts.v0 = ones (8, 1);
+%! fail ("eigs (A, 4, 'sm', opts)", "opts.v0 must be n-by-1");
--- a/scripts/sparse/etreeplot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/etreeplot.m	Sun May 16 09:44:35 2021 +0200
@@ -36,10 +36,15 @@
 
 function etreeplot (A, varargin)
 
-  if (nargin < 1)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
   treeplot (etree (A+A'), varargin{:});
 
 endfunction
+
+
+## Test input validation
+%!error <Invalid call> etreeplot ()
+%!error <Invalid call> etreeplot (1,2,3,4)
--- a/scripts/sparse/gmres.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/gmres.m	Sun May 16 09:44:35 2021 +0200
@@ -258,9 +258,9 @@
   size_b = rows (b);
 
   if (tol >= 1)
-    warning("Input tol is bigger than 1. \n Try to use a smaller tolerance.");
+    warning ("Input tol is bigger than 1. \n Try to use a smaller tolerance.");
   elseif (tol <= eps / 2)
-    warning("Input tol may not be achievable by gmres. \n Try to use a bigger tolerance.");
+    warning ("Input tol may not be achievable by gmres. \n Try to use a bigger tolerance.");
   endif
 
   ## This big "if block" is to set maxit and restart in the proper way
@@ -270,7 +270,7 @@
     maxit = 1;
     max_iter_number = min (size_b, 10);
   elseif (restart <= 0) || (maxit <= 0)
-    error ("gmres: MAXIT and RESTART must be positive integers")
+    error ("gmres: MAXIT and RESTART must be positive integers");
   elseif (restart < size_b) && (empty_maxit)
     maxit = min (size_b / restart, 10);
     max_iter_number = maxit * restart;
@@ -278,7 +278,7 @@
     maxit = 1;
     max_iter_number = min (size_b, 10);
   elseif (restart > size_b) && (empty_maxit)
-    warning ("RESTART is %d but it should be bounded by SIZE(A,2).\n Setting restart to %d. \n", restart, size_b)
+    warning ("RESTART is %d but it should be bounded by SIZE(A,2).\n Setting restart to %d. \n", restart, size_b);
     restart = size_b;
     maxit = 1;
     max_iter_number = restart;
@@ -290,8 +290,8 @@
     restart = size_b;
     maxit = size_b;
     max_iter_number = size_b;
-  elseif (restart > size_b) && (!empty_maxit)
-    warning ("RESTART is %d but it should be bounded by SIZE(A,2).\n Setting restart to %d. \n", restart, size_b)
+  elseif (restart > size_b) && (! empty_maxit)
+    warning ("RESTART is %d but it should be bounded by SIZE(A,2).\n Setting restart to %d. \n", restart, size_b);
     restart = size_b;
     max_iter_number = restart * maxit;
   elseif (restart == size_b) && (maxit <= size_b)
@@ -303,14 +303,14 @@
   prec_b_norm = norm (b, 2);
   if (prec_b_norm == 0)
     if (nargout < 2)
-      printf("The right hand side vector is all zero so gmres\nreturned an all zero solution without iterating.\n")
+      printf ("The right hand side vector is all zero so gmres\nreturned an all zero solution without iterating.\n")
     endif
     x_min = b;
     flag = 0;
     relres = 0;
     resvec = 0;
     it = [0, 0];
-    return
+    return;
   endif
 
   ## gmres: function handle case
@@ -324,14 +324,14 @@
   iter_min = 0; # iteration with minimum residual
   outer_it = 1; # number of outer iterations
   restart_it  =  1; # number of inner iterations
-  it = zeros(1, 2);
+  it = zeros (1, 2);
   resvec = zeros (max_iter_number + 1, 1);
   flag = 1; # Default flag is maximum # of iterations exceeded
 
   ## begin loop
   u = feval (Afun, x_old, varargin{:});
   try
-    warning("error", "Octave:singular-matrix", "local")
+    warning ("error", "Octave:singular-matrix", "local");
     prec_res = feval (M1fun, b - u, varargin{:}); # M1*(b-u)
     prec_res = feval (M2fun, prec_res, varargin{:});
     presn = norm (prec_res, 2);
@@ -401,22 +401,22 @@
   if ((nargout < 2) && (restart != size_b)) # restart applied
     switch (flag)
       case {0} # gmres converged
-        printf ("gmres(%d) converged at outer iteration %d (inner iteration %d) ",restart, it (1), it (2));
+        printf ("gmres (%d) converged at outer iteration %d (inner iteration %d) ",restart, it (1), it (2));
         printf ("to a solution with relative residual %d \n", relres);
       case {1} # max number of iteration reached
-        printf ("gmres(%d) stopped at outer iteration %d (inner iteration %d) ", restart, outer_it, restart_it-1);
+        printf ("gmres (%d) stopped at outer iteration %d (inner iteration %d) ", restart, outer_it, restart_it-1);
         printf ("without converging to the desired tolerance %d ", tol);
         printf ("because the maximum number of iterations was reached \n");
         printf ("The iterated returned (number %d(%d)) ", it(1), it(2));
         printf ("has relative residual %d \n", relres);
       case {2} # preconditioner singular
-        printf ("gmres(%d) stopped at outer iteration %d (inner iteration %d) ",restart, outer_it, restart_it-1);
+        printf ("gmres (%d) stopped at outer iteration %d (inner iteration %d) ",restart, outer_it, restart_it-1);
         printf ("without converging to the desired tolerance %d ", tol);
         printf ("because the preconditioner matrix is singular \n");
         printf ("The iterated returned (number %d(%d)) ", it(1), it(2));
         printf ("has relative residual %d \n", relres);
       case {3} # stagnation
-        printf ("gmres(%d) stopped at outer iteration %d (inner iteration %d) ", restart, outer_it, restart_it - 1);
+        printf ("gmres (%d) stopped at outer iteration %d (inner iteration %d) ", restart, outer_it, restart_it - 1);
         printf ("without converging to the desired tolerance %d", tol);
         printf ("because it stagnates. \n");
         printf ("The iterated returned (number %d(%d)) ", it(1), it(2));
@@ -447,8 +447,10 @@
         printf ("has relative residual %d \n", relres);
     endswitch
   endif
+
 endfunction
 
+
 %!demo
 %! dim = 20;
 %! A = spdiags ([-ones(dim,1) 2*ones(dim,1) ones(dim,1)], [-1:1], dim, dim);
@@ -539,7 +541,7 @@
 %! [x, flag] = gmres (A, b, 10, 1e-10, dim, @(x) x ./ diag (A), [], b);
 %! assert (x, A\b, 1e-9*norm (x, Inf));
 %! [x, flag] = gmres (A, b, dim, 1e-10, 1e4, @(x) diag (diag (A)) \ x, [], b);
-%! assert(x, A\b, 1e-7*norm (x, Inf));
+%! assert (x, A\b, 1e-7*norm (x, Inf));
 
 %!test
 %! dim = 100;
@@ -564,14 +566,14 @@
 %! b = sum (A, 2);
 %! [x, flag] = gmres(A, b, [], [], 5);
 %! assert (flag, 0);
-%! assert (x, ones (5, 1), -1e-06)
+%! assert (x, ones (5, 1), -1e-06);
 
 %!test
 %! ## Maximum number of iteration reached
 %! A = hilb (100);
 %! b = sum (A, 2);
 %! [x, flag, relres, iter] = gmres (A, b, [], 1e-14);
-%! assert(flag, 1);
+%! assert (flag, 1);
 
 %!test
 %! ## gmres recognizes that the preconditioner matrix is singular
@@ -580,56 +582,56 @@
 %! I = eye (3);
 %! M = [1 0 0; 0 1 0; 0 0 0]; # the last row is zero
 %! [x, flag] = gmres(@(y) AA * y, bb, [], [], [], @(y) M \ y, @(y) y);
-%! assert (flag, 2)
+%! assert (flag, 2);
 
 %!test
 %! A = rand (4);
 %! A = A' * A;
 %! [x, flag] = gmres (A, zeros (4, 1), [], [], [], [], [], ones (4, 1));
-%! assert (x, zeros (4, 1))
+%! assert (x, zeros (4, 1));
 
 %!test
 %! A = rand (4);
 %! b = zeros (4, 1);
 %! [x, flag, relres, iter] = gmres (A, b);
-%! assert (relres, 0)
+%! assert (relres, 0);
 
 %!test
 %! A = toeplitz (sparse ([2, 1, 0, 0, 0]), sparse ([2, -1, 0, 0, 0]));
 %! b = A * ones (5, 1);
 %! [x, flag, relres, iter] = gmres (A, b, [], [], [], [], [], ...
 %! ones (5, 1) + 1e-8);
-%! assert (iter, [0, 0])
+%! assert (iter, [0, 0]);
 
 %!test
 %! A = rand (20);
 %! b = A * ones (20, 1);
 %! [x, flag, relres, iter, resvec] = gmres (A, b, [], [], 1);
-%! assert (iter, [1, 1])
+%! assert (iter, [1, 1]);
 
 %!test
 %! A = hilb (20);
 %! b = A * ones (20, 1);
 %! [x, flag, relres, iter, resvec] = gmres (A, b ,5, 1e-14);
-%! assert (iter, [4, 5])
+%! assert (iter, [4, 5]);
 
 %!test
 %! A = single (1);
 %! b = 1;
 %! [x, flag] = gmres (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %! A = 1;
 %! b = single (1);
 %! [x, flag] = gmres (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %! A = single (1);
 %! b = single (1);
 %! [x, flag] = gmres (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %!function y = Afun (x)
@@ -637,11 +639,11 @@
 %!   y = A * x;
 %!endfunction
 %! [x, flag] = gmres ("Afun", [1; 2; 2; 3]);
-%! assert (x, ones(4, 1), 1e-6)
+%! assert (x, ones (4, 1), 1e-6);
 
 %!test # preconditioned residual
 %! A = toeplitz (sparse ([2, 1, 0, 0, 0]), sparse ([2, -1, 0, 0, 0]));
 %! b = sum (A, 2);
 %! M = magic (5);
 %! [x, flag, relres] = gmres (A, b, [], [], 2, M);
-%! assert (relres, norm (M \ (b - A * x)) / norm (M \ b), 8 * eps)
+%! assert (relres, norm (M \ (b - A * x)) / norm (M \ b), 8 * eps);
--- a/scripts/sparse/gplot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/gplot.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function [x, y] = gplot (A, xy, line_style)
 
-  if (nargin < 2 || nargin > 3 || nargout > 2)
+  if (nargin < 2)
     print_usage ();
   endif
 
--- a/scripts/sparse/ichol.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/ichol.m	Sun May 16 09:44:35 2021 +0200
@@ -160,7 +160,7 @@
 
 function L = ichol (A, opts = struct ())
 
-  if (nargin < 1 || nargin > 2 || nargout > 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -169,7 +169,7 @@
   endif
 
   if (! isstruct (opts))
-    error ("ichol: OPTS must be a structure.");
+    error ("ichol: OPTS must be a structure");
   endif
 
   ## If A is empty then return empty L for Matlab compatibility
--- a/scripts/sparse/ilu.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/ilu.m	Sun May 16 09:44:35 2021 +0200
@@ -168,7 +168,7 @@
 
 function [L, U, P] = ilu (A, opts = struct ())
 
-  if (nargin < 1 || nargin > 2 || (nargout > 3))
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -177,7 +177,7 @@
   endif
 
   if (! isstruct (opts))
-    error ("ilu: OPTS must be a structure.");
+    error ("ilu: OPTS must be a structure");
   endif
 
   ## If A is empty then return empty L, U and P for Matlab compatibility
@@ -507,7 +507,7 @@
 %! A = sparse (magic (4));
 %! opts.type = "ilutp";
 %! [L, U] = ilu (A, opts);
-%! assert (L * U, A, eps)
+%! assert (L * U, A, eps);
 
 ## Tests for input validation
 %!shared A_tiny, opts
--- a/scripts/sparse/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -8,6 +8,7 @@
   %reldir%/private/__sprand__.m
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/bicg.m \
   %reldir%/bicgstab.m \
   %reldir%/cgs.m \
--- a/scripts/sparse/nonzeros.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/nonzeros.m	Sun May 16 09:44:35 2021 +0200
@@ -31,7 +31,7 @@
 
 function v = nonzeros (A)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -52,5 +52,4 @@
 %!assert (nonzeros (sparse ([1,2,3,0])), [1;2;3])
 
 ## Test input validation
-%!error nonzeros ()
-%!error nonzeros (1, 2)
+%!error <Invalid call> nonzeros ()
--- a/scripts/sparse/pcg.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/pcg.m	Sun May 16 09:44:35 2021 +0200
@@ -284,7 +284,7 @@
   b_norm = norm (b);
   if (b_norm == 0)
      if (n_arg_out < 2)
-       printf("The right hand side vector is all zero so pcg \n");
+       printf ("The right hand side vector is all zero so pcg \n");
        printf ("returned an all zero solution without iterating.\n");
      endif
      x_min = b;
@@ -293,7 +293,7 @@
      resvec = 0;
      iter_min = 0;
      eigest = [NaN, NaN];
-     return
+     return;
   endif
 
   x = x_pr = x_min = x0;
@@ -319,7 +319,7 @@
   while (resvec(iter-1,1) > tol * b_norm && iter < maxit)
     if (iter == 2) # Check whether M1 or M2 are singular
       try
-        warning ("error","Octave:singular-matrix","local")
+        warning ("error","Octave:singular-matrix","local");
         z = feval (M1fun, r, varargin{:});
         z = feval (M2fun, z, varargin{:});
       catch
@@ -395,7 +395,7 @@
       endif
     else
       eigest = [NaN, NaN];
-      warning ('pcg: eigenvalue estimate failed: matrix not positive definite?')
+      warning ('pcg: eigenvalue estimate failed: matrix not positive definite?');
     endif
     resvec(iter - 1, 2) = sqrt (r' * z);
     resvec  = resvec (1:(iter-1), :);
@@ -454,6 +454,7 @@
         printf ("has relative residual %d \n", relres);
     endswitch
   endif
+
 endfunction
 
 
--- a/scripts/sparse/pcr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/pcr.m	Sun May 16 09:44:35 2021 +0200
@@ -334,7 +334,7 @@
 %! printf ("The solution relative error is %g\n", norm (x-X) / norm (X));
 %! clf;
 %! title ("Convergence history");
-%! xlabel ("Iteration"); ylabel ("log(||b-Ax||/||b||)");
+%! xlabel ("Iteration"); ylabel ("log (||b-Ax||/||b||)");
 %! semilogy ([0:iter], resvec/resvec(1), "o-g;relative residual;");
 
 %!demo
@@ -354,13 +354,13 @@
 %! endif
 %! clf;
 %! title ("Convergence history");
-%! xlabel ("Iteration"); ylabel ("log(||b-Ax||)");
+%! xlabel ("Iteration"); ylabel ("log (||b-Ax||)");
 %! semilogy ([0:iter], resvec, "o-g;absolute residual;");
 
 %!demo
 %! ## Full output from PCR
 %! ## We use an indefinite matrix based on the 1-D Laplacian matrix for A,
-%! ## and here we have cond(A) = O(N^2)
+%! ## and here we have cond (A) = O(N^2)
 %! ## That's the reason we need some preconditioner; here we take
 %! ## a very simple and not powerful Jacobi preconditioner,
 %! ## which is the diagonal of A.
@@ -383,7 +383,7 @@
 %! [x, flag, relres, iter, resvec] = pcr (A,b,[],maxit);
 %! clf;
 %! title ("Convergence history");
-%! xlabel ("Iteration"); ylabel ("log(||b-Ax||)");
+%! xlabel ("Iteration"); ylabel ("log (||b-Ax||)");
 %! semilogy ([0:iter], resvec, "o-g;NO preconditioning: absolute residual;");
 %!
 %! pause (1);
@@ -445,7 +445,7 @@
 %! b = ones (N,1);
 %! X = A \ b;  # X is the true solution
 %! [x, flag, relres, iter] = pcr (A,b,[],[],A,b);
-%! assert (norm (x-X) / norm(X) < 1e-6);
+%! assert (norm (x-X) / norm (X) < 1e-6);
 %! assert (relres < 1e-6);
 %! assert (flag, 0);
 %! assert (iter, 1); # should converge in one iteration
--- a/scripts/sparse/private/__alltohandles__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/private/__alltohandles__.m	Sun May 16 09:44:35 2021 +0200
@@ -64,47 +64,65 @@
      Afun = A;
   elseif (ischar (A))
     Afun = str2func (A);
-  elseif (!isnumeric (A) || !issquare (A))
-    error([solver_name, ": A must be a square matrix or a function handle"])
+  elseif (! isnumeric (A) || ! issquare (A))
+    error ([solver_name, ": A must be a square matrix or a function handle"]);
   else
     A_is_numeric = true;
     if (size (A, 2) != size (b, 1))
-      error ("__alltohandles__: dimension of b is not consistent with A")
+      error ("__alltohandles__: dimension of B is not consistent with A");
     endif
   endif
 
   ## Check M1 and sets its type
   if (isempty (M1)) # M1 empty, set to identity function
-      M1fun = @(x) x;
+    switch (solver_name)
+      case {"pcg", "gmres", "bicgstab", "cgs", "tfqmr"}
+        ## methods which do not require the transpose
+        M1fun = @(x) x;
+      case {"bicg"}
+        ## methods which do require the transpose
+        M1fun = @(x, ~) x;
+      otherwise
+        error (["__alltohandles__: unknown method: ", solver_name]);
+    endswitch
   else # M1 not empty
     if (is_function_handle (M1))
       M1fun = M1;
     elseif (ischar (M1))
       M1fun = str2func (M1);
-    elseif (!isnumeric (M1) || !issquare (M1))
-      error([solver_name, ": M1 must be a square matrix or a function handle"])
+    elseif (! isnumeric (M1) || ! issquare (M1))
+      error ([solver_name, ": M1 must be a square matrix or a function handle"]);
     else
       M1_is_numeric = true;
     endif
   endif
 
   if (isempty (M2)) # M2 empty, then I set is to the identity function
-    M2fun = @(x) x;
+    switch (solver_name)
+      case {"pcg", "gmres", "bicgstab", "cgs", "tfqmr"}
+        ## methods which do not require the transpose
+        M2fun = @(x) x;
+      case {"bicg"}
+        ## methods which do require the transpose
+        M2fun = @(x, ~) x;
+      otherwise
+        error (["__alltohandles__: unknown method: ", solver_name]);
+    endswitch
   else # M2 not empty
     if (is_function_handle (M2))
       M2fun = M2;
     elseif (ischar (M2))
       M2fun = str2func (M2);
-    elseif (!isnumeric (M2) || !issquare (M2))
-      error([solver_name, ": M2 must be a square matrix or a function handle"])
+    elseif (! isnumeric (M2) || ! issquare (M2))
+      error ([solver_name, ": M2 must be a square matrix or a function handle"]);
     else
       M2_is_numeric = true;
     endif
   endif
 
-  switch solver_name
+  switch (solver_name)
     case {"pcg", "gmres", "bicgstab", "cgs", "tfqmr"}
-      # methods which do not require the transpose
+      ## methods which do not require the transpose
       if (A_is_numeric)
         Afun = @(x) A * x;
       endif
@@ -115,7 +133,7 @@
         M2fun = @(x) M2 \ x;
       endif
     case {"bicg"}
-      # methods which do require the transpose
+      ## methods which do require the transpose
       if (A_is_numeric)
         Afun = @(x, trans) A_sub (A, x, trans);
       endif
@@ -128,6 +146,7 @@
     otherwise
       error (["__alltohandles__: unknown method: ", solver_name]);
   endswitch
+
 endfunction
 
 function y = A_sub (A, x, trans)
--- a/scripts/sparse/private/__default__input__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/private/__default__input__.m	Sun May 16 09:44:35 2021 +0200
@@ -34,31 +34,39 @@
 ## @item @var{def_val} is a cell array that contains the values to use
 ## as default.
 ##
-## @item @var{varargin} are the input arguments
+## @item @var{varargin} are the input arguments.
 ## @end itemize
 ##
 ## The output arguments are:
 ##
 ## @itemize @minus
-## @item @var{varargout} all input arguments completed with default
-## values for empty or omitted parameters.
+## @item @var{varargout} are the input arguments where any empty or omitted
+## parameters have been replaced with default values.
 ##
 ## @end itemize
 ##
 ## @end deftypefn
 
-
-function [varargout] = __default__input__ (def_val, varargin)
+function varargout = __default__input__ (def_val, varargin)
 
-  m = length (def_val);
-  n = length (varargin);
+  m = numel (def_val);
+  n = numel (varargin);
+  count = min (m, n);
 
-  for i = 1:m
-    if (n < i || isempty (varargin{i}))
+  ## Check for missing values in input and replace with default value.
+  for i = 1:count
+    if (isempty (varargin{i}))
       varargout{i} = def_val{i};
     else
       varargout{i} = varargin{i};
     endif
   endfor
 
+  ## Copy any remaining items to output
+  if (n < m)
+    varargout(n+1:m) = def_val(n+1:m);
+  elseif (m < n)
+    varargout(m+1:n) = varargin(m+1:n);
+  endif
+
 endfunction
--- a/scripts/sparse/private/__sprand__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/private/__sprand__.m	Sun May 16 09:44:35 2021 +0200
@@ -117,7 +117,7 @@
       else
         ## Only the min (m, n) greater singular values from rc vector are used.
         if (length (rc) > min (m,n))
-          rc = rc(1:min(m, n));
+          rc = rc(1:min (m, n));
         endif
         S = sparse (diag (sort (rc, "descend"), m, n));
       endif
--- a/scripts/sparse/qmr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/qmr.m	Sun May 16 09:44:35 2021 +0200
@@ -206,13 +206,13 @@
       vt = pt - beta1 * v;
 
       y = M1m1x (vt);
-      rho1 = norm(y);
+      rho1 = norm (y);
       wt = Atx (q) - beta1 * w;
       z = M2tm1x (wt);
 
-      xi1 = norm(z);
-      theta1 = rho1 / (gamma0 * abs(beta1));
-      gamma1 = 1 / sqrt(1 + theta1^2);   # If gamma1 == 0, method fails.
+      xi1 = norm (z);
+      theta1 = rho1 / (gamma0 * abs (beta1));
+      gamma1 = 1 / sqrt (1 + theta1^2);   # If gamma1 == 0, method fails.
       eta1 = -eta0 * rho0 * gamma1^2 / (beta1 * gamma0^2);
 
       if (iter == 1)
@@ -267,7 +267,7 @@
       printf ("to a solution with relative residual %e\n", res1);
     endif
   else
-    print_usage();
+    print_usage ();
   endif
 
 endfunction
--- a/scripts/sparse/spconvert.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/spconvert.m	Sun May 16 09:44:35 2021 +0200
@@ -37,7 +37,7 @@
 
 function s = spconvert (m)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,8 +73,7 @@
 %! assert (size (spconvert ([1, 1, 3; 5, 15, 0])), [5, 15]);
 
 ## Test input validation
-%!error spconvert ()
-%!error spconvert (1, 2)
+%!error <Invalid call> spconvert ()
 %!error spconvert ({[1 2 3]})
 %!error spconvert ([1 2])
 %!error spconvert ([1 2 3i])
--- a/scripts/sparse/spdiags.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/spdiags.m	Sun May 16 09:44:35 2021 +0200
@@ -64,7 +64,7 @@
 
 function [B, d] = spdiags (v, d, m, n)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -178,5 +178,4 @@
 %!assert (spdiags ([0.5 -1 0.5], 0:2, 1, 1), sparse (0.5))
 
 ## Test input validation
-%!error spdiags ()
-%!error spdiags (1,2,3,4,5)
+%!error <Invalid call> spdiags ()
--- a/scripts/sparse/spfun.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/spfun.m	Sun May 16 09:44:35 2021 +0200
@@ -25,11 +25,53 @@
 
 ## -*- texinfo -*-
 ## @deftypefn {} {@var{y} =} spfun (@var{f}, @var{S})
-## Compute @code{f(@var{S})} for the nonzero values of @var{S}.
+## Compute @code{f (@var{S})} for the nonzero elements of @var{S}.
+##
+## The input function @var{f} is applied only to the nonzero elements of
+## the input matrix @var{S} which is typically sparse.  The function @var{f}
+## can be passed as a string, function handle, or inline function.
+##
+## The output @var{y} is a sparse matrix with the same sparsity structure as
+## the input @var{S}.  @code{spfun} preserves sparsity structure which is
+## different than simply applying the function @var{f} to the sparse matrix
+## @var{S} when @code{@var{f} (0) != 0}.
+##
+## Example
+##
+## Sparsity preserving @code{spfun} versus normal function application
+##
+## @example
+## @group
+## S = pi * speye (2,2)
+## S =
+##
+## Compressed Column Sparse (rows = 2, cols = 2, nnz = 2 [50%])
 ##
-## This results in a sparse matrix with the same structure as @var{S}.  The
-## function @var{f} can be passed as a string, a function handle, or an
-## inline function.
+##   (1, 1) -> 3.1416
+##   (2, 2) -> 3.1416
+##
+## y = spfun (@@cos, S)
+## y =
+##
+## Compressed Column Sparse (rows = 2, cols = 2, nnz = 2 [50%])
+##
+##   (1, 1) -> -1
+##   (2, 2) -> -1
+## @end group
+##
+## @group
+## y = cos (S)
+## y =
+##
+## Compressed Column Sparse (rows = 2, cols = 2, nnz = 4 [100%])
+##
+##   (1, 1) -> -1
+##   (2, 1) -> 1
+##   (1, 2) -> 1
+##   (2, 2) -> -1
+##
+## @end group
+## @end example
 ## @seealso{arrayfun, cellfun, structfun}
 ## @end deftypefn
 
@@ -39,14 +81,14 @@
     print_usage ();
   endif
 
+  if (! isnumeric (S))
+    error ("spfun: S must be numeric");
+  endif
+
   [i, j, v] = find (S);
   [m, n] = size (S);
 
-  if (is_function_handle (f))
-    y = sparse (i, j, f(v), m, n);
-  else
-    y = sparse (i, j, feval (f, v), m, n);
-  endif
+  y = sparse (i, j, feval (f, v), m, n);
 
 endfunction
 
@@ -55,3 +97,9 @@
 %!assert (spfun ("exp", sparse ([1,2;3,0])), sparse ([exp(1),exp(2);exp(3),0]))
 %!assert (spfun (@exp, [1,2;3,0]), sparse ([exp(1),exp(2);exp(3),0]))
 %!assert (spfun (@exp, sparse ([1,2;3,0])), sparse ([exp(1),exp(2);exp(3),0]))
+
+## Test input validation
+%!error <Invalid call> spfun ()
+%!error <Invalid call> spfun (@cos)
+%!error <S must be numeric> spfun (@cos, {1})
+%!error <S must be numeric> spfun (@cos, "FooBar")
--- a/scripts/sparse/spones.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/spones.m	Sun May 16 09:44:35 2021 +0200
@@ -33,7 +33,7 @@
 
 function r = spones (S)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/sparse/sprand.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/sprand.m	Sun May 16 09:44:35 2021 +0200
@@ -49,9 +49,9 @@
 
 function s = sprand (m, n, d, rc)
 
-  if (nargin == 1 )
+  if (nargin == 1)
     s = __sprand__ (m, @rand);
-  elseif ( nargin == 3)
+  elseif (nargin == 3)
     s = __sprand__ (m, n, d, "sprand", @rand);
   elseif (nargin == 4)
     s = __sprand__ (m, n, d, rc, "sprand", @rand);
@@ -99,9 +99,8 @@
 %!assert (size (sprand (3, 0, 0.5)), [3, 0])
 
 ## Test input validation
-%!error sprand ()
-%!error sprand (1, 2)
-%!error sprand (1, 2, 3, 4)
+%!error <Invalid call> sprand ()
+%!error <Invalid call> sprand (1, 2)
 %!error <M must be a non-negative integer> sprand (-1, -1, 0.5)
 %!error <M must be a non-negative integer> sprand (ones (3), 3, 0.5)
 %!error <M must be a non-negative integer> sprand (3.5, 3, 0.5)
--- a/scripts/sparse/sprandn.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/sprandn.m	Sun May 16 09:44:35 2021 +0200
@@ -49,9 +49,9 @@
 
 function s = sprandn (m, n, d, rc)
 
-  if (nargin == 1 )
+  if (nargin == 1)
     s = __sprand__ (m, @randn);
-  elseif ( nargin == 3)
+  elseif (nargin == 3)
     s = __sprand__ (m, n, d, "sprandn", @randn);
   elseif (nargin == 4)
     s = __sprand__ (m, n, d, rc, "sprandn", @randn);
@@ -98,9 +98,8 @@
 %!assert (size (sprandn (3, 0, 0.5)), [3, 0])
 
 ## Test input validation
-%!error sprandn ()
-%!error sprandn (1, 2)
-%!error sprandn (1, 2, 3, 4)
+%!error <Invalid call> sprandn ()
+%!error <Invalid call> sprandn (1, 2)
 %!error <M must be a non-negative integer> sprand (-1, -1, 0.5)
 %!error <M must be a non-negative integer> sprandn (ones (3), 3, 0.5)
 %!error <M must be a non-negative integer> sprandn (3.5, 3, 0.5)
--- a/scripts/sparse/sprandsym.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/sprandsym.m	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,7 @@
 
 function S = sprandsym (n, d)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -181,8 +181,7 @@
 %!assert (size (sprandsym (0, 0.5)), [0, 0])
 
 ## Test input validation
-%!error sprandsym ()
-%!error sprandsym (1, 2, 3)
+%!error <Invalid call> sprandsym ()
 %!error sprandsym (ones (3), 0.5)
 %!error sprandsym (3.5, 0.5)
 %!error sprandsym (-1, 0.5)
--- a/scripts/sparse/spstats.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/spstats.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function [count, mean, var] = spstats (S, j)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/sparse/spy.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/spy.m	Sun May 16 09:44:35 2021 +0200
@@ -29,17 +29,17 @@
 ## @deftypefnx {} {} spy (@dots{}, @var{line_spec})
 ## Plot the sparsity pattern of the sparse matrix @var{x}.
 ##
-## If the argument @var{markersize} is given as a scalar value, it is used to
-## determine the point size in the plot.
+## If the optional numeric argument @var{markersize} is given, it determines
+## the size of the markers used in the plot.
 ##
-## If the string @var{line_spec} is given it is passed to @code{plot} and
-## determines the appearance of the plot.
+## If the optional string @var{line_spec} is given it is passed to @code{plot}
+## and determines the appearance of the plot.
 ## @seealso{plot, gplot}
 ## @end deftypefn
 
 function spy (x, varargin)
 
-  if (nargin < 1)
+  if (nargin < 1 || nargin > 3)
     print_usage ();
   endif
 
@@ -49,21 +49,22 @@
   else
     line_spec = ".";
   endif
-  for i = 1:length (varargin)
-    if (ischar (varargin{i}))
-      if (length (varargin{i}) == 1)
-        line_spec = [line_spec, varargin{i}];
+  for arg = varargin
+    arg = arg{1};
+    if (ischar (arg))
+      if (numel (arg) == 1)
+        line_spec = [line_spec, arg];
       else
-        line_spec = varargin{i};
+        line_spec = arg;
       endif
-    elseif (isscalar (varargin{i}))
-      markersize = varargin{i};
+    elseif (isreal (arg) && isscalar (arg))
+      markersize = arg;
     else
       error ("spy: expected markersize or linespec");
     endif
   endfor
 
-  [i, j, s] = find (x);
+  [i, j] = find (x);
   [m, n] = size (x);
 
   if (isnan (markersize))
@@ -73,6 +74,7 @@
   endif
 
   axis ([0, n+1, 0, m+1], "ij");
+  xlabel (sprintf ("nnz = %d", nnz (x)));
 
 endfunction
 
@@ -81,5 +83,6 @@
 %! clf;
 %! spy (sprand (10,10, 0.2));
 
-## Mark graphical function as tested by demo block
-%!assert (1)
+## Test input validation
+%!error <Invalid call> spy ()
+%!error <Invalid call> spy (1,2,3,4)
--- a/scripts/sparse/svds.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/svds.m	Sun May 16 09:44:35 2021 +0200
@@ -102,7 +102,7 @@
 
   persistent root2 = sqrt (2);
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- a/scripts/sparse/tfqmr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/tfqmr.m	Sun May 16 09:44:35 2021 +0200
@@ -217,7 +217,7 @@
   norm_b = norm (b, 2);
   if (norm_b == 0)
     if (nargout < 2)
-      printf("The right hand side vector is all zero so tfqmr \n")
+      printf ("The right hand side vector is all zero so tfqmr \n")
       printf ("returned an all zero solution without iterating.\n")
     endif
     x_min = zeros (numel (b), 1);
@@ -225,7 +225,7 @@
     flag = 0;
     resvec = 0;
     relres = 0;
-    return
+    return;
   endif
 
   x = x_pr = x_min = x0;
@@ -242,7 +242,7 @@
   it = 1;
 
   try
-    warning("error", "Octave:singular-matrix", "local");
+    warning ("error", "Octave:singular-matrix", "local");
     u_hat = feval (M1fun, u, varargin{:});
     u_hat = feval (M2fun, u_hat, varargin{:});
     v = feval (Afun, u_hat, varargin{:});
@@ -257,7 +257,7 @@
         ## Essentially the next iteration doesn't change x,
         ## and the iter after this will have a division by zero
         flag = 4;
-        break
+        break;
       endif
       alpha = rho_1 / v_r;
       u_1 = u - alpha * v;  # u at the after iteration
@@ -279,7 +279,7 @@
         ## Essentially the next iteration doesn't change x,
         ## and the iter after this will have a division by zero
         flag = 4;
-        break
+        break;
       endif
       beta = rho_1 / rho_2;
       u_1 = w + beta * u; # u at the after iteration
@@ -298,7 +298,7 @@
     endif
     if (norm (x_pr - x) <= norm (x) * eps)
       flag = 3; # Stagnation
-      break
+      break;
     endif
     x_pr = x;
     it = -it;
@@ -306,8 +306,8 @@
   resvec = resvec (1: (iter + 1));
 
   relres = resvec (iter_min + 1) / norm (b);
-  iter_min = floor(iter_min / 2); # compatibility, since it
-                                  # makes two times the effective iterations
+  iter_min = floor (iter_min / 2); # compatibility, since it
+                                   # makes two times the effective iterations
 
   if (relres <= tol)
     flag = 0;
@@ -344,7 +344,10 @@
         printf ("has relative residual %e\n", relres);
     endswitch
   endif
+
 endfunction
+
+
 %!test
 %! ## Check that all type of inputs work
 %! A = toeplitz (sparse ([2, 1, 0, 0, 0]), sparse ([2, -1, 0, 0, 0]));
@@ -428,46 +431,46 @@
 %! A (1,50) = 10000;
 %! b = ones (50,1);
 %! [x, flag, relres, iter, resvec] = tfqmr (A, b, [], 100);
-%! assert (flag, 0)
-%! assert (x, A \ b, 1e-05)
+%! assert (flag, 0);
+%! assert (x, A \ b, 1e-05);
 %! ## Detects a singular preconditioner
 %! M = ones (50);
 %! M(1, 1) = 0;
 %! [x, flag] = tfqmr (A, b, [], 100, M);
-%! assert (flag, 2)
+%! assert (flag, 2);
 
 %!test
 %! A = single (1);
 %! b = 1;
 %! [x, flag] = tfqmr (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %! A = 1;
 %! b = single (1);
 %! [x, flag] = tfqmr (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %! A = single (1);
 %! b = single (1);
 %! [x, flag] = tfqmr (A, b);
-%! assert (class (x), "single")
+%! assert (class (x), "single");
 
 %!test
 %!function y = Afun (x)
-%!   A = toeplitz ([2, 1, 0, 0], [2, -1, 0, 0]);
-%!   y = A * x;
+%!  A = toeplitz ([2, 1, 0, 0], [2, -1, 0, 0]);
+%!  y = A * x;
 %!endfunction
 %! [x, flag] = tfqmr ("Afun", [1; 2; 2; 3]);
-%! assert (x, ones(4, 1), 1e-6)
+%! assert (x, ones (4, 1), 1e-6);
 
 %!test # unpreconditioned residual
 %! A = toeplitz (sparse ([2, 1, 0, 0, 0]), sparse ([2, -1, 0, 0, 0]));
 %! b = sum (A, 2);
 %! M = magic (5);
 %! [x, flag, relres] = tfqmr (A, b, [], 3, M);
-%! assert (relres, norm (b - A * x) / norm (b), 8 * eps)
+%! assert (relres, norm (b - A * x) / norm (b), 8 * eps);
 
 %!demo # simplest use
 %! n = 20;
--- a/scripts/sparse/treelayout.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/treelayout.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 function [x_coordinate, y_coordinate, height, s] = ...
                                                  treelayout (tree, permutation)
 
-  if (nargin < 1 || nargin > 2 || nargout > 4)
+  if (nargin < 1)
     print_usage ();
   elseif (! isvector (tree) || rows (tree) != 1 || ! isnumeric (tree)
           || any (tree > length (tree)) || any (tree < 0))
@@ -72,7 +72,7 @@
 
       if (hare < i)
         ## This part of graph was checked before.
-        break
+        break;
       endif
 
       tortoise = tree(tortoise);
--- a/scripts/sparse/treeplot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/sparse/treeplot.m	Sun May 16 09:44:35 2021 +0200
@@ -40,7 +40,7 @@
 
 function treeplot (tree, node_style = "ko", edge_style = "r")
 
-  if (nargin < 1 || nargin > 3 || nargout > 0)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/specfun/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/specfun/beta.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/beta.m	Sun May 16 09:44:35 2021 +0200
@@ -43,8 +43,8 @@
 ##
 ## The Beta function can grow quite large and it is often more useful to work
 ## with the logarithm of the output rather than the function directly.
-## @xref{XREFbetaln,,betaln}, for computing the logarithm of the Beta function
-## in an efficient manner.
+## @xref{XREFbetaln,,@code{betaln}}, for computing the logarithm of the Beta
+## function in an efficient manner.
 ## @seealso{betaln, betainc, betaincinv}
 ## @end deftypefn
 
@@ -88,9 +88,8 @@
 %! assert (zeros (size (a)), beta (a, -a), tol);
 %! assert (zeros (size (a)), beta (-a, a), tol);
 
-%!error beta ()
-%!error beta (1)
-%!error beta (1,2,3)
+%!error <Invalid call> beta ()
+%!error <Invalid call> beta (1)
 %!error <A and B must be real> beta (1i, 2)
 %!error <A and B must be real> beta (2, 1i)
 %!error <A and B must have consistent sizes> beta ([1 2], [1 2 3])
--- a/scripts/specfun/betainc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/betainc.m	Sun May 16 09:44:35 2021 +0200
@@ -9,7 +9,7 @@
 ##
 ## Octave is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
+## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
 ##
 ## Octave is distributed in the hope that it will be useful, but
@@ -74,7 +74,7 @@
 
 function y = betainc (x, a, b, tail = "lower")
 
-  if (nargin < 3 || nargin > 4)
+  if (nargin < 3)
     print_usage ();
   endif
 
@@ -205,12 +205,12 @@
 %! y_ex = [0.999999999999989; 0.999999999999992; 0.999999999999995];
 %! assert (y, y_ex, -1e-14);
 
-%!assert (betainc (0.001, 20, 30), 2.750687665855991e-47, -3e-14);
-%!assert (betainc (0.0001, 20, 30), 2.819953178893307e-67, -7e-14);
-%!assert <*54383> (betainc (0.99, 20, 30, "upper"), 1.5671643161872703e-47, -7e-14);
-%!assert (betainc (0.999, 20, 30, "upper"), 1.850806276141535e-77, -7e-14);
-%!assert (betainc (0.5, 200, 300), 0.9999964565197356, -1e-15);
-%!assert (betainc (0.5, 200, 300, "upper"), 3.54348026439253e-06, -3e-13);
+%!assert (betainc (0.001, 20, 30), 2.750687665855991e-47, -3e-14)
+%!assert (betainc (0.0001, 20, 30), 2.819953178893307e-67, -7e-14)
+%!assert <*54383> (betainc (0.99, 20, 30, "upper"), 1.5671643161872703e-47, -7e-14)
+%!assert (betainc (0.999, 20, 30, "upper"), 1.850806276141535e-77, -7e-14)
+%!assert (betainc (0.5, 200, 300), 0.9999964565197356, -1e-15)
+%!assert (betainc (0.5, 200, 300, "upper"), 3.54348026439253e-06, -3e-13)
 
 ## Test trivial values
 %!test
@@ -223,10 +223,9 @@
 %! assert (betainc (0.5, 1, Inf), NaN);
 
 ## Test input validation
-%!error betainc ()
-%!error betainc (1)
-%!error betainc (1,2)
-%!error betainc (1,2,3,4,5)
+%!error <Invalid call> betainc ()
+%!error <Invalid call> betainc (1)
+%!error <Invalid call> betainc (1,2)
 %!error <must be of common size or scalars> betainc (ones (2,2), ones (1,2), 1)
 %!error <all inputs must be real> betainc (0.5i, 1, 2)
 %!error <all inputs must be real> betainc (0, 1i, 1)
--- a/scripts/specfun/betaincinv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/betaincinv.m	Sun May 16 09:44:35 2021 +0200
@@ -141,7 +141,7 @@
     x(y == 0) = 1;
     x(y == 1) = 0;
   else
-    error ("betaincinv: invalid value for TAIL")
+    error ("betaincinv: invalid value for TAIL");
   endif
 
   ## Special values have been already computed.
@@ -193,6 +193,7 @@
 
 ## subfunctions: Bisection and Newton Methods
 function xc = bisection_method (F, xl, xr, a, b, y, maxit)
+
   F_l = F (xl, a, b, y);
   F_r = F (xr, a, b, y);
   for it = 1:maxit
@@ -208,9 +209,11 @@
     F_r(flag_r) = F_c(flag_r);
     F_l(flag_c) = F_r(flag_c) = 0;
   endfor
+
 endfunction
 
 function x = newton_method (F, JF, x0, a, b, y, tol, maxit);
+
   res = -F (x0, a, b, y) ./ JF (x0, a, b);
   todo = (abs (res) >= tol * abs (x0));
   x = x0;
@@ -226,6 +229,7 @@
     todo = (abs (res) >= tol * abs (x));
   endwhile
   x += res;
+
 endfunction
 
 
@@ -267,19 +271,17 @@
 %!assert <*60528> (betaincinv (1-1e-6, 3, 1), 0.999999666666556, 5*eps)
 
 ## Test input validation
-%!error betaincinv ()
-%!error betaincinv (1)
-%!error betaincinv (1,2)
+%!error <Invalid call> betaincinv ()
+%!error <Invalid call> betaincinv (1)
+%!error <Invalid call> betaincinv (1,2)
 %!error <must be of common size or scalars>
 %! betaincinv (ones (2,2), ones (1,2), 1);
-
 %!error <must be .* floating point> betaincinv ('a', 1, 2)
 %!error <must be .* floating point> betaincinv (0, int8 (1), 1)
 %!error <must be .* floating point> betaincinv (0, 1, true)
 %!error <must be real> betaincinv (0.5i, 1, 2)
 %!error <must be real> betaincinv (0, 1i, 1)
 %!error <must be real> betaincinv (0, 1, 1i)
-
 %!error <Y must be in the range \[0, 1\]> betaincinv (-0.1,1,1)
 %!error <Y must be in the range \[0, 1\]> betaincinv (1.1,1,1)
 %!error <Y must be in the range \[0, 1\]>
--- a/scripts/specfun/betaln.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/betaln.m	Sun May 16 09:44:35 2021 +0200
@@ -68,9 +68,8 @@
 %!assert (betaln (3,4), log (beta (3,4)), eps)
 
 ## Test input validation
-%!error betaln ()
-%!error betaln (1)
-%!error betaln (1,2,3)
+%!error <Invalid call> betaln ()
+%!error <Invalid call> betaln (1)
 %!error <A and B must be real> betaln (1i, 2)
 %!error <A and B must be real> betaln (2, 1i)
 %!error <A and B must have consistent sizes> betaln ([1 2], [1 2 3])
--- a/scripts/specfun/cosint.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/cosint.m	Sun May 16 09:44:35 2021 +0200
@@ -76,7 +76,7 @@
 
 function y = cosint (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -96,7 +96,7 @@
     x = complex (real (x)(:), imag (x)(:));
   else
     x = x(:);
-  end
+  endif
 
   ## Initialize the result
   y = zeros (size (x), class (x));
@@ -106,7 +106,7 @@
 
   ## Special values
   y(x == Inf) = 0;
-  y((x == -Inf) & !signbit (imag (x))) = 1i * pi;
+  y((x == -Inf) & ! signbit (imag (x))) = 1i * pi;
   y((x == -Inf) &  signbit (imag (x))) = -1i * pi;
 
   todo(isinf (x)) = false;
@@ -136,11 +136,11 @@
     xx = complex (real (x)(todo), imag (x)(todo));
   else
     xx = x(todo);
-  end
+  endif
   ssum = - xx .^ 2 / 4; # First term of the series expansion
   ## FIXME: This is way more precision than a double value can hold.
   gma = 0.57721566490153286060651209008; # Euler gamma constant
-  yy = gma + log (complex (xx)) + ssum;  # log(complex(...) handles signed zero
+  yy = gma + log (complex (xx)) + ssum;  # log (complex (...) handles signed zero
   flag_sum = true (nnz (todo), 1);
   it = 0;
   maxit = 300;
@@ -161,7 +161,7 @@
 endfunction
 
 
-%!assert (cosint (1.1), 0.38487337742465081550, 2 * eps);
+%!assert (cosint (1.1), 0.38487337742465081550, 2 * eps)
 
 %!test
 %! x = [2, 3, pi; exp(1), 5, 6];
@@ -267,6 +267,5 @@
 %#!test <*52953>
 
 ## Test input validation
-%!error cosint ()
-%!error cosint (1,2)
+%!error <Invalid call> cosint ()
 %!error <X must be numeric> cosint ("1")
--- a/scripts/specfun/ellipke.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/ellipke.m	Sun May 16 09:44:35 2021 +0200
@@ -90,7 +90,7 @@
 
 function [k, e] = ellipke (m, tol = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -219,8 +219,7 @@
 %! assert (e, e_exp, 8*eps (e_exp));
 
 ## Test input validation
-%!error ellipke ()
-%!error ellipke (1,2,3)
+%!error <Invalid call> ellipke ()
 %!error <M must be real> ellipke (1i)
 %!error <M must be .= 1> ellipke (2)
 %!error <TOL must be a real scalar . 0> ellipke (1, i)
--- a/scripts/specfun/expint.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/expint.m	Sun May 16 09:44:35 2021 +0200
@@ -96,7 +96,7 @@
 
 function E1 = expint (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -254,7 +254,7 @@
 %!         9.018757389858152e-22 - 1.475771020004195e-21i, -4*eps);
 
 %!test <*47738>
-%! assert (expint (10i), 0.0454564330044554 + 0.0875512674239774i, -4*eps);
+%! assert (expint (10i), 0.0454564330044554 + 0.0875512674239774i, -5*eps);
 
 ## Test preservation or conversion of the class
 %!assert (class (expint (single (1))), "single")
@@ -273,6 +273,5 @@
 %!assert (! isreal (expint (-1)))
 
 ## Test input validation
-%!error expint ()
-%!error expint (1,2)
+%!error <Invalid call> expint ()
 %!error <X must be numeric> expint ("1")
--- a/scripts/specfun/factor.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/factor.m	Sun May 16 09:44:35 2021 +0200
@@ -43,7 +43,7 @@
 
 function [pf, n] = factor (q)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -120,8 +120,7 @@
 %! assert (n, double (3));
 
 ## Test input validation
-%!error factor ()
-%!error factor (1,2)
+%!error <Invalid call> factor ()
 %!error <Q must be a real non-negative integer> factor (6i)
 %!error <Q must be a real non-negative integer> factor ([1,2])
 %!error <Q must be a real non-negative integer> factor (1.5)
--- a/scripts/specfun/factorial.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/factorial.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function x = factorial (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! isreal (n) || any (n(:) < 0 | n(:) != fix (n(:))))
     error ("factorial: all N must be real non-negative integers");
@@ -53,9 +53,9 @@
   ## This doesn't seem particularly worth copying--for example uint8 would
   ## saturate for n > 5.  If desired, however, the following code could be
   ## uncommented.
-  # if (! isfloat (x))
-  #   x = cast (x, class (n));
-  # endif
+  ## if (! isfloat (x))
+  ##   x = cast (x, class (n));
+  ## endif
 
 endfunction
 
@@ -65,8 +65,7 @@
 %!assert (factorial (70), exp (sum (log (1:70))), -128*eps)
 %!assert (factorial (0), 1)
 
-%!error factorial ()
-%!error factorial (1,2)
+%!error <Invalid call> factorial ()
 %!error <must be real non-negative integers> factorial (2i)
 %!error <must be real non-negative integers> factorial (-3)
 %!error <must be real non-negative integers> factorial (5.5)
--- a/scripts/specfun/gammainc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/gammainc.m	Sun May 16 09:44:35 2021 +0200
@@ -9,7 +9,7 @@
 ##
 ## Octave is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
+## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
 ##
 ## Octave is distributed in the hope that it will be useful, but
@@ -95,7 +95,7 @@
 
 function y = gammainc (x, a, tail = "lower")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -299,6 +299,7 @@
 
 ## a == 1.
 function y = gammainc_a1 (x, tail)
+
   if (strcmp (tail, "lower"))
     if (abs (x) < 1/2)
       y = - expm1 (-x);
@@ -316,12 +317,14 @@
   else
     y = 1 ./ x;
   endif
+
 endfunction
 
 ## positive integer a; exp (x) and a! both under 1/eps
 ## uses closed-form expressions for nonnegative integer a
 ## -- http://mathworld.wolfram.com/IncompleteGammaFunction.html.
 function y = gammainc_an (x, a, tail)
+
   y = t = ones (size (x), class (x));
   i = 1;
   while (any (a(:) > i))
@@ -339,12 +342,14 @@
   elseif (strcmp (tail, "scaledupper"))
     y .*= exp (-x) ./ D(x, a);
   endif
+
 endfunction
 
 ## x + 0.25 < a | x < 0 | abs(x) < 1.
 ## Numerical Recipes in Fortran 77 (6.2.5)
 ## series
 function y = gammainc_s (x, a, tail)
+
   if (strcmp (tail, "scaledlower") || strcmp (tail, "scaledupper"))
     y = ones (size (x), class (x));
     term = x ./ (a + 1);
@@ -367,6 +372,7 @@
   elseif (strcmp (tail, "scaledupper"))
     y = 1 ./ D (x,a) - y;
   endif
+
 endfunction
 
 ## x positive and large relative to a
@@ -375,6 +381,7 @@
 ## Lentz's algorithm
 ## __gammainc__ in libinterp/corefcn/__gammainc__.cc
 function y = gammainc_l (x, a, tail)
+
   y = __gammainc__ (x, a);
   if (strcmp (tail,  "lower"))
     y = 1 - y .* D (x, a);
@@ -383,6 +390,7 @@
   elseif (strcmp (tail, "scaledlower"))
     y = 1 ./ D (x, a) - y;
   endif
+
 endfunction
 
 ## Compute exp(-x)*x^a/Gamma(a+1) in a stable way for x and a large.
@@ -391,6 +399,7 @@
 ## SIAM J. Sci. Stat. Comput., 7(3), 1986
 ## which quotes Section 5, Abramowitz&Stegun 6.1.40, 6.1.41.
 function y = D (x, a)
+
   athresh = 10;  # FIXME: can this be better tuned?
   y = zeros (size (x), class (x));
 
@@ -430,7 +439,7 @@
   endif
 
   ii = (x < 0) & (a == fix (a));
-  if (any(ii))  # remove spurious imaginary part.
+  if (any (ii))  # remove spurious imaginary part.
     y(ii) = real (y(ii));
   endif
 
@@ -478,9 +487,9 @@
 %!        -2.9582761911890713293e7-1i * 9.612022339061679758e6, -30*eps)
 %!assert (gammainc (-10, 10, "upper"), -3.112658165341493126871616e7, ...
 %!        -2*eps)
-%!assert (gammainc (-10, 10, "scaledlower"), 0.5128019364747265, -1e-14);
-%!assert (gammainc (-10, 10, "scaledupper"), -0.5128019200000000, -1e-14);
-%!assert (gammainc (200, 201, "upper"), 0.518794309678684497, -2 * eps);
+%!assert (gammainc (-10, 10, "scaledlower"), 0.5128019364747265, -1e-14)
+%!assert (gammainc (-10, 10, "scaledupper"), -0.5128019200000000, -1e-14)
+%!assert (gammainc (200, 201, "upper"), 0.518794309678684497, -2 * eps)
 %!assert (gammainc (200, 201, "scaledupper"),
 %!        18.4904360746560462660798514, -eps)
 ## Here we are very good (no D (x,a)) involved
@@ -529,7 +538,7 @@
 %! y_exp = 9.995001666250085e-04;
 %! assert (gammainc (1/1000, 1), y_exp, -eps);
 
-%!xtest <53612>
+%!test <53612>
 %! assert (gammainc (-20, 1.1, "upper"), ...
 %!         6.50986687074979e8 + 2.11518396291149e8*i, -1e-13);
 
@@ -566,9 +575,8 @@
 %!assert (class (gammainc (1, int8 (0.5))) == "double")
 
 ## Test input validation
-%!error gammainc ()
-%!error gammainc (1)
-%!error gammainc (1,2,3,4)
+%!error <Invalid call> gammainc ()
+%!error <Invalid call> gammainc (1)
 %!error <must be of common size or scalars> gammainc ([0, 0],[0; 0])
 %!error <must be of common size or scalars> gammainc ([1 2 3], [1 2])
 %!error <all inputs must be real> gammainc (2+i, 1)
--- a/scripts/specfun/gammaincinv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/gammaincinv.m	Sun May 16 09:44:35 2021 +0200
@@ -9,7 +9,7 @@
 ##
 ## Octave is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
+## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
 ##
 ## Octave is distributed in the hope that it will be useful, but
@@ -87,7 +87,7 @@
 
 function x = gammaincinv (y, a, tail = "lower")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -148,7 +148,7 @@
     q = y;
     p = 1 - q;
   else
-    error ("gammaincinv: invalid value for TAIL")
+    error ("gammaincinv: invalid value for TAIL");
   endif
 
   todo = (a != 1) & (y != 0) & (y != 1);
@@ -256,6 +256,7 @@
 
 ## subfunction: Newton's Method
 function x = newton_method (F, JF, y, a, x0, tol, maxit);
+
   l = numel (y);
   res = -F (y, a, x0) ./ JF (a, x0);
   todo = (abs (res) >= tol * abs (x0));
@@ -267,6 +268,7 @@
     todo = (abs (res) >= tol * abs (x));
   endwhile
   x += res;
+
 endfunction
 
 
@@ -312,9 +314,8 @@
 %!assert (class (gammaincinv (single (0.5), int8 (1))), "single")
 
 ## Test input validation
-%!error gammaincinv ()
-%!error gammaincinv (1)
-%!error gammaincinv (1, 2, 3, 4)
+%!error <Invalid call> gammaincinv ()
+%!error <Invalid call> gammaincinv (1)
 %!error <must be of common size or scalars>
 %! gammaincinv (ones (2,2), ones (1,2), 1);
 %!error <all inputs must be real> gammaincinv (0.5i, 1)
--- a/scripts/specfun/isprime.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/isprime.m	Sun May 16 09:44:35 2021 +0200
@@ -69,7 +69,7 @@
 
 function t = isprime (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (any (fix (x) != x))
     error ("isprime: X contains non-integer entries");
@@ -173,7 +173,6 @@
 %!assert (isprime (magic (3)), logical ([0, 0, 0; 1, 1, 1; 0, 0, 1]))
 
 ## Test input validation
-%!error isprime ()
-%!error isprime (1, 2)
+%!error <Invalid call> isprime ()
 %!error <X contains non-integer entries> isprime (0.5i)
 %!error <X contains non-integer entries> isprime (0.5)
--- a/scripts/specfun/lcm.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/lcm.m	Sun May 16 09:44:35 2021 +0200
@@ -58,7 +58,8 @@
 
 %!assert (lcm (3, 5, 7, 15), 105)
 
-%!error lcm ()
-%!error lcm (1)
+## Test input validation
+%!error <Invalid call> lcm ()
+%!error <Invalid call> lcm (1)
 %!error <same size or scalar> lcm ([1 2], [1 2 3])
 %!error <arguments must be numeric> lcm ([1 2], {1 2})
--- a/scripts/specfun/legendre.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/legendre.m	Sun May 16 09:44:35 2021 +0200
@@ -167,7 +167,7 @@
 
   persistent warned_overflow = false;
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -311,9 +311,8 @@
 %! assert (result, expected);
 
 ## Test input validation
-%!error legendre ()
-%!error legendre (1)
-%!error legendre (1,2,3,4)
+%!error <Invalid call> legendre ()
+%!error <Invalid call> legendre (1)
 %!error <must be a real non-negative integer> legendre (i, [-1, 0, 1])
 %!error <must be a real non-negative integer> legendre ([1, 2], [-1, 0, 1])
 %!error <must be a real non-negative integer> legendre (-1, [-1, 0, 1])
--- a/scripts/specfun/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/beta.m \
   %reldir%/betainc.m \
   %reldir%/betaincinv.m \
--- a/scripts/specfun/nchoosek.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/nchoosek.m	Sun May 16 09:44:35 2021 +0200
@@ -149,9 +149,8 @@
 %!assert (size (nchoosek (1:5,0)), [1 0])
 
 ## Test input validation
-%!error nchoosek ()
-%!error nchoosek (1)
-%!error nchoosek (1,2,3)
+%!error <Invalid call> nchoosek ()
+%!error <Invalid call> nchoosek (1)
 
 %!error nchoosek (100, 2i)
 %!error nchoosek (100, [2 3])
--- a/scripts/specfun/nthroot.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/nthroot.m	Sun May 16 09:44:35 2021 +0200
@@ -106,9 +106,8 @@
 %! assert (lastwarn (), warnmsg);
 
 ## Test input validation
-%!error nthroot ()
-%!error nthroot (1)
-%!error nthroot (1,2,3)
+%!error <Invalid call> nthroot ()
+%!error <Invalid call> nthroot (1)
 %!error <X must not contain complex values> nthroot (1+j, 2)
 %!error <N must be a real nonzero scalar> nthroot (1, i)
 %!error <N must be a real nonzero scalar> nthroot (1, [1 2])
--- a/scripts/specfun/perms.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/perms.m	Sun May 16 09:44:35 2021 +0200
@@ -58,7 +58,7 @@
 
 function A = perms (v)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -123,8 +123,7 @@
 %!assert (unique (perms (1:5)(:))', 1:5)
 %!assert (perms (int8 (1:4)), int8 (perms (1:4)))
 
-%!error perms ()
-%!error perms (1, 2)
+%!error <Invalid call> perms ()
 
 ## Should work for any array type, such as cells and structs, and not
 ## only for numeric data.
@@ -161,5 +160,5 @@
 %!test <*52432>
 %! s = struct ();
 %! s(1) = [];
-%! assert (perms (reshape (s, 0, 0)), reshape (s, 1, 0))
-%! assert (perms (reshape (s, 0, 1)), reshape (s, 1, 0))
+%! assert (perms (reshape (s, 0, 0)), reshape (s, 1, 0));
+%! assert (perms (reshape (s, 0, 1)), reshape (s, 1, 0));
--- a/scripts/specfun/pow2.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/pow2.m	Sun May 16 09:44:35 2021 +0200
@@ -47,12 +47,14 @@
 
 function y = pow2 (f, e)
 
+  if (nargin < 1)
+    print_usage ();
+  endif
+
   if (nargin == 1)
     y = 2 .^ f;
-  elseif (nargin == 2)
+  else
     y = f .* (2 .^ e);
-  else
-    print_usage ();
   endif
 
 endfunction
@@ -69,5 +71,4 @@
 %! z = x .* (2 .^ y);
 %! assert (pow2 (x,y), z, sqrt (eps));
 
-%!error pow2 ()
-%!error pow2 (1,2,3)
+%!error <Invalid call> pow2 ()
--- a/scripts/specfun/primes.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/primes.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 
 function p = primes (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -108,7 +108,6 @@
 %!assert (class (primes (single (10))), "single")
 %!assert (class (primes (uint8 (10))), "uint8")
 
-%!error primes ()
-%!error primes (1, 2)
+%!error <Invalid call> primes ()
 %!error <N must be a numeric scalar> primes ("1")
 %!error <N must be a numeric scalar> primes (ones (2,2))
--- a/scripts/specfun/reallog.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/reallog.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function y = reallog (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (iscomplex (x) || any (x(:) < 0))
     error ("reallog: produced complex result");
@@ -50,7 +50,6 @@
 %! x = rand (10, 10);
 %! assert (reallog (x), log (x));
 
-%!error reallog ()
-%!error reallog (1,2)
+%!error <Invalid call> reallog ()
 %!error <produced complex result> reallog (2i)
 %!error <produced complex result> reallog (-1)
--- a/scripts/specfun/realpow.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/realpow.m	Sun May 16 09:44:35 2021 +0200
@@ -54,7 +54,6 @@
 %! assert (x.^y, realpow (x,y));
 %!assert <47775> (realpow (1i,2), -1)
 
-%!error realpow ()
-%!error realpow (1)
-%!error realpow (1,2,3)
+%!error <Invalid call> realpow ()
+%!error <Invalid call> realpow (1)
 %!error <produced complex result> realpow (-1, 1/2)
--- a/scripts/specfun/realsqrt.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/realsqrt.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function y = realsqrt (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (iscomplex (x) || any (x(:) < 0))
     error ("realsqrt: produced complex result");
@@ -50,6 +50,5 @@
 %! x = rand (10, 10);
 %! assert (realsqrt (x), sqrt (x));
 
-%!error realsqrt ()
-%!error realsqrt (1,2)
+%!error <Invalid call> realsqrt ()
 %!error <produced complex result> realsqrt (-1)
--- a/scripts/specfun/sinint.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/specfun/sinint.m	Sun May 16 09:44:35 2021 +0200
@@ -54,7 +54,7 @@
 
 function y = sinint (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -75,7 +75,7 @@
     x = complex (real (x)(:), imag (x)(:));
   else
     x = x(:);
-  end
+  endif
 
   ## Initialize the result
   y = zeros (size (x), class (x));
@@ -202,14 +202,13 @@
 %!      -0.000099999999944461111128 + 0.99999999833338888972e-6*1i
 %!      -1.5386156269726011209 - 0.053969388020443786229*1i ];
 %! B = sinint (x);
-%! assert (A, B, -3*eps)
+%! assert (A, B, -3*eps);
 %! B = sinint (single (x));
-%! assert (A, B, -3*eps ("single"))
+%! assert (A, B, -3*eps ("single"));
 
 ## FIXME: Need a test for bug #52953
 %#!test <*52953>
 
 ## Test input validation
-%!error sinint ()
-%!error sinint (1,2)
+%!error <Invalid call> sinint ()
 %!error <X must be numeric> sinint ("1")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/special-matrix/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/special-matrix/gallery.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/gallery.m	Sun May 16 09:44:35 2021 +0200
@@ -413,12 +413,12 @@
 ## uniformdata) by Nicholas J. Higham <Nicholas.J.Higham@manchester.ac.uk>
 ## Adapted for Octave and into single gallery function by Carnë Draug
 
-function [varargout] = gallery (name, varargin)
+function varargout = gallery (name, varargin)
 
   if (nargin < 1)
     print_usage ();
   elseif (! ischar (name))
-    error ("gallery: NAME must be a string.");
+    error ("gallery: NAME must be a string");
   endif
 
   ## NOTE: there isn't a lot of input check in the individual functions
@@ -439,7 +439,7 @@
 
   switch (tolower (name))
     case "binomial"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "cauchy"     , [varargout{1:n_out}] = cauchy      (varargin{:});
     case "chebspec"   , [varargout{1:n_out}] = chebspec    (varargin{:});
     case "chebvand"   , [varargout{1:n_out}] = chebvand    (varargin{:});
@@ -470,7 +470,7 @@
     case "lauchli"    , [varargout{1:n_out}] = lauchli     (varargin{:});
     case "lehmer"     , [varargout{1:n_out}] = lehmer      (varargin{:});
     case "leslie"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "lesp"       , [varargout{1:n_out}] = lesp        (varargin{:});
     case "lotkin"     , [varargout{1:n_out}] = lotkin      (varargin{:});
     case "minij"      , [varargout{1:n_out}] = minij       (varargin{:});
@@ -483,19 +483,19 @@
     case "poisson"    , [varargout{1:n_out}] = poisson     (varargin{:});
     case "prolate"    , [varargout{1:n_out}] = prolate     (varargin{:});
     case "randcolu"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "randcorr"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "randhess"    , [varargout{1:n_out}] = randhess    (varargin{:});
     case "randjorth"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "rando"       , [varargout{1:n_out}] = rando       (varargin{:});
     case "randsvd"     , [varargout{1:n_out}] = randsvd     (varargin{:});
     case "redheff"     , [varargout{1:n_out}] = redheff     (varargin{:});
     case "riemann"     , [varargout{1:n_out}] = riemann     (varargin{:});
     case "ris"         , [varargout{1:n_out}] = ris         (varargin{:});
     case "sampling"
-      error ("gallery: matrix %s not implemented.", name);
+      error ("gallery: matrix %s not implemented", name);
     case "smoke"       , [varargout{1:n_out}] = smoke       (varargin{:});
     case "toeppd"      , [varargout{1:n_out}] = toeppd      (varargin{:});
     case "toeppen"     , [varargout{1:n_out}] = toeppen     (varargin{:});
@@ -534,11 +534,11 @@
   ##     pp. 279-313, 1962. (States the totally positive property on p. 295.)
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for cauchy matrix.");
+    error ("gallery: 1 or 2 arguments are required for cauchy matrix");
   elseif (! isnumeric (x))
-    error ("gallery: X must be numeric for cauchy matrix.");
+    error ("gallery: X must be numeric for cauchy matrix");
   elseif (nargin == 2 && ! isnumeric (y))
-    error ("gallery: Y must be numeric for cauchy matrix.");
+    error ("gallery: Y must be numeric for cauchy matrix");
   endif
 
   n = numel (x);
@@ -548,7 +548,7 @@
   elseif (n > 1 && isvector (x))
     ## do nothing
   else
-    error ("gallery: X be an integer or a vector for cauchy matrix.");
+    error ("gallery: X be an integer or a vector for cauchy matrix");
   endif
 
   if (nargin == 1)
@@ -559,7 +559,7 @@
   x = x(:);
   y = y(:);
   if (numel (x) != numel (y))
-    error ("gallery: X and Y must be vectors of same length for cauchy matrix.");
+    error ("gallery: X and Y must be vectors of same length for cauchy matrix");
   endif
 
   C = 1 ./ (x .+ y.');
@@ -586,11 +586,11 @@
   ##      derivative, SIAM J. Sci. Stat. Comput., 9 (1988), pp. 1050-1057.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for chebspec matrix.");
+    error ("gallery: 1 to 2 arguments are required for chebspec matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for chebspec matrix.");
+    error ("gallery: N must be an integer for chebspec matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a scalar for chebspec matrix.");
+    error ("gallery: K must be a scalar for chebspec matrix");
   endif
 
   ## k = 1 case obtained from k = 0 case with one bigger n.
@@ -598,7 +598,7 @@
     case (0), # do nothing
     case (1), n = n + 1;
     otherwise
-      error ("gallery: K should be either 0 or 1 for chebspec matrix.");
+      error ("gallery: K should be either 0 or 1 for chebspec matrix");
   endswitch
 
   n -= 1;
@@ -648,7 +648,7 @@
   ##     pp. 23-41.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for chebvand matrix.");
+    error ("gallery: 1 or 2 arguments are required for chebvand matrix");
   endif
 
   ## because the order of the arguments changes if nargin is 1 or 2 ...
@@ -659,7 +659,7 @@
 
   n = numel (p);
   if (! isnumeric (p))
-    error ("gallery: P must be numeric for chebvand matrix.");
+    error ("gallery: P must be numeric for chebvand matrix");
   elseif (isscalar (p) && fix (p) == p)
     n = p;
     p = linspace (0, 1, n);
@@ -671,7 +671,7 @@
   if (nargin == 1)
     m = n;
   elseif (! isnumeric (m) || ! isscalar (m))
-    error ("gallery: M must be a scalar for chebvand matrix.");
+    error ("gallery: M must be a scalar for chebvand matrix");
   endif
 
   C = ones (m, n);
@@ -699,13 +699,13 @@
   ##      Hessenberg matrices, SIAM Review, 13 (1971), pp. 220-221.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for chow matrix.");
+    error ("gallery: 1 to 3 arguments are required for chow matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for chow matrix.");
+    error ("gallery: N must be an integer for chow matrix");
   elseif (! isnumeric (alpha) || ! isscalar (alpha))
-    error ("gallery: ALPHA must be a scalar for chow matrix.");
+    error ("gallery: ALPHA must be a scalar for chow matrix");
   elseif (! isnumeric (delta) || ! isscalar (delta))
-    error ("gallery: DELTA must be a scalar for chow matrix.");
+    error ("gallery: DELTA must be a scalar for chow matrix");
   endif
 
   A = toeplitz (alpha.^(1:n), [alpha 1 zeros(1, n-2)]) + delta * eye (n);
@@ -727,9 +727,9 @@
   ##   P.J. Davis, Circulant Matrices, John Wiley, 1977.
 
   if (nargin != 1)
-    error ("gallery: 1 argument is required for circul matrix.");
+    error ("gallery: 1 argument is required for circul matrix");
   elseif (! isnumeric (v))
-    error ("gallery: V must be numeric for circul matrix.");
+    error ("gallery: V must be numeric for circul matrix");
   endif
 
   n = numel (v);
@@ -739,7 +739,7 @@
   elseif (n > 1 && isvector (v))
     ## do nothing
   else
-    error ("gallery: X must be a scalar or a vector for circul matrix.");
+    error ("gallery: X must be a scalar or a vector for circul matrix");
   endif
 
   v = v(:).';   # Make sure v is a row vector
@@ -772,11 +772,11 @@
   ##      Linear Algebra and Appl., 150 (1991), pp. 341-360.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for clement matrix.");
+    error ("gallery: 1 or 2 arguments are required for clement matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for clement matrix.");
+    error ("gallery: N must be an integer for clement matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for clement matrix.");
+    error ("gallery: K must be a numeric scalar for clement matrix");
   endif
 
   n -= 1;
@@ -789,7 +789,7 @@
     y = sqrt (x.*z);
     A = diag (y, -1) + diag (y, 1);
   else
-    error ("gallery: K must have a value of 0 or 1 for clement matrix.");
+    error ("gallery: K must have a value of 0 or 1 for clement matrix");
   endif
 endfunction
 
@@ -808,11 +808,11 @@
   ##   triangular matrices, SIAM Review, 29 (1987), pp. 575-596.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for compar matrix.");
+    error ("gallery: 1 or 2 arguments are required for compar matrix");
   elseif (! isnumeric (A) || ndims (A) != 2)
-    error ("gallery: A must be a 2-D matrix for compar matrix.");
+    error ("gallery: A must be a 2-D matrix for compar matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for compar matrix.");
+    error ("gallery: K must be a numeric scalar for compar matrix");
   endif
 
   [m, n] = size (A);
@@ -840,7 +840,7 @@
     if (all (A == triu (A))), C = triu (C); endif
 
   else
-    error ("gallery: K must have a value of 0 or 1 for compar matrix.");
+    error ("gallery: K must have a value of 0 or 1 for compar matrix");
   endif
 
 endfunction
@@ -869,13 +869,13 @@
   ##      (Algorithm 674), ACM Trans. Math. Soft., 14 (1988), pp. 381-396.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for condex matrix.");
+    error ("gallery: 1 to 3 arguments are required for condex matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for condex matrix.");
+    error ("gallery: N must be an integer for condex matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for condex matrix.");
+    error ("gallery: K must be a numeric scalar for condex matrix");
   elseif (! isnumeric (theta) || ! isscalar (theta))
-    error ("gallery: THETA must be a numeric scalar for condex matrix.");
+    error ("gallery: THETA must be a numeric scalar for condex matrix");
   endif
 
   if (k == 1)       # Cline and Rew (1983), Example B.
@@ -905,7 +905,7 @@
     A = eye (n) + theta*P;
 
   else
-    error ("gallery: unknown estimator K '%d' for condex matrix.", k);
+    error ("gallery: unknown estimator K '%d' for condex matrix", k);
   endif
 
   ## Pad out with identity as necessary.
@@ -929,11 +929,11 @@
   ##   elimination: see NA Digest Volume 89, Issue 3 (January 22, 1989).
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for cycol matrix.");
+    error ("gallery: 1 or 2 arguments are required for cycol matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be a 1 or 2 element integer for cycol matrix.");
+    error ("gallery: N must be a 1 or 2 element integer for cycol matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a scalar for cycol matrix.");
+    error ("gallery: K must be a scalar for cycol matrix");
   endif
 
   ## Parameter n specifies dimension: m-by-n
@@ -964,11 +964,11 @@
   ##   pp. 271-283.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 or 2 arguments are required for dorr matrix.");
+    error ("gallery: 1 or 2 arguments are required for dorr matrix");
   elseif (! isscalar (n) || ! isnumeric (n) || fix (n) != n)
-    error ("gallery: N must be an integer for dorr matrix.");
+    error ("gallery: N must be an integer for dorr matrix");
   elseif (! isscalar (theta) || ! isnumeric (theta))
-    error ("gallery: THETA must be a numeric scalar for dorr matrix.");
+    error ("gallery: THETA must be a numeric scalar for dorr matrix");
   endif
 
   c = zeros (n, 1);
@@ -1023,11 +1023,11 @@
   ##      (0,1) matrix, Linear Algebra and Appl., 183 (1993), pp. 147-153.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for dramadah matrix.");
+    error ("gallery: 1 to 2 arguments are required for dramadah matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for dramadah matrix.");
+    error ("gallery: N must be an integer for dramadah matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for dramadah matrix.");
+    error ("gallery: K must be a numeric scalar for dramadah matrix");
   endif
 
   switch (k)
@@ -1061,7 +1061,7 @@
       A = toeplitz (c, [1 1 zeros(1,n-2)]);
 
     otherwise
-      error ("gallery: unknown K '%d' for dramadah matrix.", k);
+      error ("gallery: unknown K '%d' for dramadah matrix", k);
   endswitch
 endfunction
 
@@ -1087,9 +1087,9 @@
   ##      Birkhauser, Basel, and Academic Press, New York, 1977, p. 159.
 
   if (nargin != 1)
-    error ("gallery: 1 argument is required for fiedler matrix.");
+    error ("gallery: 1 argument is required for fiedler matrix");
   elseif (! isnumeric (c))
-    error ("gallery: C must be numeric for fiedler matrix.");
+    error ("gallery: C must be numeric for fiedler matrix");
   endif
 
   n = numel (c);
@@ -1099,7 +1099,7 @@
   elseif (n > 1 && isvector (c))
     ## do nothing
   else
-    error ("gallery: C must be an integer or a vector for fiedler matrix.");
+    error ("gallery: C must be an integer or a vector for fiedler matrix");
   endif
   c = c(:).';           # Ensure c is a row vector.
 
@@ -1115,13 +1115,13 @@
   ##   ALPHA defaults to SQRT(EPS) and LAMBDA to 0.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for forsythe matrix.");
+    error ("gallery: 1 to 3 arguments are required for forsythe matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for forsythe matrix.");
+    error ("gallery: N must be an integer for forsythe matrix");
   elseif (! isnumeric (alpha) || ! isscalar (alpha))
-    error ("gallery: ALPHA must be a numeric scalar for forsythe matrix.");
+    error ("gallery: ALPHA must be a numeric scalar for forsythe matrix");
   elseif (! isnumeric (lambda) || ! isscalar (lambda))
-    error ("gallery: LAMBDA must be a numeric scalar for forsythe matrix.");
+    error ("gallery: LAMBDA must be a numeric scalar for forsythe matrix");
   endif
 
   A = jordbloc (n, lambda);
@@ -1167,11 +1167,11 @@
   ##      Comput., 7 (1986), pp. 835-839.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for frank matrix.");
+    error ("gallery: 1 to 2 arguments are required for frank matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for frank matrix.");
+    error ("gallery: N must be an integer for frank matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for frank matrix.");
+    error ("gallery: K must be a numeric scalar for frank matrix");
   endif
 
   p = n:-1:1;
@@ -1181,15 +1181,15 @@
     case (0), # do nothing
     case (1), F = F(p,p)';
     otherwise
-      error ("gallery: K must have a value of 0 or 1 for frank matrix.");
+      error ("gallery: K must have a value of 0 or 1 for frank matrix");
   endswitch
 endfunction
 
 function c = gcdmat (n)
   if (nargin != 1)
-    error ("gallery: 1 argument is required for gcdmat matrix.");
+    error ("gallery: 1 argument is required for gcdmat matrix");
   elseif (! isscalar (n) || ! isnumeric (n) || fix (n) != n)
-    error ("gallery: N must be an integer for gcdmat matrix.");
+    error ("gallery: N must be an integer for gcdmat matrix");
   endif
   c = gcd (repmat ((1:n)', [1 n]), repmat (1:n, [n 1]));
 endfunction
@@ -1213,13 +1213,13 @@
   ##   Math. Comp., 23 (1969), pp. 119-125.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for gearmat matrix.");
+    error ("gallery: 1 to 3 arguments are required for gearmat matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for gearmat matrix.");
+    error ("gallery: N must be an integer for gearmat matrix");
   elseif (! isnumeric (i) || ! isscalar (i) || i == 0 || abs (i) > n)
-    error ("gallery: I must be a nonzero scalar, and abs (I) <= N for gearmat matrix.");
+    error ("gallery: I must be a nonzero scalar, and abs (I) <= N for gearmat matrix");
   elseif (! isnumeric (j) || ! isscalar (j) || i == 0 || abs (j) > n)
-    error ("gallery: J must be a nonzero scalar, and abs (J) <= N for gearmat matrix.");
+    error ("gallery: J must be a nonzero scalar, and abs (J) <= N for gearmat matrix");
   endif
 
   A = diag (ones (n-1, 1), -1) + diag (ones (n-1, 1), 1);
@@ -1243,11 +1243,11 @@
   ##        Appl., 13 (1992), pp. 796-825.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for grcar matrix.");
+    error ("gallery: 1 to 2 arguments are required for grcar matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for grcar matrix.");
+    error ("gallery: N must be an integer for grcar matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for grcar matrix.");
+    error ("gallery: K must be a numeric scalar for grcar matrix");
   endif
 
   G = tril (triu (ones (n)), k) - diag (ones (n-1, 1), -1);
@@ -1267,13 +1267,13 @@
   ##   Berlin, 1987. (pp. 86-87)
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for hanowa matrix.");
+    error ("gallery: 1 to 2 arguments are required for hanowa matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for hanowa matrix.");
+    error ("gallery: N must be an integer for hanowa matrix");
   elseif (rem (n, 2) != 0)
-    error ("gallery: N must be even for hanowa matrix.");
+    error ("gallery: N must be even for hanowa matrix");
   elseif (! isnumeric (d) || ! isscalar (d))
-    error ("gallery: D must be a numeric scalar for hanowa matrix.");
+    error ("gallery: D must be a numeric scalar for hanowa matrix");
   endif
 
   m = n/2;
@@ -1307,9 +1307,9 @@
   ##      Press, 1965.
 
   if (nargin != 1)
-    error ("gallery: 1 argument is required for house matrix.");
+    error ("gallery: 1 argument is required for house matrix");
   elseif (! isnumeric (x) || ! isvector (x))
-    error ("gallery: X must be a vector for house matrix.");
+    error ("gallery: X must be a vector for house matrix");
   endif
 
   ## must be a column vector
@@ -1331,7 +1331,7 @@
 function A = integerdata (varargin)
 
   if (nargin < 3)
-    error ("gallery: At least 3 arguments required for integerdata matrix.");
+    error ("gallery: At least 3 arguments required for integerdata matrix");
   endif
 
   if (isnumeric (varargin{end}))
@@ -1394,9 +1394,9 @@
   ##       Operator Theory, 10 (1987), pp. 82-95.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for invhess matrix.");
+    error ("gallery: 1 to 2 arguments are required for invhess matrix");
   elseif (! isnumeric (x))
-    error ("gallery: X must be numeric for invhess matrix.");
+    error ("gallery: X must be numeric for invhess matrix");
   endif
 
   if (isscalar (x) && fix (x) == x)
@@ -1405,13 +1405,13 @@
   elseif (! isscalar (x) && isvector (x))
     n = numel (x);
   else
-    error ("gallery: X must be an integer scalar, or a vector for invhess matrix.");
+    error ("gallery: X must be an integer scalar, or a vector for invhess matrix");
   endif
 
   if (nargin < 2)
     y = -x(1:end-1);
   elseif (! isvector (y) || numel (y) != numel (x) -1)
-    error ("gallery: Y must be a vector of length -1 than X for invhess matrix.");
+    error ("gallery: Y must be a vector of length -1 than X for invhess matrix");
   endif
 
   x = x(:);
@@ -1436,10 +1436,10 @@
   ##   of involutory and of idempotent matrices, Numer. Math. 5 (1963),
   ##   pp. 234-237.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for invol matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for invol matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for invol matrix.");
+    error ("gallery: N must be an integer for invol matrix");
   endif
 
   A = hilb (n);
@@ -1470,11 +1470,11 @@
   ##   Dept. of Mathematics, University of Bradford, 1993.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for ipjfact matrix.");
+    error ("gallery: 1 to 2 arguments are required for ipjfact matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for ipjfact matrix.");
+    error ("gallery: N must be an integer for ipjfact matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for ipjfact matrix.");
+    error ("gallery: K must be a numeric scalar for ipjfact matrix");
   endif
 
   c = cumprod (2:n+1);
@@ -1486,7 +1486,7 @@
     case (0), # do nothing
     case (1), A = ones (n) ./ A;
     otherwise
-      error ("gallery: K must have a value of 0 or 1 for ipjfact matrix.");
+      error ("gallery: K must have a value of 0 or 1 for ipjfact matrix");
   endswitch
 
   if (nargout == 2)
@@ -1507,7 +1507,7 @@
       endif
 
     else
-      error ("gallery: K must have a value of 0 or 1 for ipjfact matrix.");
+      error ("gallery: K must have a value of 0 or 1 for ipjfact matrix");
     endif
 
     detA = d;
@@ -1520,11 +1520,11 @@
   ##   LAMBDA.  LAMBDA = 1 is the default.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for jordbloc matrix.");
+    error ("gallery: 1 to 2 arguments are required for jordbloc matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for jordbloc matrix.");
+    error ("gallery: N must be an integer for jordbloc matrix");
   elseif (! isnumeric (lambda) || ! isscalar (lambda))
-    error ("gallery: LAMBDA must be a numeric scalar for jordbloc matrix.");
+    error ("gallery: LAMBDA must be a numeric scalar for jordbloc matrix");
   endif
 
   J = lambda * eye (n) + diag (ones (n-1, 1), 1);
@@ -1558,13 +1558,13 @@
   ##      triangular matrices, SIAM Review, 29 (1987), pp. 575-596.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for kahan matrix.");
+    error ("gallery: 1 to 3 arguments are required for kahan matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be a 1 or 2 element integer for kahan matrix.");
+    error ("gallery: N must be a 1 or 2 element integer for kahan matrix");
   elseif (! isnumeric (theta) || ! isscalar (theta))
-    error ("gallery: THETA must be a numeric scalar for kahan matrix.");
+    error ("gallery: THETA must be a numeric scalar for kahan matrix");
   elseif (! isnumeric (pert) || ! isscalar (pert))
-    error ("gallery: PERT must be a numeric scalar for kahan matrix.");
+    error ("gallery: PERT must be a numeric scalar for kahan matrix");
   endif
 
   ## Parameter n specifies dimension: r-by-n
@@ -1603,11 +1603,11 @@
   ##    10 (1989), pp. 135-146 (and see the references therein).
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for lauchli matrix.");
+    error ("gallery: 1 to 2 arguments are required for lauchli matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lauchli matrix.");
+    error ("gallery: N must be an integer for lauchli matrix");
   elseif (! isscalar (rho))
-    error ("gallery: RHO must be a scalar for lauchli matrix.");
+    error ("gallery: RHO must be a scalar for lauchli matrix");
   endif
 
   A = (1:n)'*ones (1,n);
@@ -1631,9 +1631,9 @@
   ##   Johns Hopkins University Press, Baltimore, Maryland, 1989, p. 369.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for krylov matrix.");
+    error ("gallery: 1 to 3 arguments are required for krylov matrix");
   elseif (! isnumeric (A) || ! issquare (A) || ndims (A) != 2)
-    error ("gallery: A must be a square 2-D matrix for krylov matrix.");
+    error ("gallery: A must be a square 2-D matrix for krylov matrix");
   endif
 
   n = length (A);
@@ -1645,13 +1645,13 @@
   if (nargin < 2)
     x = ones (n, 1);
   elseif (! isvector (x) || numel (x) != n)
-    error ("gallery: X must be a vector of length equal to A for krylov matrix.");
+    error ("gallery: X must be a vector of length equal to A for krylov matrix");
   endif
 
   if (nargin < 3)
     j = n;
   elseif (! isnumeric (j) || ! isscalar (j) || fix (j) != j)
-    error ("gallery: J must be an integer for krylov matrix.");
+    error ("gallery: J must be an integer for krylov matrix");
   endif
 
   B = ones (n, j);
@@ -1673,11 +1673,11 @@
   ##   kleinsten Quadraten, Numer. Math, 3 (1961), pp. 226-240.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for lauchli matrix.");
+    error ("gallery: 1 to 2 arguments are required for lauchli matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lauchli matrix.");
+    error ("gallery: N must be an integer for lauchli matrix");
   elseif (! isscalar (mu))
-    error ("gallery: MU must be a scalar for lauchli matrix.");
+    error ("gallery: MU must be a scalar for lauchli matrix");
   endif
 
   A = [ones(1, n)
@@ -1700,10 +1700,10 @@
   ##   J. Todd, Basic Numerical Mathematics, Vol. 2: Numerical Algebra,
   ##      Birkhauser, Basel, and Academic Press, New York, 1977, p. 154.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for lehmer matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for lehmer matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lehmer matrix.");
+    error ("gallery: N must be an integer for lehmer matrix");
   endif
 
   A = ones (n, 1) * (1:n);
@@ -1731,10 +1731,10 @@
   ##        Mathematics, volume 260, Longman Scientific and Technical, Essex,
   ##        UK, 1992, pp. 234-266.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for lesp matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for lesp matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lesp matrix.");
+    error ("gallery: N must be an integer for lesp matrix");
   endif
 
   x = 2:n;
@@ -1751,10 +1751,10 @@
   ##   Reference:
   ##   M. Lotkin, A set of test matrices, MTAC, 9 (1955), pp. 153-161.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for lotkin matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for lotkin matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for lotkin matrix.");
+    error ("gallery: N must be an integer for lotkin matrix");
   endif
 
   A = hilb (n);
@@ -1779,10 +1779,10 @@
   ##      chemistry---II, Proc. Royal Soc. Edin., 63, A (1952), pp. 232-241.
   ##      (For the eigenvalues of Givens' matrix.)
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for minij matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for minij matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for minij matrix.");
+    error ("gallery: N must be an integer for minij matrix");
   endif
 
   A = bsxfun (@min, 1:n, (1:n)');
@@ -1803,11 +1803,11 @@
   ##   Bristol, 1990 (Appendix 1).
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for moler matrix.");
+    error ("gallery: 1 to 2 arguments are required for moler matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for moler matrix.");
+    error ("gallery: N must be an integer for moler matrix");
   elseif (! isscalar (alpha))
-    error ("gallery: ALPHA must be a scalar for moler matrix.");
+    error ("gallery: ALPHA must be a scalar for moler matrix");
   endif
 
   A = triw (n, alpha)' * triw (n, alpha);
@@ -1826,16 +1826,16 @@
   ##   R.J. Plemmons, Regular splittings and the discrete Neumann
   ##   problem, Numer. Math., 25 (1976), pp. 153-161.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for neumann matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for neumann matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be a 1 or 2 element integer for neumann matrix.");
+    error ("gallery: N must be a 1 or 2 element integer for neumann matrix");
   endif
 
   if (isscalar (n))
     m = sqrt (n);
     if (m^2 != n)
-      error ("gallery: N must be a perfect square for neumann matrix.");
+      error ("gallery: N must be a perfect square for neumann matrix");
     endif
     n(1) = m;
     n(2) = m;
@@ -1851,7 +1851,7 @@
 function A = normaldata (varargin)
 
   if (nargin < 2)
-    error ("gallery: At least 2 arguments required for normaldata matrix.");
+    error ("gallery: At least 2 arguments required for normaldata matrix");
   endif
   if (isnumeric (varargin{end}))
     jidx = varargin{end};
@@ -1924,11 +1924,11 @@
   ##        pp. 500-507.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for orthog matrix.");
+    error ("gallery: 1 to 2 arguments are required for orthog matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for orthog matrix.");
+    error ("gallery: N must be an integer for orthog matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for orthog matrix.");
+    error ("gallery: K must be a numeric scalar for orthog matrix");
   endif
 
   switch (k)
@@ -1971,7 +1971,7 @@
       Q = cos (m);
 
     otherwise
-      error ("gallery: unknown K '%d' for orthog matrix.", k);
+      error ("gallery: unknown K '%d' for orthog matrix", k);
   endswitch
 endfunction
 
@@ -1992,10 +1992,10 @@
   ##   E.E. Tyrtyshnikov, Cauchy-Toeplitz matrices and some applications,
   ##        Linear Algebra and Appl., 149 (1991), pp. 1-18.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for parter matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for parter matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for parter matrix.");
+    error ("gallery: N must be an integer for parter matrix");
   endif
 
   A = cauchy ((1:n) + 0.5, -(1:n));
@@ -2013,11 +2013,11 @@
   ##   Comm. ACM, 5 (1962), p. 508.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for pei matrix.");
+    error ("gallery: 1 to 2 arguments are required for pei matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for pei matrix.");
+    error ("gallery: N must be an integer for pei matrix");
   elseif (! isnumeric (alpha) || ! isscalar (alpha))
-    error ("gallery: ALPHA must be a scalar for pei matrix.");
+    error ("gallery: ALPHA must be a scalar for pei matrix");
   endif
 
   P = alpha * eye (n) + ones (n);
@@ -2034,10 +2034,10 @@
   ##   Johns Hopkins University Press, Baltimore, Maryland, 1989
   ##   (Section 4.5.4).
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for poisson matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for poisson matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for poisson matrix.");
+    error ("gallery: N must be an integer for poisson matrix");
   endif
 
   S = tridiag (n, -1, 2, -1);
@@ -2060,11 +2060,11 @@
   ##   187:269--278, 1993.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for prolate matrix.");
+    error ("gallery: 1 to 2 arguments are required for prolate matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for prolate matrix.");
+    error ("gallery: N must be an integer for prolate matrix");
   elseif (! isnumeric (w) || ! isscalar (w))
-    error ("gallery: W must be a scalar for prolate matrix.");
+    error ("gallery: W must be a scalar for prolate matrix");
   endif
 
   a      = zeros (n, 1);
@@ -2095,10 +2095,10 @@
   ##   W.B. Gragg, The QR algorithm for unitary Hessenberg matrices,
   ##   J. Comp. Appl. Math., 16 (1986), pp. 1-8.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for randhess matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for randhess matrix");
   elseif (! isnumeric (x) || ! isreal (x))
-    error ("gallery: N or X must be numeric real values for randhess matrix.");
+    error ("gallery: N or X must be numeric real values for randhess matrix");
   endif
 
   if (isscalar (x))
@@ -2111,7 +2111,7 @@
     H = eye (n);
     H(n,n) = sign (x(n)) + (x(n) == 0); # Second term ensures H(n,n) nonzero.
   else
-    error ("gallery: N or X must be a scalar or a vector for randhess matrix.");
+    error ("gallery: N or X must be a scalar or a vector for randhess matrix");
   endif
 
   for i = n:-1:2
@@ -2134,11 +2134,11 @@
   ##   N may be a 2-vector, in which case the matrix is N(1)-by-N(2).
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for rando matrix.");
+    error ("gallery: 1 to 2 arguments are required for rando matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be an integer for rando matrix.");
+    error ("gallery: N must be an integer for rando matrix");
   elseif (! isnumeric (k) || ! isscalar (k))
-    error ("gallery: K must be a numeric scalar for smoke matrix.");
+    error ("gallery: K must be a numeric scalar for smoke matrix");
   endif
 
   ## Parameter n specifies dimension: m-by-n.
@@ -2150,7 +2150,7 @@
     case (2), A = 2*floor (  rand(m, n) + 0.5) -1;  # {-1, 1}
     case (3), A =   round (3*rand(m, n) - 1.5);     # {-1, 0, 1}
     otherwise
-      error ("gallery: unknown K '%d' for smoke matrix.", k);
+      error ("gallery: unknown K '%d' for smoke matrix", k);
   endswitch
 
 endfunction
@@ -2191,19 +2191,19 @@
   ##   New York, 1989.
 
   if (nargin < 1 || nargin > 5)
-    error ("gallery: 1 to 5 arguments are required for randsvd matrix.");
+    error ("gallery: 1 to 5 arguments are required for randsvd matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]) || fix (n) != n)
-    error ("gallery: N must be a 1 or 2 element integer vector for randsvd matrix.");
+    error ("gallery: N must be a 1 or 2 element integer vector for randsvd matrix");
   elseif (! isnumeric (kappa) || ! isscalar (kappa))
-    error ("gallery: KAPPA must be a numeric scalar for randsvd matrix.");
+    error ("gallery: KAPPA must be a numeric scalar for randsvd matrix");
   elseif (abs (kappa) < 1)
-    error ("gallery: KAPPA must larger than or equal to 1 for randsvd matrix.");
+    error ("gallery: KAPPA must larger than or equal to 1 for randsvd matrix");
   elseif (! isnumeric (mode) || ! isscalar (mode))
-    error ("gallery: MODE must be a numeric scalar for randsvd matrix.");
+    error ("gallery: MODE must be a numeric scalar for randsvd matrix");
   elseif (! isnumeric (kl) || ! isscalar (kl))
-    error ("gallery: KL must be a numeric scalar for randsvd matrix.");
+    error ("gallery: KL must be a numeric scalar for randsvd matrix");
   elseif (! isnumeric (ku) || ! isscalar (ku))
-    error ("gallery: KU must be a numeric scalar for randsvd matrix.");
+    error ("gallery: KU must be a numeric scalar for randsvd matrix");
   endif
 
   posdef = 0;
@@ -2242,7 +2242,7 @@
       rand ("uniform");
       sigma = exp (-rand (p, 1) * log (kappa));
     otherwise
-      error ("gallery: unknown MODE '%d' for randsvd matrix.", mode);
+      error ("gallery: unknown MODE '%d' for randsvd matrix", mode);
   endswitch
 
   ##  Convert to diagonal matrix of singular values.
@@ -2305,10 +2305,10 @@
   ##   Spectral Properties of a Matrix of Redheffer,
   ##   Linear Algebra and Appl., 162 (1992), pp. 673-683.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for redheff matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for redheff matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for redheff matrix.");
+    error ("gallery: N must be an integer for redheff matrix");
   endif
 
   i = (1:n)' * ones (1, n);
@@ -2335,10 +2335,10 @@
   ##   F. Roesler, Riemann's hypothesis as an eigenvalue problem,
   ##   Linear Algebra and Appl., 81 (1986), pp. 153-198.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for riemann matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for riemann matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for riemann matrix.");
+    error ("gallery: N must be an integer for riemann matrix");
   endif
 
   n += 1;
@@ -2361,10 +2361,10 @@
   ##   Algebra and Function Minimisation, second edition, Adam Hilger,
   ##   Bristol, 1990 (Appendix 1).
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for ris matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for ris matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for ris matrix.");
+    error ("gallery: N must be an integer for ris matrix");
   endif
 
   p = -2*(1:n) + (n+1.5);
@@ -2389,11 +2389,11 @@
   ##   Toeplitz matrices, Linear Algebra and Appl., 162-164:153-185, 1992.
 
   if (nargin < 1 || nargin > 2)
-    error ("gallery: 1 to 2 arguments are required for smoke matrix.");
+    error ("gallery: 1 to 2 arguments are required for smoke matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be an integer for smoke matrix.");
+    error ("gallery: N must be an integer for smoke matrix");
   elseif (! isnumeric (n) || ! isscalar (n))
-    error ("gallery: K must be a numeric scalar for smoke matrix.");
+    error ("gallery: K must be a numeric scalar for smoke matrix");
   endif
 
   w = exp (2*pi*i/n);
@@ -2403,7 +2403,7 @@
     case (0), A(n,1) = 1;
     case (1), # do nothing
     otherwise,
-      error ("gallery: K must have a value of 0 or 1 for smoke matrix.");
+      error ("gallery: K must have a value of 0 or 1 for smoke matrix");
   endswitch
 endfunction
 
@@ -2424,13 +2424,13 @@
   ##   Comput., 7 (1986), pp. 123-131.
 
   if (nargin < 1 || nargin > 4)
-    error ("gallery: 1 to 4 arguments are required for toeppd matrix.");
+    error ("gallery: 1 to 4 arguments are required for toeppd matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be a numeric integer for toeppd matrix.");
+    error ("gallery: N must be a numeric integer for toeppd matrix");
   elseif (! isnumeric (m) || ! isscalar (m) || fix (m) != m)
-    error ("gallery: M must be a numeric integer for toeppd matrix.");
+    error ("gallery: M must be a numeric integer for toeppd matrix");
   elseif (numel (w) != m || numel (theta) != m)
-    error ("gallery: W and THETA must be vectors of length M for toeppd matrix.");
+    error ("gallery: W and THETA must be vectors of length M for toeppd matrix");
   endif
 
   T = zeros (n);
@@ -2465,11 +2465,11 @@
   ##      1966, pp. 349-365.
 
   if (nargin < 1 || nargin > 6)
-    error ("gallery: 1 to 6 arguments are required for toeppen matrix.");
+    error ("gallery: 1 to 6 arguments are required for toeppen matrix");
   elseif (! isnumeric (n) || ! isscalar (n) || fix (n) != n)
-    error ("gallery: N must be a numeric integer for toeppen matrix.");
+    error ("gallery: N must be a numeric integer for toeppen matrix");
   elseif (any (! cellfun ("isnumeric", {a b c d e})) || any (cellfun ("numel", {a b c d e}) != 1))
-    error ("gallery: A, B, C, D and E must be numeric scalars for toeppen matrix.");
+    error ("gallery: A, B, C, D and E must be numeric scalars for toeppen matrix");
   endif
 
   P = spdiags ([a*ones(n,1) b*ones(n,1) c*ones(n,1) d*ones(n,1) e*ones(n,1)],
@@ -2497,7 +2497,7 @@
   ##     chemistry---II, Proc. Royal Soc. Edin., 63, A (1952), pp. 232-241.
 
   if (nargin != 1 && nargin != 3 && nargin != 4)
-    error ("gallery: 1, 3, or 4 arguments are required for tridiag matrix.");
+    error ("gallery: 1, 3, or 4 arguments are required for tridiag matrix");
   elseif (nargin == 3)
     z = y;
     y = x;
@@ -2514,9 +2514,9 @@
     z *= ones (n-1, 1);
     y *= ones (n,   1);
   elseif (numel (y) != numel (x) + 1)
-    error ("gallery: X must have one element less than Y for tridiag matrix.");
+    error ("gallery: X must have one element less than Y for tridiag matrix");
   elseif (numel (y) != numel (z) + 1)
-    error ("gallery: Z must have one element less than Y for tridiag matrix.");
+    error ("gallery: Z must have one element less than Y for tridiag matrix");
   endif
 
   ##  T = diag (x, -1) + diag (y) + diag (z, 1);  # For non-sparse matrix.
@@ -2555,13 +2555,13 @@
   ##      Academic Press, London, 1978, pp. 109-135.
 
   if (nargin < 1 || nargin > 3)
-    error ("gallery: 1 to 3 arguments are required for triw matrix.");
+    error ("gallery: 1 to 3 arguments are required for triw matrix");
   elseif (! isnumeric (n) || all (numel (n) != [1 2]))
-    error ("gallery: N must be a 1 or 2 elements vector for triw matrix.");
+    error ("gallery: N must be a 1 or 2 elements vector for triw matrix");
   elseif (! isscalar (alpha))
-    error ("gallery: ALPHA must be a scalar for triw matrix.");
+    error ("gallery: ALPHA must be a scalar for triw matrix");
   elseif (! isscalar (k) || ! isnumeric (k) || fix (k) != k || k < 0)
-    error ("gallery: K must be a numeric integer >= 0 for triw matrix.");
+    error ("gallery: K must be a numeric integer >= 0 for triw matrix");
   endif
 
   m = n(1);              # Parameter n specifies dimension: m-by-n.
@@ -2573,7 +2573,7 @@
 function A = uniformdata (varargin)
 
   if (nargin < 2)
-    error ("gallery: At least 2 arguments required for uniformdata matrix.");
+    error ("gallery: At least 2 arguments required for uniformdata matrix");
   endif
   if (isnumeric (varargin{end}))
     jidx = varargin{end};
@@ -2687,13 +2687,13 @@
   ##   format.
 
   if (nargin < 2 || nargin > 3)
-    error ("gallery: 2 or 3 arguments are required for wathen matrix.");
+    error ("gallery: 2 or 3 arguments are required for wathen matrix");
   elseif (! isnumeric (nx) || ! isscalar (nx) || nx < 1)
-    error ("gallery: NX must be a positive scalar for wathen matrix.");
+    error ("gallery: NX must be a positive scalar for wathen matrix");
   elseif (! isnumeric (ny) || ! isscalar (ny) || ny < 1)
-    error ("gallery: NY must be a positive scalar for wathen matrix.");
+    error ("gallery: NY must be a positive scalar for wathen matrix");
   elseif (! isscalar (k))
-    error ("gallery: K must be a scalar for wathen matrix.");
+    error ("gallery: K must be a scalar for wathen matrix");
   endif
 
   e1 = [ 6  -6   2  -8
@@ -2762,10 +2762,10 @@
   ##   J.H. Wilkinson, The Algebraic Eigenvalue Problem, Oxford University
   ##      Press, 1965.
 
-  if (nargin != 1)
-    error ("gallery: 1 argument is required for wilk matrix.");
+  if (nargin < 1)
+    error ("gallery: 1 argument is required for wilk matrix");
   elseif (! isnumeric (n) || ! isscalar (n))
-    error ("gallery: N must be a numeric scalar for wilk matrix.");
+    error ("gallery: N must be a numeric scalar for wilk matrix");
   endif
 
   if (n == 3)
@@ -2802,7 +2802,7 @@
     A = diag (abs (-m:m)) + E + E';
 
   else
-    error ("gallery: unknown N '%d' for wilk matrix.", n);
+    error ("gallery: unknown N '%d' for wilk matrix", n);
   endif
 endfunction
 
@@ -2912,7 +2912,7 @@
 %!assert (gallery ("invhess", 2), [1 -1; 1 2])
 
 ## Test input validation of main dispatch function only
-%!error gallery ()
+%!error <Invalid call> gallery ()
 %!error <NAME must be a string> gallery (123)
 %!error <matrix binomial not implemented> gallery ("binomial")
 %!error <unknown matrix with NAME foobar> gallery ("foobar")
@@ -2930,9 +2930,9 @@
 %!   4  5  6  7  8
 %!   5  6  7  8  9
 %!   6  7  8  9  10];
-%! assert (gallery ("cauchy", 5), exp)
-%! assert (gallery ("cauchy", 1:5), exp)
-%! assert (gallery ("cauchy", 1:5, 1:5), exp)
+%! assert (gallery ("cauchy", 5), exp);
+%! assert (gallery ("cauchy", 1:5), exp);
+%! assert (gallery ("cauchy", 1:5, 1:5), exp);
 %!
 %! exp = 1 ./ [
 %!   1  2  3  4  5
@@ -2940,9 +2940,9 @@
 %!   3  4  5  6  7
 %!   4  5  6  7  8
 %!   5  6  7  8  9];
-%! assert (gallery ("cauchy", 0:4, 1:5), exp)
-%! assert (gallery ("cauchy", 1:5, 0:4), exp)
-%! assert (gallery ("cauchy", 1:5, 4:-1:0), fliplr (exp))
+%! assert (gallery ("cauchy", 0:4, 1:5), exp);
+%! assert (gallery ("cauchy", 1:5, 0:4), exp);
+%! assert (gallery ("cauchy", 1:5, 4:-1:0), fliplr (exp));
 %!
 %! exp = 1 ./ [
 %!  -1  0  1  2  3
@@ -2950,16 +2950,16 @@
 %!   1  2  3  4  5
 %!   2  3  4  5  6
 %!   3  4  5  6  7];
-%! assert (gallery ("cauchy", 1:5, -2:2), exp)
+%! assert (gallery ("cauchy", 1:5, -2:2), exp);
 %!
 %! exp = 1 ./ [
 %!    8  18  -4  2
 %!   13  23   1  7
 %!    9  19  -3  3
 %!   15  25   3  9];
-%! assert (gallery ("cauchy", [-2 3 -1 5], [10 20 -2 4]), exp)
-%! assert (gallery ("cauchy", [-2 3 -1 5], [10 20 -2 4]'), exp)
-%! assert (gallery ("cauchy", [-2 3 -1 5]', [10 20 -2 4]), exp)
+%! assert (gallery ("cauchy", [-2 3 -1 5], [10 20 -2 4]), exp);
+%! assert (gallery ("cauchy", [-2 3 -1 5], [10 20 -2 4]'), exp);
+%! assert (gallery ("cauchy", [-2 3 -1 5]', [10 20 -2 4]), exp);
 
 %!assert (size (gallery ("chebspec", 5)), [5 5])
 %!assert (size (gallery ("chebspec", 5, 1)), [5 5])
@@ -3006,10 +3006,10 @@
 %!   2   1   0   1   2
 %!   3   2   1   0   1
 %!   4   3   2   1   0];
-%! assert (gallery ("fiedler", 5), exp)
-%! assert (gallery ("fiedler", 1:5), exp)
-%! assert (gallery ("fiedler", -2:2), exp)
-%! assert (gallery ("fiedler", 2:5), exp(1:4,1:4))
+%! assert (gallery ("fiedler", 5), exp);
+%! assert (gallery ("fiedler", 1:5), exp);
+%! assert (gallery ("fiedler", -2:2), exp);
+%! assert (gallery ("fiedler", 2:5), exp(1:4,1:4));
 
 %!assert (size (gallery ("forsythe", 5)), [5 5])
 %!assert (size (gallery ("forsythe", 5, 1, 0.5)), [5 5])
--- a/scripts/special-matrix/hadamard.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/hadamard.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 
 function h = hadamard (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -176,6 +176,6 @@
 %!   assert (norm (h*h' - n*eye (n)), 0);
 %! endfor
 
-%!error hadamard ()
+%!error <Invalid call> hadamard ()
 %!error hadamard (1,2)
 %!error <N must be 2\^k\*p> hadamard (5)
--- a/scripts/special-matrix/hankel.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/hankel.m	Sun May 16 09:44:35 2021 +0200
@@ -56,7 +56,7 @@
 
 function retval = hankel (c, r)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -99,7 +99,6 @@
 %!warning <column wins anti-diagonal conflict>
 %!  assert (hankel (1:3,4:6), [1,2,3;2,3,5;3,5,6]);
 
-%!error hankel ()
-%!error hankel (1, 2, 3)
+%!error <Invalid call> hankel ()
 %!error <C must be a vector> hankel ([1, 2; 3, 4])
 %!error <C and R must be vectors> hankel (1:4, [1, 2; 3, 4])
--- a/scripts/special-matrix/hilb.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/hilb.m	Sun May 16 09:44:35 2021 +0200
@@ -60,7 +60,7 @@
 
 function retval = hilb (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! isscalar (n))
     error ("hilb: N must be a scalar integer");
@@ -77,6 +77,5 @@
 %!assert (hilb (2), [1, 1/2; 1/2, 1/3])
 %!assert (hilb (3), [1, 1/2, 1/3; 1/2, 1/3, 1/4; 1/3, 1/4, 1/5])
 
-%!error hilb ()
-%!error hilb (1, 2)
+%!error <Invalid call> hilb ()
 %!error <N must be a scalar integer> hilb (ones (2))
--- a/scripts/special-matrix/invhilb.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/invhilb.m	Sun May 16 09:44:35 2021 +0200
@@ -81,7 +81,7 @@
 
 function retval = invhilb (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! isscalar (n))
     error ("invhilb: N must be a scalar integer");
@@ -128,6 +128,5 @@
 %! assert (invhilb (4), result4);
 %!assert (invhilb (7) * hilb (7), eye (7), sqrt (eps))
 
-%!error invhilb ()
-%!error invhilb (1, 2)
+%!error <Invalid call> invhilb ()
 %!error <N must be a scalar integer> invhilb ([1, 2])
--- a/scripts/special-matrix/magic.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/magic.m	Sun May 16 09:44:35 2021 +0200
@@ -38,7 +38,7 @@
 
 function A = magic (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -105,6 +105,5 @@
 %!assert (magic (1.5), 1)
 
 ## Test input validation
-%!error magic ()
-%!error magic (1, 2)
+%!error <Invalid call> magic ()
 %!error <N must be non-negative> magic (-5)
--- a/scripts/special-matrix/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/gallery.m \
   %reldir%/hadamard.m \
   %reldir%/hankel.m \
--- a/scripts/special-matrix/pascal.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/pascal.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 
 function retval = pascal (n, t = 0)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isscalar (n) && isscalar (t)))
     error ("pascal: N and T must be scalars");
@@ -90,8 +90,7 @@
 %!assert (pascal (0,2), [])
 
 ## Test input validation
-%!error pascal ()
-%!error pascal (1,2,3)
+%!error <Invalid call> pascal ()
 %!error <N and T must be scalars> pascal ([1 2])
 %!error <N and T must be scalars> pascal (1, [1 2])
 %!error <T must be -1> pascal (3,-2)
--- a/scripts/special-matrix/rosser.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/rosser.m	Sun May 16 09:44:35 2021 +0200
@@ -33,10 +33,6 @@
 
 function retval = rosser ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   retval = [611,   196,  -192,   407,    -8,   -52,   -49,    29;
             196,   899,   113,  -192,   -71,   -43,    -8,   -44;
            -192,   113,   899,   196,    61,    49,     8,    52;
@@ -52,4 +48,4 @@
 %!assert (size (rosser ()), [8,8])
 %!assert (rosser ()([1, end]), [611, 99])
 
-%!error (rosser (1))
+%!error rosser (1)
--- a/scripts/special-matrix/toeplitz.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/toeplitz.m	Sun May 16 09:44:35 2021 +0200
@@ -65,7 +65,7 @@
 
 function retval = toeplitz (c, r)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -133,8 +133,7 @@
 %!assert (toeplitz ([1, 2, 3], [1; -3i; -5i]), [1, -3i, -5i; 2, 1, -3i; 3, 2, 1])
 
 ## Test input validation
-%!error toeplitz ()
-%!error toeplitz (1, 2, 3)
+%!error <Invalid call> toeplitz ()
 %!error <C must be a vector> toeplitz ([1, 2; 3, 4])
 %!error <C and R must be vectors> toeplitz ([1, 2; 3, 4], 1)
 %!error <C and R must be vectors> toeplitz (1, [1, 2; 3, 4])
--- a/scripts/special-matrix/vander.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/vander.m	Sun May 16 09:44:35 2021 +0200
@@ -95,6 +95,5 @@
 %!assert (vander (2, 3), [4, 2, 1])
 %!assert (vander ([2, 3], 3), [4, 2, 1; 9, 3, 1])
 
-%!error vander ()
-%!error vander (1, 2, 3)
+%!error <Invalid call> vander ()
 %!error <polynomial C must be a vector> vander ([1, 2; 3, 4])
--- a/scripts/special-matrix/wilkinson.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/special-matrix/wilkinson.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function retval = wilkinson (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,8 +58,7 @@
 %!assert (wilkinson (4), [1.5,1,0,0;1,0.5,1,0;0,1,0.5,1;0,0,1,1.5])
 
 ## Test input validation
-%!error wilkinson ()
-%!error wilkinson (1,2)
+%!error <Invalid call> wilkinson ()
 %!error <N must be a non-negative integer> wilkinson (ones (2))
 %!error <N must be a non-negative integer> wilkinson (-1)
 %!error <N must be a non-negative integer> wilkinson (1.5)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/statistics/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/statistics/bounds.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/bounds.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
 
 function [s, l] = bounds (x, dim, nanflag = false)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -119,8 +119,7 @@
 %! assert (l, x(:,:,3));
 
 ## Test input validation
-%!error bounds ()
-%!error bounds (1, 2, 3, 4)
+%!error <Invalid call> bounds ()
 %!error <X must be a numeric> bounds (['A'; 'B'])
 %!error <DIM must be an integer> bounds (1, ones (2,2))
 %!error <DIM must be an integer> bounds (1, 1.5)
--- a/scripts/statistics/center.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/center.m	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
 
 function retval = center (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -92,8 +92,7 @@
 %!assert (center (1, 3), 0)
 
 ## Test input validation
-%!error center ()
-%!error center (1, 2, 3)
+%!error <Invalid call> center ()
 %!error <DIM must be an integer> center (1, ones (2,2))
 %!error <DIM must be an integer> center (1, 1.5)
 %!error <DIM must be .* a valid dimension> center (1, 0)
--- a/scripts/statistics/corr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/corr.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 
 function retval = corr (x, y = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -107,8 +107,7 @@
 %!assert (corr (single (5)), single (1))
 
 ## Test input validation
-%!error corr ()
-%!error corr (1, 2, 3)
+%!error <Invalid call> corr ()
 %!error corr ([1; 2], ["A", "B"])
 %!error corr (ones (2,2,2))
 %!error corr (ones (2,2), ones (2,2,2))
--- a/scripts/statistics/corrcoef.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/corrcoef.m	Sun May 16 09:44:35 2021 +0200
@@ -284,7 +284,7 @@
 %! r = corrcoef (x, y);
 %! assert (r, [1, NaN; NaN, 1]);
 
-%!error corrcoef ()
+%!error <Invalid call> corrcoef ()
 %!error <parameter 1 must be a string> corrcoef (1, 2, 3)
 %!error <parameter "alpha" missing value> corrcoef (1, 2, "alpha")
 %!error <"alpha" must be a scalar> corrcoef (1,2, "alpha", "1")
--- a/scripts/statistics/cov.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/cov.m	Sun May 16 09:44:35 2021 +0200
@@ -79,7 +79,7 @@
 
 function c = cov (x, y = [], opt = 0)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -171,10 +171,9 @@
 %! assert (c, 2);
 
 ## Test input validation
-%!error cov ()
-%!error cov (1, 2, 3, 4)
+%!error <Invalid call> cov ()
 %!error cov ([1; 2], ["A", "B"])
 %!error cov (ones (2,2,2))
 %!error cov (ones (2,2), ones (2,2,2))
-%!error cov (1, 3)
+%!error <normalization OPT must be 0 or 1> cov (1, 3)
 %!error cov (ones (2,2), ones (3,2))
--- a/scripts/statistics/discrete_cdf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/discrete_cdf.m	Sun May 16 09:44:35 2021 +0200
@@ -64,7 +64,7 @@
 %!shared x,v,p,y
 %! x = [-1 0.1 1.1 1.9 3];
 %! v = 0.1:0.2:1.9;
-%! p = 1/length(v) * ones (1, length(v));
+%! p = 1/length (v) * ones (1, length (v));
 %! y = [0 0.1 0.6 1 1];
 %!assert (discrete_cdf ([x, NaN], v, p), [y, NaN], eps)
 
@@ -74,10 +74,9 @@
 %!assert (discrete_cdf ([x, NaN], v, single (p)), single ([y, NaN]), 2*eps ("single"))
 
 ## Test input validation
-%!error discrete_cdf ()
-%!error discrete_cdf (1)
-%!error discrete_cdf (1,2)
-%!error discrete_cdf (1,2,3,4)
+%!error <Invalid call> discrete_cdf ()
+%!error <Invalid call> discrete_cdf (1)
+%!error <Invalid call> discrete_cdf (1,2)
 %!error discrete_cdf (1, ones (2), ones (2,1))
 %!error discrete_cdf (1, [1 ; NaN], ones (2,1))
 %!error discrete_cdf (1, ones (2,1), ones (1,1))
--- a/scripts/statistics/discrete_inv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/discrete_inv.m	Sun May 16 09:44:35 2021 +0200
@@ -76,7 +76,7 @@
 %!shared x,v,p,y
 %! x = [-1 0 0.1 0.5 1 2];
 %! v = 0.1:0.2:1.9;
-%! p = 1/length(v) * ones (1, length(v));
+%! p = 1/length (v) * ones (1, length (v));
 %! y = [NaN v(1) v(1) v(end/2) v(end) NaN];
 %!assert (discrete_inv ([x, NaN], v, p), [y, NaN], eps)
 
@@ -86,10 +86,9 @@
 %!assert (discrete_inv ([x, NaN], v, single (p)), single ([y, NaN]), eps ("single"))
 
 ## Test input validation
-%!error discrete_inv ()
-%!error discrete_inv (1)
-%!error discrete_inv (1,2)
-%!error discrete_inv (1,2,3,4)
+%!error <Invalid call> discrete_inv ()
+%!error <Invalid call> discrete_inv (1)
+%!error <Invalid call> discrete_inv (1,2)
 %!error discrete_inv (1, ones (2), ones (2,1))
 %!error discrete_inv (1, ones (2,1), ones (1,1))
 %!error discrete_inv (1, ones (2,1), [1 NaN])
--- a/scripts/statistics/discrete_pdf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/discrete_pdf.m	Sun May 16 09:44:35 2021 +0200
@@ -75,10 +75,9 @@
 %!assert (discrete_pdf ([x, NaN], v, single (p)), single ([y, NaN]), 5*eps ("single"))
 
 ## Test input validation
-%!error discrete_pdf ()
-%!error discrete_pdf (1)
-%!error discrete_pdf (1,2)
-%!error discrete_pdf (1,2,3,4)
+%!error <Invalid call> discrete_pdf ()
+%!error <Invalid call> discrete_pdf (1)
+%!error <Invalid call> discrete_pdf (1,2)
 %!error discrete_pdf (1, ones (2), ones (2,1))
 %!error discrete_pdf (1, [1 ; NaN], ones (2,1))
 %!error discrete_pdf (1, ones (2,1), ones (1,1))
--- a/scripts/statistics/discrete_rnd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/discrete_rnd.m	Sun May 16 09:44:35 2021 +0200
@@ -88,11 +88,11 @@
 %!assert (class (discrete_rnd (1:2, 1:2)), "double")
 %!assert (class (discrete_rnd (single (1:2), 1:2)), "single")
 ## FIXME: Maybe this should work, maybe it shouldn't.
-#%!assert(class (discrete_rnd (1:2, single(1:2))), "single")
+#%!assert (class (discrete_rnd (1:2, single(1:2))), "single")
 
 ## Test input validation
-%!error discrete_rnd ()
-%!error discrete_rnd (1)
+%!error <Invalid call> discrete_rnd ()
+%!error <Invalid call> discrete_rnd (1)
 %!error discrete_rnd (1:2,1:2, -1)
 %!error discrete_rnd (1:2,1:2, ones (2))
 %!error discrete_rnd (1:2,1:2, [2 -1 2])
--- a/scripts/statistics/empirical_cdf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/empirical_cdf.m	Sun May 16 09:44:35 2021 +0200
@@ -58,7 +58,6 @@
 %!assert (empirical_cdf ([x, NaN], single (v)), single ([y, NaN]), eps)
 
 ## Test input validation
-%!error empirical_cdf ()
-%!error empirical_cdf (1)
-%!error empirical_cdf (1,2,3)
+%!error <Invalid call> empirical_cdf ()
+%!error <Invalid call> empirical_cdf (1)
 %!error empirical_cdf (1, ones (2))
--- a/scripts/statistics/empirical_inv.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/empirical_inv.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,6 @@
 %!assert (empirical_inv ([x, NaN], single (v)), single ([y, NaN]), eps)
 
 ## Test input validation
-%!error empirical_inv ()
-%!error empirical_inv (1)
-%!error empirical_inv (1,2,3)
+%!error <Invalid call> empirical_inv ()
+%!error <Invalid call> empirical_inv (1)
 %!error empirical_inv (1, ones (2))
--- a/scripts/statistics/empirical_pdf.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/empirical_pdf.m	Sun May 16 09:44:35 2021 +0200
@@ -68,7 +68,6 @@
 %!assert (empirical_pdf (2, [1 2 3 2]), 0.5)
 
 ## Test input validation
-%!error empirical_pdf ()
-%!error empirical_pdf (1)
-%!error empirical_pdf (1,2,3)
+%!error <Invalid call> empirical_pdf ()
+%!error <Invalid call> empirical_pdf (1)
 %!error empirical_inv (1, ones (2))
--- a/scripts/statistics/empirical_rnd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/empirical_rnd.m	Sun May 16 09:44:35 2021 +0200
@@ -65,6 +65,6 @@
 %!assert (class (empirical_rnd (single (1:2), 1)), "single")
 
 ## Test input validation
-%!error empirical_rnd ()
+%!error <Invalid call> empirical_rnd ()
 %!error empirical_rnd (ones (2), 1)
 %!error empirical_rnd (ones (2), 1, 1)
--- a/scripts/statistics/histc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/histc.m	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 
 function [n, idx] = histc (x, edges, dim)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -188,9 +188,9 @@
 %! n = histc (x, 0:10, 2);
 %! assert (n, repmat ([repmat(100, 1, 10), 1], [2, 1, 3]));
 
-%!error histc ()
-%!error histc (1)
-%!error histc (1, 2, 3, 4)
+## Test input validation
+%!error <Invalid call> histc ()
+%!error <Invalid call> histc (1)
 %!error histc ([1:10 1+i], 2)
 %!warning <empty EDGES specified> histc (1:10, []);
 %!error histc (1, 1, 3)
--- a/scripts/statistics/iqr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/iqr.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function y = iqr (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -97,8 +97,7 @@
 %! assert (iqr (x, 1), 50);
 %! assert (iqr (x', 2), 50);
 
-%!error iqr ()
-%!error iqr (1, 2, 3)
+%!error <Invalid call> iqr ()
 %!error iqr (1)
 %!error iqr (['A'; 'B'])
 %!error iqr (1:10, 3)
--- a/scripts/statistics/kendall.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/kendall.m	Sun May 16 09:44:35 2021 +0200
@@ -93,7 +93,7 @@
 
 function tau = kendall (x, y = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -148,8 +148,7 @@
 %!assert (kendall (single (1)), single (1))
 
 ## Test input validation
-%!error kendall ()
-%!error kendall (1, 2, 3)
+%!error <Invalid call> kendall ()
 %!error kendall (['A'; 'B'])
 %!error kendall (ones (2,1), ['A'; 'B'])
 %!error kendall (ones (2,2,2))
--- a/scripts/statistics/kurtosis.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/kurtosis.m	Sun May 16 09:44:35 2021 +0200
@@ -88,7 +88,7 @@
 
 function y = kurtosis (x, flag, dim)
 
-  if (nargin < 1) || (nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -162,8 +162,7 @@
 %! assert (lastwarn (), "");
 
 ## Test input validation
-%!error kurtosis ()
-%!error kurtosis (1, 2, 3)
+%!error <Invalid call> kurtosis ()
 %!error <X must be a numeric vector or matrix> kurtosis (['A'; 'B'])
 %!error <FLAG must be 0 or 1> kurtosis (1, 2)
 %!error <FLAG must be 0 or 1> kurtosis (1, [1 0])
--- a/scripts/statistics/mad.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/mad.m	Sun May 16 09:44:35 2021 +0200
@@ -58,7 +58,7 @@
 
 function retval = mad (x, opt = 0, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -105,8 +105,7 @@
 %!assert (mad (magic (4), 1, 2), [5.5; 1.5; 1.5; 5.5])
 
 ## Test input validation
-%!error mad ()
-%!error mad (1, 2, 3, 4)
+%!error <Invalid call> mad ()
 %!error <X must be a numeric> mad (['A'; 'B'])
 %!error <OPT must be 0 or 1> mad (1, 2)
 %!error <DIM must be an integer> mad (1, [], ones (2,2))
--- a/scripts/statistics/mean.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/mean.m	Sun May 16 09:44:35 2021 +0200
@@ -152,7 +152,7 @@
     case "a"
       y = sum (x, dim) / n;
     case "g"
-      if (all (x(:) >= 0))
+      if (! any (x(:) < 0))
         y = exp (sum (log (x), dim) ./ n);
       else
         error ("mean: X must not contain any negative values");
@@ -179,6 +179,7 @@
       ## this should have been filtered out during input check, but...
       error ("mean: OUTTYPE '%s' not recognized", out_type);
   endswitch
+
 endfunction
 
 
@@ -217,25 +218,25 @@
 %!test
 %! in = [1 2 3];
 %! out = 2;
-%! assert (mean (in, "default"), mean (in))
-%! assert (mean (in, "default"), out)
+%! assert (mean (in, "default"), mean (in));
+%! assert (mean (in, "default"), out);
 %!
 %! in = single ([1 2 3]);
 %! out = 2;
-%! assert (mean (in, "default"), mean (in))
-%! assert (mean (in, "default"), single (out))
-%! assert (mean (in, "double"), out)
-%! assert (mean (in, "native"), single (out))
+%! assert (mean (in, "default"), mean (in));
+%! assert (mean (in, "default"), single (out));
+%! assert (mean (in, "double"), out);
+%! assert (mean (in, "native"), single (out));
 %!
 %! in = uint8 ([1 2 3]);
 %! out = 2;
-%! assert (mean (in, "default"), mean (in))
-%! assert (mean (in, "default"), out)
-%! assert (mean (in, "double"), out)
-%! assert (mean (in, "native"), uint8 (out))
+%! assert (mean (in, "default"), mean (in));
+%! assert (mean (in, "default"), out);
+%! assert (mean (in, "double"), out);
+%! assert (mean (in, "native"), uint8 (out));
 %!
 %! in = logical ([1 0 1]);
 %! out = 2/3;
-%! assert (mean (in, "default"), mean (in))
-%! assert (mean (in, "default"), out)
-%! assert (mean (in, "native"), out) # logical ignores native option
+%! assert (mean (in, "default"), mean (in));
+%! assert (mean (in, "default"), out);
+%! assert (mean (in, "native"), out);  # logical ignores native option
--- a/scripts/statistics/meansq.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/meansq.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
 
 function y = meansq (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -88,8 +88,7 @@
 %!assert (meansq ([1 2], 3), [1 4])
 
 ## Test input validation
-%!error meansq ()
-%!error meansq (1, 2, 3)
+%!error <Invalid call> meansq ()
 %!error <X must be a numeric> meansq (['A'; 'B'])
 %!error <DIM must be an integer> meansq (1, ones (2,2))
 %!error <DIM must be an integer> meansq (1, 1.5)
--- a/scripts/statistics/median.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/median.m	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 
 function retval = median (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -138,8 +138,7 @@
 %!assert (median (single ([1, 3, NaN])), single (NaN))
 
 ## Test input validation
-%!error median ()
-%!error median (1, 2, 3)
+%!error <Invalid call> median ()
 %!error <X must be a numeric> median ({1:5})
 %!error <X cannot be an empty matrix> median ([])
 %!error <DIM must be an integer> median (1, ones (2,2))
--- a/scripts/statistics/mode.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/mode.m	Sun May 16 09:44:35 2021 +0200
@@ -45,7 +45,7 @@
 
 function [m, f, c] = mode (x, dim)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -182,8 +182,7 @@
 %! assert (c{3}, [1; 2; 3]);
 
 ## Test input validation
-%!error mode ()
-%!error mode (1, 2, 3)
+%!error <Invalid call> mode ()
 %!error <X must be a numeric> mode ({1 2 3})
 %!error <DIM must be an integer> mode (1, ones (2,2))
 %!error <DIM must be an integer> mode (1, 1.5)
--- a/scripts/statistics/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/bounds.m \
   %reldir%/center.m \
   %reldir%/corr.m \
--- a/scripts/statistics/moment.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/moment.m	Sun May 16 09:44:35 2021 +0200
@@ -130,7 +130,7 @@
 
 function m = moment (x, p, opt1, opt2)
 
-  if (nargin < 2 || nargin > 4)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -206,9 +206,8 @@
 %!assert (moment (1, 2, 4), 0)
 
 ## Test input validation
-%!error moment ()
-%!error moment (1)
-%!error moment (1, 2, 3, 4, 5)
+%!error <Invalid call> moment ()
+%!error <Invalid call> moment (1)
 %!error <X must be a non-empty numeric matrix> moment (['A'; 'B'], 2)
 %!error <X must be a non-empty numeric matrix> moment (ones (2,0,3), 2)
 %!error <P must be a numeric scalar> moment (1, true)
--- a/scripts/statistics/movmad.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movmad.m	Sun May 16 09:44:35 2021 +0200
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmax, movmean, movmedian, movmin, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -140,10 +140,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([0.5; repmat(2/3,8,1); 0.5], movmad ((1:10).', 3))
 
-
 ## Test input validation
-%!error movmad ()
-%!error movmad (1)
+%!error <Invalid call> movmad ()
+%!error <Invalid call> movmad (1)
--- a/scripts/statistics/movmax.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movmax.m	Sun May 16 09:44:35 2021 +0200
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmean, movmedian, movmin, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -141,9 +141,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([(2:10).'; 10], movmax ((1:10).', 3))
 
 ## Test input validation
-%!error movmax ()
-%!error movmax (1)
+%!error <Invalid call> movmax ()
+%!error <Invalid call> movmax (1)
--- a/scripts/statistics/movmean.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movmean.m	Sun May 16 09:44:35 2021 +0200
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmedian, movmin, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -140,9 +140,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([1.5; (2:9).'; 9.5], movmean ((1:10).', 3))
 
 ## Test input validation
-%!error movmean ()
-%!error movmean (1)
+%!error <Invalid call> movmean ()
+%!error <Invalid call> movmean (1)
--- a/scripts/statistics/movmedian.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movmedian.m	Sun May 16 09:44:35 2021 +0200
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmin, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -140,9 +140,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([1.5; (2:9).'; 9.5], movmedian ((1:10).', 3))
 
 ## Test input validation
-%!error movmedian ()
-%!error movmedian (1)
+%!error <Invalid call> movmedian ()
+%!error <Invalid call> movmedian (1)
--- a/scripts/statistics/movmin.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movmin.m	Sun May 16 09:44:35 2021 +0200
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movprod, movstd, movsum, movvar}
 ## @end deftypefn
@@ -141,9 +141,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([1; (1:9).'], movmin ((1:10).', 3))
 
 ## Test input validation
-%!error movmin ()
-%!error movmin (1)
+%!error <Invalid call> movmin ()
+%!error <Invalid call> movmin (1)
--- a/scripts/statistics/movprod.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movprod.m	Sun May 16 09:44:35 2021 +0200
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movstd, movsum, movvar}
 ## @end deftypefn
@@ -141,9 +141,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([2; 6; 24; 60; 120; 210; 336; 504; 720; 90], movprod ((1:10).', 3))
 
 ## Test input validation
-%!error movprod ()
-%!error movprod (1)
+%!error <Invalid call> movprod ()
+%!error <Invalid call> movprod (1)
--- a/scripts/statistics/movstd.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movstd.m	Sun May 16 09:44:35 2021 +0200
@@ -138,7 +138,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movsum, movvar}
 ## @end deftypefn
@@ -167,7 +167,7 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([1/sqrt(2); ones(8,1); 1/sqrt(2)], movstd ((1:10).', 3), 1e-8)
 
 %!test <*56765>
@@ -179,5 +179,5 @@
 %! assert (y1(1:3), sqrt ([1/4, 2/3, 5/4]));
 
 ## Test input validation
-%!error movstd ()
-%!error movstd (1)
+%!error <Invalid call> movstd ()
+%!error <Invalid call> movstd (1)
--- a/scripts/statistics/movsum.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movsum.m	Sun May 16 09:44:35 2021 +0200
@@ -123,7 +123,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movstd, movvar}
 ## @end deftypefn
@@ -141,9 +141,9 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([(3:3:27).'; 19], movsum ((1:10).', 3))
 
 ## Test input validation
-%!error movsum ()
-%!error movsum (1)
+%!error <Invalid call> movsum ()
+%!error <Invalid call> movsum (1)
--- a/scripts/statistics/movvar.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/movvar.m	Sun May 16 09:44:35 2021 +0200
@@ -137,7 +137,7 @@
 ## @end table
 ##
 ## Programming Note: This function is a wrapper which calls @code{movfun}.
-## For additional options and documentation, @pxref{XREFmovfun,,movfun}.
+## For additional options and documentation, @pxref{XREFmovfun,,@code{movfun}}.
 ##
 ## @seealso{movfun, movslice, movmad, movmax, movmean, movmedian, movmin, movprod, movstd, movsum}
 ## @end deftypefn
@@ -166,7 +166,7 @@
 
 
 ## FIXME: Need functional BIST tests
-# test for bug #55241
+## test for bug #55241
 %!assert ([0.5; ones(8,1); 0.5], movvar ((1:10).', 3))
 
 %!test <*56765>
@@ -178,5 +178,5 @@
 %! assert (y1(1:3), [1/4, 2/3, 5/4]);
 
 ## Test input validation
-%!error movvar ()
-%!error movvar (1)
+%!error <Invalid call> movvar ()
+%!error <Invalid call> movvar (1)
--- a/scripts/statistics/prctile.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/prctile.m	Sun May 16 09:44:35 2021 +0200
@@ -46,7 +46,7 @@
 
 function q = prctile (x, p = [], dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -68,9 +68,8 @@
     ## Find the first non-singleton dimension.
     (dim = find (sz > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-        || !(1 <= dim && dim <= nd))
-      error ("prctile: DIM must be an integer and a valid dimension");
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
+      error ("quantile: DIM must be a positive integer");
     endif
   endif
 
@@ -179,12 +178,12 @@
 %! qa = [0.1270; 0.2041; 0.6437; 0.6477; 0.9322];
 %! assert (q, qa, tol);
 
+%!assert (prctile ([1:10], 1, 3), [1:10])
+
 ## Test input validation
-%!error prctile ()
-%!error prctile (1, 2, 3, 4)
+%!error <Invalid call> prctile ()
 %!error prctile (['A'; 'B'], 10)
 %!error prctile (1:10, [true, false])
 %!error prctile (1:10, ones (2,2))
 %!error prctile (1, 1, 1.5)
 %!error prctile (1, 1, 0)
-%!error prctile (1, 1, 3)
--- a/scripts/statistics/quantile.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/quantile.m	Sun May 16 09:44:35 2021 +0200
@@ -156,7 +156,7 @@
 
 function q = quantile (x, p = [], dim, method = 5)
 
-  if (nargin < 1 || nargin > 4)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -176,14 +176,13 @@
     ## Find the first non-singleton dimension.
     (dim = find (size (x) > 1, 1)) || (dim = 1);
   else
-    if (!(isscalar (dim) && dim == fix (dim))
-        || !(1 <= dim && dim <= ndims (x)))
-      error ("quantile: DIM must be an integer and a valid dimension");
+    if (! (isscalar (dim) && dim == fix (dim) && dim > 0))
+      error ("quantile: DIM must be a positive integer");
     endif
   endif
 
   ## Set the permutation vector.
-  perm = 1:ndims (x);
+  perm = 1:(max (ndims (x), dim));
   perm(1) = dim;
   perm(dim) = 1;
 
@@ -382,16 +381,15 @@
 %!assert <*54421> (quantile ([1:10]', 0.5, 2), [1:10]')
 %!assert <*54421> (quantile ([1:10], [0.25, 0.75]), [3, 8])
 %!assert <*54421> (quantile ([1:10], [0.25, 0.75]'), [3; 8])
+%!assert (quantile ([1:10], 1, 3), [1:10])
 
 ## Test input validation
-%!error quantile ()
-%!error quantile (1, 2, 3, 4, 5)
+%!error <Invalid call> quantile ()
 %!error quantile (['A'; 'B'], 10)
 %!error quantile (1:10, [true, false])
 %!error quantile (1:10, ones (2,2))
 %!error quantile (1, 1, 1.5)
 %!error quantile (1, 1, 0)
-%!error quantile (1, 1, 3)
 %!error quantile ((1:5)', 0.5, 1, 0)
 %!error quantile ((1:5)', 0.5, 1, 10)
 
@@ -405,7 +403,7 @@
 ## Description: Quantile function of empirical samples
 function inv = __quantile__ (x, p, method = 5)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ("quantile");
   endif
 
--- a/scripts/statistics/range.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/range.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
 
 function y = range (x, dim)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -62,5 +62,4 @@
 %!assert (range (2), 0)
 
 ## Test input validation
-%!error range ()
-%!error range (1, 2, 3)
+%!error <Invalid call> range ()
--- a/scripts/statistics/ranks.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/ranks.m	Sun May 16 09:44:35 2021 +0200
@@ -53,7 +53,7 @@
 
 function y = ranks (x, dim, rtype = 0)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -105,7 +105,7 @@
       otherwise
         if (! ischar (rtype))
           rtype = num2str (rtype);
-        end
+        endif
         error ("ranks: unknown RTYPE '%s'", rtype);
     endswitch
 
@@ -164,8 +164,7 @@
 %!assert (ranks ([1, 2, 2, 4], [], "dense"), [1, 2, 2, 3])
 
 ## Test input validation
-%!error ranks ()
-%!error ranks (1, 2, 3, 4)
+%!error <Invalid call> ranks ()
 %!error <X must be a numeric vector or matrix> ranks ({1, 2})
 %!error <X must be a numeric vector or matrix> ranks (['A'; 'B'])
 %!error <DIM must be an integer> ranks (1, 1.5)
--- a/scripts/statistics/run_count.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/run_count.m	Sun May 16 09:44:35 2021 +0200
@@ -36,7 +36,7 @@
 
 function retval = run_count (x, n, dim)
 
-  if (nargin != 2 && nargin != 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -103,9 +103,8 @@
 %!assert (run_count (ones (3), 4), [0,0,0;0,0,0;1,1,1;0,0,0])
 
 ## Test input validation
-%!error run_count ()
-%!error run_count (1)
-%!error run_count (1, 2, 3, 4)
+%!error <Invalid call> run_count ()
+%!error <Invalid call> run_count (1)
 %!error run_count ({1, 2}, 3)
 %!error run_count (['A'; 'A'; 'B'], 3)
 %!error run_count (1:5, ones (2,2))
--- a/scripts/statistics/runlength.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/runlength.m	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
 
 function [count, value] = runlength (x)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -73,7 +73,6 @@
 %! assert (v, [2 0 4 0 1]);
 
 ## Test input validation
-%!error runlength ()
-%!error runlength (1, 2)
+%!error <Invalid call> runlength ()
 %!error runlength (['A'; 'B'])
 %!error runlength (ones (2,2))
--- a/scripts/statistics/skewness.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/skewness.m	Sun May 16 09:44:35 2021 +0200
@@ -87,7 +87,7 @@
 
 function y = skewness (x, flag, dim)
 
-  if (nargin < 1) || (nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -161,8 +161,7 @@
 %! assert (lastwarn (), "");
 
 ## Test input validation
-%!error skewness ()
-%!error skewness (1, 2, 3)
+%!error <Invalid call> skewness ()
 %!error <X must be a numeric vector or matrix> skewness (['A'; 'B'])
 %!error <FLAG must be 0 or 1> skewness (1, 2)
 %!error <FLAG must be 0 or 1> skewness (1, [1 0])
--- a/scripts/statistics/spearman.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/spearman.m	Sun May 16 09:44:35 2021 +0200
@@ -68,7 +68,7 @@
 
 function rho = spearman (x, y = [])
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -114,8 +114,7 @@
 %!assert (spearman ([1 2 3], [-1 1 -2]), -0.5, 5*eps)
 
 ## Test input validation
-%!error spearman ()
-%!error spearman (1, 2, 3)
+%!error <Invalid call> spearman ()
 %!error spearman (['A'; 'B'])
 %!error spearman (ones (1,2), {1, 2})
 %!error spearman (ones (2,2,2))
--- a/scripts/statistics/statistics.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/statistics.m	Sun May 16 09:44:35 2021 +0200
@@ -39,7 +39,7 @@
 
 function stats = statistics (x, dim)
 
-  if (nargin != 1 && nargin != 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -93,8 +93,7 @@
 %! assert (kurtosis (x, [], 2), s(:,9), eps);
 
 ## Test input validation
-%!error statistics ()
-%!error statistics (1, 2, 3)
+%!error <Invalid call> statistics ()
 %!error statistics (['A'; 'B'])
 %!error statistics (1, ones (2,2))
 %!error statistics (1, 1.5)
--- a/scripts/statistics/std.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/std.m	Sun May 16 09:44:35 2021 +0200
@@ -70,7 +70,7 @@
 
 function retval = std (x, opt = 0, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -126,8 +126,7 @@
 %!assert (std ([1 2 3], [], 3), [0 0 0])
 
 ## Test input validation
-%!error std ()
-%!error std (1, 2, 3, 4)
+%!error <Invalid call> std ()
 %!error <X must be a numeric> std (['A'; 'B'])
 %!error <OPT must be 0 or 1> std (1, 2)
 %!error <DIM must be an integer> std (1, [], ones (2,2))
--- a/scripts/statistics/var.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/var.m	Sun May 16 09:44:35 2021 +0200
@@ -74,7 +74,7 @@
 
 function retval = var (x, opt = 0, dim)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -123,8 +123,7 @@
 %!assert (var ([1,2,3], [], 3), [0,0,0])
 
 ## Test input validation
-%!error var ()
-%!error var (1,2,3,4)
+%!error <Invalid call> var ()
 %!error <X must be a numeric> var (['A'; 'B'])
 %!error <OPT must be 0 or 1> var (1, -1)
 %!error <FLAG must be 0 or 1> skewness (1, 2)
--- a/scripts/statistics/zscore.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/statistics/zscore.m	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 
 function [z, mu, sigma] = zscore (x, opt = 0, dim)
 
-  if (nargin < 1 || nargin > 3 )
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -102,7 +102,7 @@
 %!assert <*54531> (zscore ([1,2,3], [], 2), [-1,0,1])
 
 ## Test input validation
-%!error zscore ()
+%!error <Invalid call> zscore ()
 %!error zscore (1, 2, 3)
 %!error <X must be a numeric> zscore (['A'; 'B'])
 %!error <OPT must be empty, 0, or 1> zscore (1, ones (2,2))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/strings/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/strings/base2dec.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/base2dec.m	Sun May 16 09:44:35 2021 +0200
@@ -115,7 +115,7 @@
 
   ## Multiply the resulting digits by the appropriate power
   ## and sum the rows.
-  out = s * (base .^ (columns(s)-1 : -1 : 0)');
+  out = s * (base .^ (columns (s)-1 : -1 : 0)');
 
 endfunction
 
@@ -128,7 +128,7 @@
 %!assert <*35621> (base2dec (["0"; "1"], 2), [0; 1])
 
 ## Test input validation
-%!error base2dec ()
+%!error <Invalid call> base2dec ()
 %!error base2dec ("11120")
 %!error base2dec ("11120", 3, 4)
 %!error <symbols .* must be unique> base2dec ("11120", "1231")
--- a/scripts/strings/bin2dec.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/bin2dec.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
 
 function d = bin2dec (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -74,6 +74,5 @@
 %!assert (bin2dec (char ("1 0 1", "   1111")), [5; 15])
 
 ## Test input validation
-%!error bin2dec ()
-%!error bin2dec (1)
-%!error bin2dec ("1", 2)
+%!error <Invalid call> bin2dec ()
+%!error <S must be a string> bin2dec (1)
--- a/scripts/strings/blanks.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/blanks.m	Sun May 16 09:44:35 2021 +0200
@@ -44,7 +44,7 @@
 
 function s = blanks (n)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! (isscalar (n) && n == fix (n) && n >= 0))
     error ("blanks: N must be a non-negative integer");
@@ -63,8 +63,7 @@
 %!assert (blanks (10), "          ")
 
 ## Test input validation
-%!error blanks ()
-%!error blanks (1, 2)
+%!error <Invalid call> blanks ()
 %!error blanks (ones (2))
 %!error blanks (2.1)
 %!error blanks (-2)
--- a/scripts/strings/deblank.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/deblank.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 
 function s = deblank (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -102,5 +102,5 @@
 %!assert (deblank ({" abc   ", {"   def   "}}), {" abc", {"   def"}})
 
 %!error <Invalid call to deblank> deblank ()
-%!error <Invalid call to deblank> deblank ("foo", "bar")
+%!error <called with too many inputs> deblank ("foo", "bar")
 %!error <argument must be a string> deblank (1)
--- a/scripts/strings/dec2base.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/dec2base.m	Sun May 16 09:44:35 2021 +0200
@@ -41,8 +41,8 @@
 ## largest value.
 ##
 ## If @var{base} is a string then the characters of @var{base} are used as
-## the symbols for the digits of @var{d}.  Space (' ') may not be used as a
-## symbol.
+## the symbols for the digits of @var{d}.  Whitespace (spaces, tabs, newlines,
+##, etc.@:) may not be used as a symbol.
 ##
 ## @example
 ## @group
@@ -58,7 +58,7 @@
 
 function retval = dec2base (d, base, len)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -78,18 +78,16 @@
 
   symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   if (ischar (base))
-    symbols = base;
-    base = length (symbols);
-    if (length (unique (symbols)) != base)
+    symbols = base(:).';  # force a row vector
+    base = numel (symbols);
+    if (numel (unique (symbols)) != base)
       error ("dec2base: symbols representing digits must be unique");
-    endif
-    if (any (isspace (symbols)))
+    elseif (any (isspace (symbols)))
       error ("dec2base: whitespace characters are not valid symbols");
     endif
-  elseif (! isscalar (base))
-    error ("dec2base: cannot convert from several bases at once");
-  elseif (base < 2 || base > length (symbols))
-    error ("dec2base: BASE must be between 2 and 36, or a string of symbols");
+  elseif (! isscalar (base) || ! isreal (base) || fix (base) != base
+          || base < 2 || base > 36)
+    error ("dec2base: BASE must be an integer between 2 and 36, or a string of symbols");
   endif
 
   ## determine number of digits required to handle all numbers, can overflow
@@ -97,6 +95,9 @@
   max_len = round (log (max (max (d), 1)) / log (base)) + 1;
 
   if (nargin == 3)
+    if (! (isscalar (len) && isreal (len) && len >= 0 && len == fix (len)))
+      error ("dec2base: LEN must be a non-negative integer");
+    endif
     max_len = max (max_len, len);
   endif
 
@@ -163,15 +164,20 @@
 %!assert <*56005> (dec2base ([0, 0], 16), ["0"; "0"])
 
 ## Test input validation
-%!error dec2base ()
-%!error dec2base (1)
-%!error dec2base (1, 2, 3, 4)
-%!error dec2base ("A")
-%!error dec2base (2i)
-%!error dec2base (-1)
-%!error dec2base (1.1)
-%!error dec2base (1, "ABA")
-%!error dec2base (1, "A B")
-%!error dec2base (1, ones (2))
-%!error dec2base (1, 1)
-%!error dec2base (1, 37)
+%!error <Invalid call> dec2base ()
+%!error <Invalid call> dec2base (1)
+%!error <input must be real non-negative integers> dec2base ("A", 10)
+%!error <input must be real non-negative integers> dec2base (2i, 10)
+%!error <input must be real non-negative integers> dec2base (-1, 10)
+%!error <input must be real non-negative integers> dec2base (1.1, 10)
+%!error <symbols representing digits must be unique> dec2base (1, "ABA")
+%!error <whitespace characters are not valid symbols> dec2base (1, "A B")
+%!error <BASE must be an integer> dec2base (1, ones (2))
+%!error <BASE must be an integer> dec2base (1, 2i)
+%!error <BASE must be an integer> dec2base (1, 2.5)
+%!error <BASE must be .* between 2 and 36> dec2base (1, 1)
+%!error <BASE must be .* between 2 and 36> dec2base (1, 37)
+%!error <LEN must be a non-negative integer> dec2base (1, 2, ones(2))
+%!error <LEN must be a non-negative integer> dec2base (1, 2, 2i)
+%!error <LEN must be a non-negative integer> dec2base (1, 2, -1)
+%!error <LEN must be a non-negative integer> dec2base (1, 2, 2.5)
--- a/scripts/strings/dec2bin.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/dec2bin.m	Sun May 16 09:44:35 2021 +0200
@@ -24,45 +24,119 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {} dec2bin (@var{d}, @var{len})
-## Return a binary number corresponding to the non-negative integer @var{d},
-## as a string of ones and zeros.
+## @deftypefn  {} {} dec2bin (@var{d})
+## @deftypefnx {} {} dec2bin (@var{d}, @var{len})
+## Return a string of ones and zeros representing the conversion of the integer
+## @var{d} to a binary number.
 ##
-## For example:
+## If @var{d} is negative, return the two's complement binary value of @var{d}.
+## If @var{d} is a matrix or cell array, return a string matrix with one row
+## for each element in @var{d}, padded with leading zeros to the width of the
+## largest value.
+##
+## The optional second argument, @var{len}, specifies the minimum number of
+## digits in the result.
+##
+## Examples:
 ##
 ## @example
 ## @group
 ## dec2bin (14)
 ##      @result{} "1110"
+##
+## dec2bin (-14)
+##      @result{} "11110010"
 ## @end group
 ## @end example
 ##
-## If @var{d} is a matrix or cell array, return a string matrix with one row
-## per element in @var{d}, padded with leading zeros to the width of the
-## largest value.
+## Programming Notes: The largest negative value that can be converted into
+## two's complement is @code{- (flintmax () / 2)}.
 ##
-## The optional second argument, @var{len}, specifies the minimum number of
-## digits in the result.
+## Known @sc{matlab} Incompatibility: @sc{matlab}'s @code{dec2bin} allows
+## non-integer values for @var{d}, truncating the value using the equivalent
+## of @code{fix (@var{d})} for positive values, but, as of R2020b and in
+## conflict with published documentation, appears to use
+## @code{round (@var{d})} for negative values.  To be consistent with
+## @code{dec2hex} and @code{dec2base}, Octave produces an error for non-integer
+## valued inputs for @var{d}.  Users wanting compatible code for non-integer
+## valued inputs should make use of @code{fix} or @code{round} as appropriate.
 ## @seealso{bin2dec, dec2base, dec2hex}
 ## @end deftypefn
 
 function b = dec2bin (d, len)
 
+  if (nargin == 0)
+    print_usage ();
+  endif
+
+  if (iscell (d))
+    d = cell2mat (d);
+  endif
+  ## Create column vector for algorithm (output is always col. vector anyways)
+  d = d(:);
+
+  lt_zero_idx = (d < 0);
+  if (any (lt_zero_idx))
+    ## FIXME: Need an algorithm that works with larger values such as int64.
+    if (any (d(lt_zero_idx) < -2^52))
+      error ("dec2bin: negative inputs cannot be less than -flintmax () / 2");
+    elseif (any (d(lt_zero_idx) < intmin ("int32")))
+      d(lt_zero_idx) += flintmax ();
+    elseif (any (d < intmin ("int16")))
+      d(lt_zero_idx) += double (intmax ("uint32")) + 1;
+    elseif (any (d < intmin ("int8")))
+      d(lt_zero_idx) += double (intmax ("uint16"))+ 1;
+    else
+      d(lt_zero_idx) += double (intmax ("uint8")) + 1;
+    endif
+  endif
+
   if (nargin == 1)
     b = dec2base (d, 2);
-  elseif (nargin == 2)
+  else
     b = dec2base (d, 2, len);
-  else
-    print_usage ();
   endif
 
 endfunction
 
 
+%!assert (dec2bin (3), "11")
 %!assert (dec2bin (14), "1110")
 %!assert (dec2bin (14, 6), "001110")
+%!assert (dec2bin ([1, 2; 3, 4]), ["001"; "011"; "010"; "100"])
 %!assert (dec2bin ({1, 2; 3, 4}), ["001"; "011"; "010"; "100"])
+%!assert (dec2bin ({1, 2; 3, 4}, 4), ["0001"; "0011"; "0010"; "0100"])
+
+## Test negative inputs
+%!assert (dec2bin (-3), "11111101")
+%!assert (dec2bin (-3, 3), "11111101")
+%!assert (dec2bin (-3, 9), "011111101")
+%!assert (dec2bin (-2^7 -1), "1111111101111111")
+%!assert (dec2bin (-2^15 -1), "11111111111111110111111111111111")
+## FIXME: Matlab generates a string that is 64 characters long
+%!assert (dec2bin (-2^31 -1),
+%!        "11111111111111111111101111111111111111111111111111111")
+%!assert (dec2bin (-2^52),
+%!        "10000000000000000000000000000000000000000000000000000")
+## FIXME: Uncomment when support for int64 is added
+%!#assert (dec2bin (-2^63),
+%!        "1000000000000000000000000000000000000000000000000000000000000000")
+%!#test
+%! assert (dec2bin (int64 (-2^63)),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2bin (int64 (-2^63) -1),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2bin (int64 (-2^63) +1),
+%!        "1000000000000000000000000000000000000000000000000000000000000001");
+%!assert (dec2bin ([-1, -2; -3, -4]),
+%!        ["11111111"; "11111101"; "11111110"; "11111100"])
+%!assert (dec2bin ([1, 2; 3, -4]),
+%!        ["00000001"; "00000011"; "00000010"; "11111100"])
+%!assert (dec2bin ({1, 2; 3, -4}),
+%!        ["00000001"; "00000011"; "00000010"; "11111100"])
 
 ## Test input validation
-%!error dec2bin ()
-%!error dec2bin (1, 2, 3)
+%!error <Invalid call> dec2bin ()
+%!error <negative inputs cannot be less than> dec2bin (- flintmax ())
--- a/scripts/strings/dec2hex.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/dec2hex.m	Sun May 16 09:44:35 2021 +0200
@@ -24,36 +24,67 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {} dec2hex (@var{d}, @var{len})
-## Return the hexadecimal string corresponding to the non-negative integer
-## @var{d}.
+## @deftypefn  {} {} dec2hex (@var{d})
+## @deftypefnx {} {} dec2hex (@var{d}, @var{len})
+## Return a string representing the conversion of the integer @var{d} to a
+## hexadecimal (base16) number.
 ##
-## For example:
+## If @var{d} is negative, return the hexadecimal equivalent of the two's
+## complement binary value of @var{d}.
+## If @var{d} is a matrix or cell array, return a string matrix with one row
+## for each element in @var{d}, padded with leading zeros to the width of the
+## largest value.
+##
+## The optional second argument, @var{len}, specifies the minimum number of
+## digits in the result.
+##
+## Examples:
 ##
 ## @example
 ## @group
 ## dec2hex (2748)
 ##      @result{} "ABC"
+##
+## dec2hex (-2)
+##      @result{} "FE"
 ## @end group
 ## @end example
 ##
-## If @var{d} is a matrix or cell array, return a string matrix with one row
-## per element in @var{d}, padded with leading zeros to the width of the
-## largest value.
-##
-## The optional second argument, @var{len}, specifies the minimum number of
-## digits in the result.
 ## @seealso{hex2dec, dec2base, dec2bin}
 ## @end deftypefn
 
 function h = dec2hex (d, len)
 
+  if (nargin == 0)
+    print_usage ();
+  endif
+
+  if (iscell (d))
+    d = cell2mat (d);
+  endif
+  ## Create column vector for algorithm (output is always col. vector anyways)
+  d = d(:);
+
+  lt_zero_idx = (d < 0);
+  if (any (lt_zero_idx))
+    ## FIXME: Need an algorithm that works with larger values such as int64.
+    if (any (d(lt_zero_idx) < -2^52))
+      error ("dec2hex: negative inputs cannot be less than -flintmax () / 2");
+    elseif (any (d(lt_zero_idx) < intmin ("int32")))
+      d(lt_zero_idx) += flintmax ();
+    elseif (any (d < intmin ("int16")))
+      d(lt_zero_idx) += double (intmax ("uint32")) + 1;
+    elseif (any (d < intmin ("int8")))
+      d(lt_zero_idx) += double (intmax ("uint16"))+ 1;
+    else
+      d(lt_zero_idx) += double (intmax ("uint8")) + 1;
+    endif
+  endif
+
   if (nargin == 1)
     h = dec2base (d, 16);
-  elseif (nargin == 2)
+  else
     h = dec2base (d, 16, len);
-  else
-    print_usage ();
   endif
 
 endfunction
@@ -61,8 +92,36 @@
 
 %!assert (dec2hex (2748), "ABC")
 %!assert (dec2hex (2748, 5), "00ABC")
+%!assert (dec2hex ([2748, 2746]), ["ABC"; "ABA"])
 %!assert (dec2hex ({2748, 2746}), ["ABC"; "ABA"])
+%!assert (dec2hex ({2748, 2746}, 4), ["0ABC"; "0ABA"])
+
+## Test negative inputs
+%!assert (dec2hex (-3), "FD")
+%!assert (dec2hex (-3, 1), "FD")
+%!assert (dec2hex (-3, 3), "0FD")
+%!assert (dec2hex (-2^7 -1), "FF7F")
+%!assert (dec2hex (-2^15 -1), "FFFF7FFF")
+## FIXME: Matlab returns longer string that begins with 'F'
+%!assert (dec2hex (-2^31 -1), "1FFFFF7FFFFFFF")
+## FIXME: Matlab returns longer string that begins with 'FFF'
+%!assert (dec2hex (-2^52), "10000000000000")
+## FIXME: Uncomment when support for int64 is added
+%!#assert (dec2hex (-2^63),
+%!        "1000000000000000000000000000000000000000000000000000000000000000")
+%!#test
+%! assert (dec2hex (int64 (-2^63)),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2hex (int64 (-2^63) -1),
+%!        "1000000000000000000000000000000000000000000000000000000000000000");
+%!#test
+%! assert (dec2hex (int64 (-2^63) +1),
+%!        "1000000000000000000000000000000000000000000000000000000000000001");
+%!assert (dec2hex ([-1, -2; -3, -4]), ["FF"; "FD"; "FE"; "FC"])
+%!assert (dec2hex ([1, 2; 3, -4]), ["01"; "03"; "02"; "FC"])
+%!assert (dec2hex ({1, 2; 3, -4}), ["01"; "03"; "02"; "FC"])
 
 ## Test input validation
-%!error dec2hex ()
-%!error dec2hex (1, 2, 3)
+%!error <Invalid call> dec2hex ()
+%!error <negative inputs cannot be less than> dec2hex (- flintmax ())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/strings/endsWith.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,173 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{retval} =} endsWith (@var{str}, @var{pattern})
+## @deftypefnx {} {@var{retval} =} endsWith (@var{str}, @var{pattern}, "IgnoreCase", @var{ignore_case})
+## Check whether string(s) end with pattern(s).
+##
+## Return an array of logical values that indicates which string(s) in the
+## input @var{str} (a single string or cell array of strings) end with
+## the input @var{pattern} (a single string or cell array of strings).
+##
+## If the value of the parameter @qcode{"IgnoreCase"} is true, then the
+## function will ignore the letter case of @var{str} and @var{pattern}.  By
+## default, the comparison is case sensitive.
+##
+## Examples:
+##
+## @example
+## @group
+## ## one string and one pattern while considering case
+## endsWith ("hello", "lo")
+##       @result{}  1
+## @end group
+##
+## @group
+## ## one string and one pattern while ignoring case
+## endsWith ("hello", "LO", "IgnoreCase", true)
+##       @result{}  1
+## @end group
+##
+## @group
+## ## multiple strings and multiple patterns while considering case
+## endsWith (@{"tests.txt", "mydoc.odt", "myFunc.m", "results.pptx"@},
+##           @{".docx", ".odt", ".txt"@})
+##       @result{}  1  1  0  0
+## @end group
+##
+## @group
+## ## multiple strings and one pattern while considering case
+## endsWith (@{"TESTS.TXT", "mydoc.odt", "result.txt", "myFunc.m"@},
+##           ".txt", "IgnoreCase", false)
+##       @result{}  0  0  1  0
+## @end group
+##
+## @group
+## ## multiple strings and one pattern while ignoring case
+## endsWith (@{"TESTS.TXT", "mydoc.odt", "result.txt", "myFunc.m"@},
+##           ".txt", "IgnoreCase", true)
+##       @result{}  1  0  1  0
+## @end group
+## @end example
+##
+## @seealso{startsWith, regexp, strncmp, strncmpi}
+## @end deftypefn
+
+function retval = endsWith (str, pattern, IgnoreCase, ignore_case)
+
+  if (nargin != 2 && nargin != 4)
+    print_usage ();
+  endif
+
+  ## Validate input str and pattern
+  if (! (iscellstr (str) || ischar (str)))
+    error ("endsWith: STR must be a string or cell array of strings");
+  endif
+  if (! (iscellstr (pattern) || ischar (pattern)))
+    error ("endsWith: PATTERN must be a string or cell array of strings");
+  endif
+
+  ## reverse str and pattern
+  str = cellfun (@flip, cellstr (str), "UniformOutput", false);
+  pattern = cellfun (@flip, cellstr (pattern), "UniformOutput", false);
+
+  if (nargin == 2)
+    ignore_case = false;
+  else
+    ## For Matlab compatibility accept any abbreviation of 3rd argument
+    if (! ischar (IgnoreCase) || isempty (IgnoreCase)
+        || ! strncmpi (IgnoreCase, "IgnoreCase", length (IgnoreCase)))
+      error ('endsWith: third input must be "IgnoreCase"');
+    endif
+
+    if (! isscalar (ignore_case) || ! isreal (ignore_case))
+      error ('endsWith: "IgnoreCase" value must be a logical scalar');
+    endif
+    ignore_case = logical (ignore_case);
+  endif
+
+  retval = false (size (str));
+  if (ignore_case)
+    for j = 1:numel (pattern)
+      retval |= strncmpi (str, pattern{j}, length (pattern{j}));
+    endfor
+  else
+    for j = 1:numel (pattern)
+      retval |= strncmp (str, pattern{j}, length (pattern{j}));
+    endfor
+  endif
+
+endfunction
+
+
+## Test simple use with one string and one pattern
+%!assert (endsWith ("hello", "lo"))
+%!assert (! endsWith ("hello", "LO"))
+%!assert (endsWith ("hello", "LO", "i", 5))
+%!assert (! endsWith ("hello", "no"))
+
+## Test multiple strings with a single pattern
+%!test
+%! str = {"myFile.odt", "results.ppt", "myCode.m"; ...
+%!        "data-analysis.ppt", "foundations.txt", "data.odt"};
+%! pattern = ".odt";
+%! expected = [true, false, false; false, false, true];
+%! assert (endsWith (str, pattern), expected);
+
+## Test multiple strings with multiple patterns
+%!test
+%! str = {"tests.txt", "mydoc.odt", "myFunc.m", "results.pptx"};
+%! pattern = {".docx", ".odt", ".txt"};
+%! expected = [true, true, false, false];
+%! assert (endsWith (str, pattern), expected);
+
+## Test IgnoreCase
+%!test
+%! str = {"TESTS.TXT", "mydoc.odt", "result.txt", "myFunc.m"};
+%! pattern = ".txt";
+%! expected_ignore = [true, false, true, false];
+%! expected_wo_ignore = [false, false, true, false];
+%! assert (endsWith (str, pattern, "IgnoreCase", true), expected_ignore);
+%! assert (endsWith (str, pattern, "IgnoreCase", false), expected_wo_ignore);
+%! assert (endsWith (str, pattern, "I", 500), expected_ignore);
+%! assert (endsWith (str, pattern, "iG", 0), expected_wo_ignore);
+
+## Test input validation
+%!error <Invalid call> endsWith ()
+%!error endsWith ("A")
+%!error endsWith ("A", "B", "C")
+%!error endsWith ("A", "B", "C", "D", "E")
+%!error <STR must be a string> endsWith (152, "hi")
+%!error <STR must be a .* cell array of strings> endsWith ({152}, "hi")
+%!error <PATTERN must be a string> endsWith ("hi", 152)
+%!error <PATTERN must be a .* cell array of strings> endsWith ("hi", {152})
+%!error <third input must be "IgnoreCase"> endsWith ("hello", "lo", 1, 1)
+%!error <third input must be "IgnoreCase"> endsWith ("hello", "lo", "", 1)
+%!error <third input must be "IgnoreCase"> endsWith ("hello", "lo", "foo", 1)
+%!error <"IgnoreCase" value must be a logical scalar>
+%! endsWith ("hello", "hi", "i", "true");
+%!error <"IgnoreCase" value must be a logical scalar>
+%! endsWith ("hello", "hi", "i", {true});
--- a/scripts/strings/erase.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/erase.m	Sun May 16 09:44:35 2021 +0200
@@ -64,7 +64,7 @@
 ## @end group
 ## @end example
 ##
-## See @code{strrep} for processing overlaps.
+## For processing overlaps, @pxref{XREFstrrep,,@code{strrep}}.
 ##
 ## @seealso{strrep, regexprep}
 ## @end deftypefn
@@ -143,7 +143,7 @@
 %!assert (erase ({'Hello World t '}, {'ld '; 'o '}), {'HellWort '})
 
 ## Test input validation
-%!error erase ()
+%!error <Invalid call> erase ()
 %!error erase ("a")
 %!error erase ("a", "b", "c")
 %!error <STR must be a string> erase ([1], "foo")
--- a/scripts/strings/hex2dec.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/hex2dec.m	Sun May 16 09:44:35 2021 +0200
@@ -50,7 +50,7 @@
 
 function d = hex2dec (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -65,6 +65,5 @@
 %!assert (hex2dec ({"A1", "1A"}), [161; 26])
 
 ## Test input validation
-%!error hex2dec ()
-%!error hex2dec (1)
-%!error hex2dec ("1", 2)
+%!error <Invalid call> hex2dec ()
+%!error <S must be a string> hex2dec (1)
--- a/scripts/strings/index.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/index.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
 
 function n = index (s, t, direction = "first")
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -113,7 +113,7 @@
 %! assert (index (str, "o", "last"), [5; 2; 3; 2]);
 
 ## Test input validation
-%!error index ()
+%!error <Invalid call> index ()
 %!error index ("a")
 %!error index ("a", "b", "first", "d")
 %!error index (1, "bar")
--- a/scripts/strings/isletter.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/isletter.m	Sun May 16 09:44:35 2021 +0200
@@ -34,7 +34,7 @@
 
 function retval = isletter (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -43,5 +43,5 @@
 endfunction
 
 
-%!error isletter ()
+%!error <Invalid call> isletter ()
 %!error isletter ("a", "b")
--- a/scripts/strings/isstring.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/isstring.m	Sun May 16 09:44:35 2021 +0200
@@ -42,7 +42,7 @@
 
 function retval = isstring (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -59,5 +59,5 @@
 %!assert (isstring ({'a'}), false)
 %!assert (isstring ({"b"}), false)
 
-%!error isstring ()
+%!error <Invalid call> isstring ()
 %!error isstring ("a", "b")
--- a/scripts/strings/isstrprop.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/isstrprop.m	Sun May 16 09:44:35 2021 +0200
@@ -137,7 +137,7 @@
 %!assert (isstrprop ({"AbC", "123"}, "lower"), {logical([0 1 0]), logical([0 0 0])})
 
 ## Test input validation
-%!error isstrprop ()
+%!error <Invalid call> isstrprop ()
 %!error isstrprop ("abc123")
 %!error isstrprop ("abc123", "alpha", "alpha")
 %!error <invalid string property> isstrprop ("abc123", "foo")
--- a/scripts/strings/mat2str.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/mat2str.m	Sun May 16 09:44:35 2021 +0200
@@ -65,7 +65,7 @@
 
 function s = mat2str (x, n = 15, cls = "")
 
-  if (nargin < 1 || nargin > 3 || ! (isnumeric (x) || islogical (x)))
+  if (nargin < 1 || ! (isnumeric (x) || islogical (x)))
     print_usage ();
   elseif (ndims (x) > 2)
     error ("mat2str: X must be two dimensional");
@@ -151,8 +151,7 @@
 %!assert (mat2str (logical ([0 1; 0 0])), "[false true;false false]")
 
 ## Test input validation
-%!error mat2str ()
-%!error mat2str (1,2,3,4)
+%!error <Invalid call> mat2str ()
 %!error mat2str (["Hello"])
 %!error <X must be two dimensional> mat2str (ones (3,3,2))
 %!error <N must have only 1 or 2 elements> mat2str (ones (3,3), [1 2 3])
--- a/scripts/strings/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/base2dec.m \
   %reldir%/bin2dec.m \
   %reldir%/blanks.m \
@@ -9,6 +10,7 @@
   %reldir%/dec2base.m \
   %reldir%/dec2bin.m \
   %reldir%/dec2hex.m \
+  %reldir%/endsWith.m \
   %reldir%/erase.m \
   %reldir%/hex2dec.m \
   %reldir%/index.m \
@@ -20,6 +22,7 @@
   %reldir%/ostrsplit.m \
   %reldir%/regexptranslate.m \
   %reldir%/rindex.m \
+  %reldir%/startsWith.m \
   %reldir%/str2num.m \
   %reldir%/strcat.m \
   %reldir%/strchr.m \
--- a/scripts/strings/native2unicode.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/native2unicode.m	Sun May 16 09:44:35 2021 +0200
@@ -45,7 +45,7 @@
 
 function utf8_str = native2unicode (native_bytes, codepage = "")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,17 +58,12 @@
     error ("native2unicode: NATIVE_BYTES must be a numeric vector");
   endif
 
-  if (! ischar (codepage))
-    error ("native2unicode: CODEPAGE must be a string")
+  if (nargin == 2 && ! (ischar (codepage) && isrow (codepage)))
+    error ("native2unicode: CODEPAGE must be a string");
   endif
 
-  ## FIXME: Would it be better to do this by converting to uint8?  Or to
-  ## let __native2unicode to the clipping?  Multiple steps here means
-  ## looping through the data and allocating memory multiple times.
-
-  native_bytes = round (native_bytes);
-  native_bytes(native_bytes < 0) = 0;
-  native_bytes(native_bytes > 255) = 255;
+  ## Convert to uint8 which rounds and clips values to range [0, 255]3
+  native_bytes = uint8 (native_bytes);
 
   utf8_str = __native2unicode__ (native_bytes, codepage);
 
@@ -88,15 +83,16 @@
 %! assert (double (native2unicode ([164:166 0 167:170], 'ISO-8859-5')),
 %!         [208 132 208 133 208 134 0 208 135 208 136 208 137 208 138]);
 
-%!assert (native2unicode ("foobar"), "foobar");
+%!assert (native2unicode ("foobar"), "foobar")
 %!assert <*54384> (double (native2unicode ([0 0 120.3 0 0 122.6 0 0])),
-%!        [0 0 120 0 0 123 0 0]);
+%!                 [0 0 120 0 0 123 0 0])
 
 %!error <Invalid call> native2unicode ()
-%!error <Invalid call> native2unicode (1, 'ISO-8859-1', 'test')
+%!error <called with too many inputs> native2unicode (1, 'ISO-8859-1', 'test')
 %!error <NATIVE_BYTES must be a numeric vector> native2unicode ([1 2; 3 4])
 %!error <NATIVE_BYTES must be a numeric vector> native2unicode ({1 2 3 4})
 %!error <CODEPAGE must be a string> native2unicode (164:170, 123)
+%!error <CODEPAGE must be a string> native2unicode (164:170, ['ISO-8859-1']')
 %!testif HAVE_ICONV
 %! fail ("native2unicode (234, 'foo')",
 %!       "converting from codepage 'foo' to UTF-8");
--- a/scripts/strings/ostrsplit.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/ostrsplit.m	Sun May 16 09:44:35 2021 +0200
@@ -62,7 +62,7 @@
 
 function cstr = ostrsplit (s, sep, strip_empty = false)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   elseif (! ischar (s) || ! ischar (sep))
     error ("ostrsplit: S and SEP must be string values");
@@ -119,7 +119,7 @@
 %!assert (ostrsplit (char ("a,bc", ",de"), ", ", true), {"a", "bc", "de"})
 
 ## Test input validation
-%!error ostrsplit ()
+%!error <Invalid call> ostrsplit ()
 %!error ostrsplit ("abc")
 %!error ostrsplit ("abc", "b", true, 4)
 %!error <S and SEP must be string values> ostrsplit (123, "b")
--- a/scripts/strings/regexptranslate.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/regexptranslate.m	Sun May 16 09:44:35 2021 +0200
@@ -89,6 +89,6 @@
 ## Test input validation
 %!error <Invalid call to regexptranslate> regexptranslate ()
 %!error <Invalid call to regexptranslate> regexptranslate ("wildcard")
-%!error <Invalid call to regexptranslate> regexptranslate ("a", "b", "c")
+%!error <called with too many inputs> regexptranslate ("a", "b", "c")
 %!error <invalid operation> regexptranslate ("foo", "abc")
 %!error <operation OP must be a string> regexptranslate (10, "abc")
--- a/scripts/strings/rindex.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/rindex.m	Sun May 16 09:44:35 2021 +0200
@@ -67,6 +67,6 @@
 %! assert (rindex (str, "o"), [5; 2; 3; 2]);
 
 ## Test input validation
-%!error rindex ()
+%!error <Invalid call> rindex ()
 %!error rindex ("foo")
 %!error rindex ("foo", "bar", "last")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/strings/startsWith.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,172 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {@var{retval} =} startsWith (@var{str}, @var{pattern})
+## @deftypefnx {} {@var{retval} =} startsWith (@var{str}, @var{pattern}, "IgnoreCase", @var{ignore_case})
+## Check whether string(s) start with pattern(s).
+##
+## Return an array of logical values that indicates which string(s) in the
+## input @var{str} (a single string or cell array of strings) begin with
+## the input @var{pattern} (a single string or cell array of strings).
+##
+## If the value of the parameter @qcode{"IgnoreCase"} is true, then the
+## function will ignore the letter case of @var{str} and @var{pattern}.  By
+## default, the comparison is case sensitive.
+##
+## Examples:
+##
+## @example
+## @group
+## ## one string and one pattern while considering case
+## startsWith ("hello", "he")
+##       @result{}  1
+## @end group
+##
+## @group
+## ## one string and one pattern while ignoring case
+## startsWith ("hello", "HE", "IgnoreCase", true)
+##       @result{}  1
+## @end group
+##
+## @group
+## ## multiple strings and multiple patterns while considering case
+## startsWith (@{"lab work.pptx", "data.txt", "foundations.ppt"@},
+##             @{"lab", "data"@})
+##       @result{}  1  1  0
+## @end group
+##
+## @group
+## ## multiple strings and one pattern while considering case
+## startsWith (@{"DATASHEET.ods", "data.txt", "foundations.ppt"@},
+##             "data", "IgnoreCase", false)
+##       @result{}  0  1  0
+## @end group
+##
+## @group
+## ## multiple strings and one pattern while ignoring case
+## startsWith (@{"DATASHEET.ods", "data.txt", "foundations.ppt"@},
+##             "data", "IgnoreCase", true)
+##       @result{}  1  1  0
+## @end group
+## @end example
+##
+## @seealso{endsWith, regexp, strncmp, strncmpi}
+## @end deftypefn
+
+function retval = startsWith (str, pattern, IgnoreCase, ignore_case)
+
+  if (nargin != 2 && nargin != 4)
+    print_usage ();
+  endif
+
+  ## Validate input str and pattern
+  if (! (iscellstr (str) || ischar (str)))
+    error ("startsWith: STR must be a string or cell array of strings");
+  endif
+  if (! (iscellstr (pattern) || ischar (pattern)))
+    error ("startsWith: PATTERN must be a string or cell array of strings");
+  endif
+
+  str = cellstr (str);
+  pattern = cellstr (pattern);
+
+  if (nargin == 2)
+    ignore_case = false;
+  else
+    ## For Matlab compatibility accept any abbreviation of 3rd argument
+    if (! ischar (IgnoreCase) || isempty (IgnoreCase)
+        || ! strncmpi (IgnoreCase, "IgnoreCase", length (IgnoreCase)))
+      error ('startsWith: third input must be "IgnoreCase"');
+    endif
+
+    if (! isscalar (ignore_case) || ! isreal (ignore_case))
+      error ('startsWith: "IgnoreCase" value must be a logical scalar');
+    endif
+    ignore_case = logical (ignore_case);
+  endif
+
+  retval = false (size (str));
+  if (ignore_case)
+    for j = 1:numel (pattern)
+      retval |= strncmpi (str, pattern{j}, length (pattern{j}));
+    endfor
+  else
+    for j = 1:numel (pattern)
+      retval |= strncmp (str, pattern{j}, length (pattern{j}));
+    endfor
+  endif
+
+endfunction
+
+
+## Test simple use with one string and one pattern
+%!assert (startsWith ("hello", "he"))
+%!assert (! startsWith ("hello", "HE"))
+%!assert (startsWith ("hello", "HE", "i", 5))
+%!assert (! startsWith ("hello", "no"))
+
+## Test multiple strings with a single pattern
+%!test
+%! str = {"data science", "dataSheet.ods", "myFunc.m"; "foundations.ppt", ...
+%!        "results.txt", "myFile.odt"};
+%! pattern = "data";
+%! expected = [true, true, false; false, false, false];
+%! assert (startsWith (str, pattern), expected);
+
+## Test multiple strings with multiple patterns
+%!test
+%! str = {"lab work.pptx", "myFile.odt", "data.txt", "foundations.ppt"};
+%! pattern = {"lab", "data"};
+%! expected = [true, false, true, false];
+%! assert (startsWith (str, pattern), expected);
+
+## Test IgnoreCase
+%!test
+%! str = {"DATASHEET.ods", "myFile.odt", "data.txt", "foundations.ppt"};
+%! pattern = "data";
+%! expected_ignore = [true, false, true, false];
+%! expected_wo_ignore = [false, false, true, false];
+%! assert (startsWith (str, pattern, "IgnoreCase", true), expected_ignore);
+%! assert (startsWith (str, pattern, "IgnoreCase", false), expected_wo_ignore);
+%! assert (startsWith (str, pattern, "I", 500), expected_ignore);
+%! assert (startsWith (str, pattern, "iG", 0), expected_wo_ignore);
+
+## Test input validation
+%!error <Invalid call> startsWith ()
+%!error startsWith ("A")
+%!error startsWith ("A", "B", "C")
+%!error startsWith ("A", "B", "C", "D", "E")
+%!error <STR must be a string> startsWith (152, "hi")
+%!error <STR must be a .* cell array of strings> startsWith ({152}, "hi")
+%!error <PATTERN must be a string> startsWith ("hi", 152)
+%!error <PATTERN must be a .* cell array of strings> startsWith ("hi", {152})
+%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", 1, 1)
+%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", "", 1)
+%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", "foo", 1)
+%!error <"IgnoreCase" value must be a logical scalar>
+%! startsWith ("hello", "hi", "i", "true");
+%!error <"IgnoreCase" value must be a logical scalar>
+%! startsWith ("hello", "hi", "i", {true});
--- a/scripts/strings/str2num.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/str2num.m	Sun May 16 09:44:35 2021 +0200
@@ -55,7 +55,7 @@
 
 function [m, state] = str2num (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   elseif (! ischar (s))
     error ("str2num: S must be a string or string array");
@@ -90,6 +90,5 @@
 %! assert (! state);
 
 ## Test input validation
-%!error str2num ()
-%!error str2num ("string", 1)
+%!error <Invalid call> str2num ()
 %!error <S must be a string> str2num ({"string"})
--- a/scripts/strings/strchr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/strchr.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 
 function varargout = strchr (str, chars, varargin)
 
-  if (nargin < 2)
+  if (nargin < 2 || nargin > 4)
     print_usage ();
   elseif (! ischar (str))
     error ("strchr: STR argument must be a string or string array");
@@ -82,7 +82,8 @@
 %!assert (strchr ("Octave is the best software", "software"), [3, 4, 6, 9, 11, 13, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27])
 
 ## Test input validation
-%!error strchr ()
-%!error strchr (1)
+%!error <Invalid call> strchr ()
+%!error <Invalid call> strchr (1)
+%!error <Invalid call> strchr ("s", "a", 1, "last", 5)
 %!error <STR argument must be a string> strchr (1, "aeiou")
 %!error <CHARS argument must be a string> strchr ("aeiou", 1)
--- a/scripts/strings/strjoin.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/strjoin.m	Sun May 16 09:44:35 2021 +0200
@@ -49,11 +49,9 @@
 ## @seealso{strsplit}
 ## @end deftypefn
 
-function rval = strjoin (cstr, delimiter)
+function rval = strjoin (cstr, delimiter = " ")
 
-  if (nargin == 1)
-    delimiter = " ";
-  elseif (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! (iscellstr (cstr) && (ischar (delimiter) || iscellstr (delimiter))))
     print_usage ();
--- a/scripts/strings/strjust.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/strjust.m	Sun May 16 09:44:35 2021 +0200
@@ -51,7 +51,7 @@
 
 function y = strjust (s, pos = "right")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! ischar (s) || ndims (s) > 2)
     error ("strjust: S must be a string or 2-D character matrix");
@@ -113,6 +113,6 @@
 
 ## Test input validation
 %!error <Invalid call to strjust> strjust ()
-%!error <Invalid call to strjust> strjust (["a";"ab"], "center", 1)
+%!error <called with too many inputs> strjust (["a";"ab"], "center", 1)
 %!error <S must be a string> strjust (ones (3,3))
 %!error <S must be a string> strjust (char (ones (3,3,3)))
--- a/scripts/strings/strsplit.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/strsplit.m	Sun May 16 09:44:35 2021 +0200
@@ -187,7 +187,7 @@
   if (! ischar (str) || (! ischar (del) && ! iscellstr (del)))
     error ("strsplit: S and DEL must be string values");
   elseif (! isempty (str) && ! isrow (str))
-    error ("strsplit: S must be a char row vector")
+    error ("strsplit: S must be a char row vector");
   elseif (! isscalar (args.collapsedelimiters))
     error ("strsplit: COLLAPSEDELIMITERS must be a scalar value");
   endif
@@ -314,7 +314,7 @@
 %!assert <*47403> (strsplit ('xxx+yyy', '+'), {"xxx", "yyy"})
 
 ## Test input validation
-%!error strsplit ()
+%!error <Invalid call> strsplit ()
 %!error strsplit ("abc", "b", true, 4)
 %!error <invalid parameter name, 'foo'> strsplit ("abc", "b", "foo", "true")
 %!error <S and DEL must be string values> strsplit (123, "b")
--- a/scripts/strings/strtok.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/strtok.m	Sun May 16 09:44:35 2021 +0200
@@ -58,12 +58,12 @@
 
 function [tok, rem] = strtok (str, delim)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   elseif (! (ischar (str) || iscellstr (str)))
-    error ("strtok: STR must be a string or cell array of strings.");
+    error ("strtok: STR must be a string or cell array of strings");
   elseif (ischar (str) && ! isvector (str) &&! isempty (str))
-    error ("strtok: STR cannot be a 2-D character array.");
+    error ("strtok: STR cannot be a 2-D character array");
   endif
 
   if (nargin < 2 || isempty (delim))
@@ -137,7 +137,7 @@
     if (isargout (2))
       rem = cell (size (str));
       rem(eidx) = {""};
-      rem(midx) = tmp(2:2:end);
+      rem (midx) = tmp(2:2:end);
     endif
   endif
 
@@ -229,7 +229,6 @@
 %! endfor
 
 ## Test input validation
-%!error strtok ()
-%!error strtok ("a", "b", "c")
+%!error <Invalid call> strtok ()
 %!error <STR must be a string> strtok (1, "b")
 %!error <STR cannot be a 2-D> strtok (char ("hello", "world"), "l")
--- a/scripts/strings/strtrim.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/strtrim.m	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 
 function s = strtrim (s)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -90,6 +90,6 @@
 %!assert (strtrim ({" abc   ", {"   def   "}}), {"abc", {"def"}})
 
 %!error <Invalid call to strtrim> strtrim ()
-%!error <Invalid call to strtrim> strtrim ("abc", "def")
+%!error <called with too many inputs> strtrim ("abc", "def")
 %!error <argument must be a string> strtrim (1)
 %!error <argument must be a string> strtrim ({[]})
--- a/scripts/strings/strtrunc.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/strtrunc.m	Sun May 16 09:44:35 2021 +0200
@@ -78,7 +78,7 @@
 %! assert (y{2}, repmat ("line", 2, 1));
 
 ## Test input validation
-%!error strtrunc ()
+%!error <Invalid call> strtrunc ()
 %!error strtrunc ("abcd")
 %!error strtrunc ("abcd", 4, 5)
 %!error <N must be a positive integer> strtrunc ("abcd", ones (2,2))
--- a/scripts/strings/substr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/substr.m	Sun May 16 09:44:35 2021 +0200
@@ -54,7 +54,7 @@
 
 function t = substr (s, offset, len)
 
-  if (nargin < 2 || nargin > 3)
+  if (nargin < 2)
     print_usage ();
   endif
 
@@ -104,7 +104,7 @@
 %!assert (isempty (substr ("This is a test string", 1, 0)))
 
 ## Test input validation
-%!error substr ()
+%!error <Invalid call> substr ()
 %!error substr ("foo", 2, 3, 4)
 %!error substr (ones (5, 1), 1, 1)
 %!error substr ("foo", ones (2,2))
--- a/scripts/strings/unicode2native.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/unicode2native.m	Sun May 16 09:44:35 2021 +0200
@@ -45,22 +45,28 @@
 
 function native_bytes = unicode2native (utf8_str, codepage = "")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
+  ## For Matlab compatibility, return empty output for empty input.
+  if (isempty (utf8_str))
+    native_bytes = uint8 ([]);
+    return;
+  endif
+
   if (! ischar (utf8_str) || ! isvector (utf8_str))
     error ("unicode2native: UTF8_STR must be a character vector");
   endif
 
-  if (! ischar (codepage))
+  if (! (ischar (codepage) && isrow (codepage)))
     error ("unicode2native: CODEPAGE must be a string");
   endif
 
   native_bytes = __unicode2native__ (utf8_str, codepage);
 
   if (iscolumn (utf8_str))
-    native_bytes = native_bytes';
+    native_bytes = native_bytes.';
   endif
 
 endfunction
@@ -69,14 +75,16 @@
 %!testif HAVE_ICONV
 %! assert (unicode2native ("ЄЅІЇЈЉЊ", "ISO-8859-5"), uint8 (164:170));
 %!testif HAVE_ICONV
-%! assert (unicode2native (["ЄЅІ" 0 "ЇЈЉЊ"], "ISO-8859-5"),
+%! assert (unicode2native (["ЄЅІ" "\0" "ЇЈЉЊ"], "ISO-8859-5"),
 %!         uint8 ([164:166 0 167:170]));
+%!assert <*60480> (unicode2native (''), uint8 ([]))
 
 %!error <Invalid call> unicode2native ()
-%!error <Invalid call> unicode2native ('a', 'ISO-8859-1', 'test')
+%!error <called with too many inputs> unicode2native ('a', 'ISO-8859-1', 'test')
 %!error <UTF8_STR must be a character vector> unicode2native (['ab'; 'cd'])
 %!error <UTF8_STR must be a character vector> unicode2native ({1 2 3 4})
 %!error <CODEPAGE must be a string> unicode2native ('ЄЅІЇЈЉЊ', 123)
+%!error <CODEPAGE must be a string> unicode2native ('ЄЅІЇЈЉЊ', ['ISO-8859-1']')
 %!testif HAVE_ICONV
 %! fail ("unicode2native ('a', 'foo')",
 %!       "converting from UTF-8 to codepage 'foo'");
--- a/scripts/strings/untabify.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/untabify.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
 
 function s = untabify (t, tw = 8, deblank_arg = false)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   elseif (! (ischar (t) || iscellstr (t)))
     error ("untabify: T must be a string or cellstring");
@@ -122,6 +122,6 @@
 %! s = char (randi ([97 97+25], 3, 3));
 %! assert (untabify (s), char (untabify (cellstr (s))));
 
-%!error untabify ()
-%!error untabify (1,2,3,4)
+## Test input validation
+%!error <Invalid call> untabify ()
 %!error <must be a string> untabify (1)
--- a/scripts/strings/validatestring.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/strings/validatestring.m	Sun May 16 09:44:35 2021 +0200
@@ -32,15 +32,14 @@
 ## @var{strarray}.
 ##
 ## When @var{str} is a character string to be tested, and @var{strarray} is a
-## cellstr of valid values, then @var{validstr} will be the validated form
-## of @var{str} where validation is defined as @var{str} being a member
-## or substring of @var{validstr}.  This is useful for both verifying
-## and expanding short options, such as @qcode{"r"}, to their longer forms,
-## such as @qcode{"red"}.  If @var{str} is a substring of @var{validstr}, and
-## there are multiple matches, the shortest match will be returned if all
-## matches are substrings of each other.  Otherwise, an error will be raised
-## because the expansion of @var{str} is ambiguous.  All comparisons are case
-## insensitive.
+## cell array of strings of valid values, then @var{validstr} will be the
+## validated form of @var{str} where validation is defined as @var{str} being
+## a member or substring of @var{validstr}.  This is useful for both verifying
+## and expanding short options, such as @qcode{"r"}, to their longer forms, such
+## as @qcode{"red"}.  If @var{str} is a substring of @var{validstr}, and there
+## are multiple matches, the shortest match will be returned if all matches are
+## substrings of each other.  Otherwise, an error will be raised because the
+## expansion of @var{str} is ambiguous.  All comparisons are case insensitive.
 ##
 ## The additional inputs @var{funcname}, @var{varname}, and @var{position}
 ## are optional and will make any generated validation error message more
@@ -69,58 +68,61 @@
     print_usage ();
   endif
 
+  ## Process input arguments
   position = 0;
-  ## Process input arguments
   if (! isempty (varargin) && isnumeric (varargin{end}))
     position = fix (varargin{end});
     varargin(end) = [];
+    if (position < 1)
+      error ("validatestring: POSITION must be >= 1");
+    endif
   endif
 
   funcname = varname = "";
   char_idx = cellfun ("isclass", varargin, "char");
   n_chararg = sum (char_idx);
   if (n_chararg > 2)
-    error ("validatestring: invalid number of character inputs (3)");
+    error ("validatestring: invalid number of character inputs (> 3)");
   elseif (n_chararg == 2)
     [funcname, varname] = deal (varargin{char_idx});
   elseif (n_chararg == 1)
     funcname = varargin{char_idx};
   endif
 
-  ## Check the inputs
-  if (! ischar (str))
-    error ("validatestring: STR must be a character string");
-  elseif (! isrow (str))
-    error ("validatestring: STR must be a single row vector");
+  ## Validate the inputs
+  if (! (ischar (str) && isrow (str)))
+    error ("validatestring: STR must be a single character string");
   elseif (! iscellstr (strarray))
     error ("validatestring: STRARRAY must be a cellstr");
   elseif (! isempty (funcname) && ! isrow (funcname))
-    error ("validatestring: FUNCNAME must be a single row vector");
+    error ("validatestring: FUNCNAME must be a single character string");
   elseif (! isempty (varname) && ! isrow (varname))
-    error ("validatestring: VARNAME must be a single row vector");
-  elseif (position < 0)
-    error ("validatestring: POSITION must be >= 0");
+    error ("validatestring: VARNAME must be a single character string");
   endif
 
   ## Make static part of error string that uses funcname, varname, and position
-  errstr = "";
-  if (! isempty (funcname))
-    errstr = [funcname ": "];
+  if (isempty (funcname))
+    funcname = "validatestring";
   endif
+  errstr = [funcname ": '" str "' "];
   if (! isempty (varname))
-    errstr = [errstr varname " "];
+    if (position > 0)
+      errstr = sprintf ("%s(variable %s, argument #%i) ", ...
+                        errstr, varname, position);
+    else
+      errstr = sprintf ("%s(variable %s) ", errstr, varname);
+    endif
   else
-    errstr = sprintf ("%s'%s' ", errstr, str);
-  endif
-  if (position > 0)
-    errstr = sprintf ("%s(argument #%i) ", errstr, position);
+    if (position > 0)
+      errstr = sprintf ("%s(argument #%i) ", errstr, position);
+    endif
   endif
 
-  matches = strncmpi (str, strarray(:), length (str));
+  matches = strncmpi (str, strarray(:), numel (str));
   nmatches = sum (matches);
   if (nmatches == 0)
-    error ("validatestring: %sdoes not match any of\n%s", errstr,
-           sprintf ("%s, ", strarray{:})(1:end-2));
+    error ("%sdoes not match any of\n%s", errstr,
+           sprintf ("'%s', ", strarray{:})(1:end-2));
   elseif (nmatches == 1)
     str = strarray{matches};
   else
@@ -134,8 +136,8 @@
     if (all (submatch))
       str = short_str;
     else
-      error ("validatestring: %sallows multiple unique matches:\n%s",
-             errstr, sprintf ("%s, ", strarray{match_idx})(1:end-2));
+      error ("%smatches multiple possible values:\n%s", errstr,
+             sprintf ("'%s', ", strarray{match_idx})(1:end-2));
     endif
   endif
 
@@ -151,18 +153,26 @@
 %!assert (validatestring ("d", strarray), "def")
 
 %!error <'xyz' does not match any> validatestring ("xyz", strarray)
-%!error <DUMMY_TEST: 'xyz' does not> validatestring ("xyz", strarray, "DUMMY_TEST")
-%!error <DUMMY_TEST: DUMMY_VAR does> validatestring ("xyz", strarray, "DUMMY_TEST", "DUMMY_VAR")
-%!error <DUMMY_TEST: DUMMY_VAR \(argument #5\) does> validatestring ("xyz", strarray, "DUMMY_TEST", "DUMMY_VAR", 5)
-%!error <'abc' allows multiple unique matches> validatestring ("abc", strarray)
+%!error <DUMMY_TEST: 'xyz' does not match any>
+%! validatestring ("xyz", strarray, "DUMMY_TEST")
+%!error <DUMMY_TEST: 'xyz' \(variable DUMMY_VAR\) does not match>
+%! validatestring ("xyz", strarray, "DUMMY_TEST", "DUMMY_VAR")
+%!error <DUMMY_TEST: 'xyz' \(variable DUMMY_VAR, argument #5\) does>
+%! validatestring ("xyz", strarray, "DUMMY_TEST", "DUMMY_VAR", 5)
+%!error <'abc' matches multiple possible values:> validatestring ("abc", strarray)
 
 ## Test input validation
-%!error validatestring ("xyz")
-%!error validatestring ("xyz", {"xyz"}, "3", "4", 5, 6)
-%!error <invalid number of character inputs> validatestring ("xyz", {"xyz"}, "3", "4", "5")
-%!error <STR must be a character string> validatestring (1, {"xyz"}, "3", "4", 5)
-%!error <STR must be a single row vector> validatestring ("xyz".', {"xyz"}, "3", "4", 5)
+%!error <Invalid call> validatestring ("xyz")
+%!error <Invalid call> validatestring ("xyz", {"xyz"}, "3", "4", 5, 6)
+%!error <POSITION must be .= 1> validatestring ("xyz", {"xyz"}, "3", "4", -5)
+%!error <invalid number of character inputs>
+%! validatestring ("xyz", {"xyz"}, "3", "4", "5")
+%!error <STR must be a single character string>
+%! validatestring (1, {"xyz"}, "3", "4", 5)
+%!error <STR must be a single character string>
+%! validatestring (['xyz';'def'], {"xyz"}, "3", "4", 5)
 %!error <STRARRAY must be a cellstr> validatestring ("xyz", "xyz", "3", "4", 5)
-%!error <FUNCNAME must be a single row vector> validatestring ("xyz", {"xyz"}, "33".', "4", 5)
-%!error <VARNAME must be a single row vector> validatestring ("xyz", {"xyz"}, "3", "44".', 5)
-%!error <POSITION must be> validatestring ("xyz", {"xyz"}, "3", "4", -5)
+%!error <FUNCNAME must be a single character string>
+%! validatestring ("xyz", {"xyz"}, ["3";"3"], "4", 5)
+%!error <VARNAME must be a single character string>
+%! validatestring ("xyz", {"xyz"}, "3", ["4";"4"], 5)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/testfun/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/testfun/__debug_octave__.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/__debug_octave__.m	Sun May 16 09:44:35 2021 +0200
@@ -45,10 +45,6 @@
 
 function __debug_octave__ (command_string)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     if (ismac ())
       status = system ("lldb --version");
--- a/scripts/testfun/assert.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/assert.m	Sun May 16 09:44:35 2021 +0200
@@ -682,8 +682,8 @@
 %! end_try_catch
 
 ## test input validation
-%!error assert ()
-%!error assert (1,2,3,4)
+%!error <Invalid call> assert ()
+%!error <Invalid call> assert (1,2,3,4)
 
 
 ## Convert all error indices into tuple format
--- a/scripts/testfun/demo.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/demo.m	Sun May 16 09:44:35 2021 +0200
@@ -103,7 +103,7 @@
 
 function demo (name, n = 0)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -186,8 +186,7 @@
 %! #-------------------------------------------------
 %! # the figure window shows one cycle of a sine wave
 
-%!error demo ()
-%!error demo (1, 2, 3)
+%!error <Invalid call> demo ()
 %!error <N must be a scalar integer> demo ("demo", {1})
 %!error <N must be a scalar integer> demo ("demo", ones (2,2))
 %!error <N must be a scalar integer> demo ("demo", 1.5)
--- a/scripts/testfun/example.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/example.m	Sun May 16 09:44:35 2021 +0200
@@ -39,13 +39,13 @@
 ## a string @var{s}, with @var{idx} indicating the ending position of the
 ## various examples.
 ##
-## See @code{demo} for a complete explanation.
+## For a complete explanation @pxref{XREFdemo,,@code{demo}}.
 ## @seealso{demo, test}
 ## @end deftypefn
 
 function [ex_code, ex_idx] = example (name, n = 0)
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -119,8 +119,7 @@
 %! assert (idx, [1, 23, 73]);
 
 ## Test input validation
-%!error example ()
-%!error example ("example", 3, 5)
+%!error <Invalid call> example ()
 %!error <N must be a scalar integer> example ("example", {1})
 %!error <N must be a scalar integer> example ("example", ones (2,2))
 %!error <N must be a scalar integer> example ("example", 1.5)
--- a/scripts/testfun/fail.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/fail.m	Sun May 16 09:44:35 2021 +0200
@@ -67,7 +67,7 @@
 
 function retval = fail (code, pattern, warning_pattern)
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -157,6 +157,5 @@
 %!error <warning failure> fail ("warning ('warning failure')", "warning", "success")
 
 ## Test input validation
-%!error fail ()
-%!error fail (1,2,3,4)
+%!error <Invalid call> fail ()
 %!error fail (1, "nowarning", "foo")
--- a/scripts/testfun/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -9,6 +9,7 @@
   %reldir%/private/html_plot_demos_template.html
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/__debug_octave__.m \
   %reldir%/__have_feature__.m \
   %reldir%/__printf_assert__.m \
--- a/scripts/testfun/oruntests.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/oruntests.m	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
   if (nargin == 0)
     dirs = ostrsplit (path (), pathsep ());
     do_class_dirs = true;
-  elseif (nargin == 1)
+  else
     dirs = {canonicalize_file_name(directory)};
     if (isempty (dirs{1}) || ! isfolder (dirs{1}))
       ## Search for directory name in path
@@ -55,8 +55,6 @@
       dirs = {fullname};
     endif
     do_class_dirs = false;
-  else
-    print_usage ();
   endif
 
   for i = 1:numel (dirs)
--- a/scripts/testfun/private/compare_plot_demos.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/private/compare_plot_demos.m	Sun May 16 09:44:35 2021 +0200
@@ -57,7 +57,7 @@
   arg.fcn_file = "dump_plot_demos.m";
   arg.replace_images = false;
 
-  for n = 1:2:numel(varargin)
+  for n = 1:2:numel (varargin)
     if (! ischar (varargin{n}))
       print_usage ();
     else
@@ -68,17 +68,17 @@
   if (ischar (arg.toolkits))
     arg.toolkits = {arg.toolkits};
   elseif (! iscellstr (arg.toolkits))
-    error ('compare_plot_demos: Invalid value for "toolkits"')
+    error ('compare_plot_demos: Invalid value for "toolkits"');
   endif
 
   if (ischar (arg.directories))
     arg.directories = {arg.directories};
   elseif (! iscellstr (arg.directories))
-    error ('compare_plot_demos: Invalid value for "directory"')
+    error ('compare_plot_demos: Invalid value for "directory"');
   endif
 
   if (! ischar (arg.fmt))
-    error ('compare_plot_demos: Invalid value for "fmt"')
+    error ('compare_plot_demos: Invalid value for "fmt"');
   endif
 
   ## Generate arg.fcn_file for rendering/saving the plot demo images
--- a/scripts/testfun/private/dump_demos.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/private/dump_demos.m	Sun May 16 09:44:35 2021 +0200
@@ -57,10 +57,6 @@
 
 function dump_demos (dirs={"plot/appearance", "plot/draw", "plot/util", "image"}, mfile="dump_plot_demos.m", fmt="png")
 
-  if (nargin > 3)
-    print_usage ();
-  endif
-
   if (ischar (dirs))
     dirs = {dirs};
   elseif (! iscellstr (dirs))
--- a/scripts/testfun/private/html_compare_plot_demos.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/private/html_compare_plot_demos.m	Sun May 16 09:44:35 2021 +0200
@@ -70,12 +70,12 @@
   in.plots_per_page = 50;
 
   ## Parse inputs
-  for n = 1:2:numel(varargin)
+  for n = 1:2:numel (varargin)
     in.(lower(varargin{n})) = varargin{n+1};
   endfor
 
   ## Compile a list of all files for all toolkits
-  for t = 1:numel(toolkits)
+  for t = 1:numel (toolkits)
     filter = sprintf ("%s/*.%s", toolkits{t}, in.fmt);
     in.figfiles = union (in.figfiles, {dir(filter).name});
   endfor
@@ -87,7 +87,7 @@
   anchor = "<!-- ##ADD TABLE HERE## -->";
   n = strfind (template, anchor);
   header = strtrim (template(1:n-1));
-  trailer = strtrim (template(n+numel(anchor):end));
+  trailer = strtrim (template(n+numel (anchor):end));
 
   page = 1;
   do
@@ -123,7 +123,7 @@
 
       ## Create table header
       fprintf (fid, "<table>\n<tr>\n");
-      for t = 1:numel(toolkits)
+      for t = 1:numel (toolkits)
         ## set default
         column_header = upper (toolkits{t});
         if (isfield (in, toolkits{t}))
@@ -147,7 +147,7 @@
           else
             err_fn = strrep (ffn, ".png", ".err");
             if (! exist (err_fn, "file"))
-              warning("File %s doesn't exist...", err_fn);
+              warning ("File %s doesn't exist...", err_fn);
             else
               err_fid = fopen (err_fn);
               msg = char (fread (err_fid))';
--- a/scripts/testfun/speed.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/speed.m	Sun May 16 09:44:35 2021 +0200
@@ -159,7 +159,7 @@
 ## FIXME: consider two dimensional speedup surfaces for functions like kron.
 function [__order, __test_n, __tnew, __torig] = speed (__f1, __init, __max_n = 100, __f2 = "", __tol = eps)
 
-  if (nargin < 1 || nargin > 6)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -243,7 +243,7 @@
         __t = min ([__t, __t2, __t3]);
       endif
       __torig(k) = __t;
-      if (! isinf(__tol))
+      if (! isinf (__tol))
         assert (__v1, __v2, __tol);
       endif
     endif
@@ -276,7 +276,7 @@
   endif
 
   if (do_display)
-    figure;
+    figure ();
     ## Strip semicolon added to code fragments before displaying
     __init(end) = "";
     __f1(end) = "";
@@ -403,7 +403,7 @@
 %! fstr_build = cstrcat (
 %!   "function x = build (n)\n",
 %!   "  idx = [1:100]';\n",
-%!   "  x = idx(:,ones(1,n));\n",
+%!   "  x = idx(:,ones (1,n));\n",
 %!   "  x = reshape (x, 1, n*100);\n",
 %!   "endfunction");
 %!
@@ -453,5 +453,4 @@
 %! assert (length (T_f2) > 10);
 
 ## Test input validation
-%!error speed ()
-%!error speed (1, 2, 3, 4, 5, 6, 7)
+%!error <Invalid call> speed ()
--- a/scripts/testfun/test.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/testfun/test.m	Sun May 16 09:44:35 2021 +0200
@@ -115,7 +115,7 @@
 ## any built-in demo blocks are extracted but not executed.  The text for all
 ## code blocks is concatenated and returned as @var{code} with @var{idx} being
 ## a vector of positions of the ends of each demo block.  For an easier way to
-## extract demo blocks from files, @xref{XREFexample,,example}.
+## extract demo blocks from files, @xref{XREFexample,,@code{example}}.
 ##
 ## If the second argument is @qcode{"explain"} then @var{name} is ignored and
 ## an explanation of the line markers used in @code{test} output reports is
@@ -137,7 +137,7 @@
   persistent __signal_file  = ">>>>> ";
   persistent __signal_skip  = "----- ";
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   elseif (! isempty (__name) && ! ischar (__name))
     error ("test: NAME must be a string");
@@ -670,7 +670,7 @@
       endif
 
       ## evaluate code for test, shared, and assert.
-      if (! isempty(__code))
+      if (! isempty (__code))
         try
           eval (sprintf ("function %s__test__(%s)\n%s\nendfunction",
                          __shared_r, __shared, __code));
@@ -727,7 +727,7 @@
             && ! strcmp (__type, "xtest")
             && ! all (__shared == " "))
           fputs (__fid, "shared variables ");
-          eval (sprintf ("fdisp(__fid,var2struct(%s));", __shared));
+          eval (sprintf ("fdisp (__fid,var2struct(%s));", __shared));
         endif
         fflush (__fid);
       endif
@@ -915,7 +915,7 @@
 function msg = trimerr (msg, prefix)
   idx = index (msg, [prefix ":"]);
   if (idx > 0)
-    msg(1:idx+length(prefix)) = [];
+    msg(1:idx+length (prefix)) = [];
   endif
   msg = strtrim (msg);
 endfunction
@@ -950,7 +950,7 @@
 %!fail ("toeplitz ([1,2],[1,2;3,4])", msg2)
 %!fail ("toeplitz ([1,2;3,4],[1,2])", msg2)
 %!test fail ("toeplitz", "Invalid call to toeplitz")
-%!fail ("toeplitz (1, 2, 3)", "Invalid call to toeplitz")
+%!fail ("toeplitz (1, 2, 3)", "called with too many inputs")
 %!test assert (toeplitz ([1,2,3], [1,4]), [1,4; 2,1; 3,2])
 %!assert (toeplitz ([1,2,3], [1,4]), [1,4; 2,1; 3,2])
 %!demo toeplitz ([1,2,3,4],[1,5,6])
@@ -984,15 +984,14 @@
 
 ## Test 'fail' keyword
 %!fail ("test", "Invalid call to test")  # no args, generates usage()
-%!fail ("test (1,2,3,4)", "usage.*test") # too many args, generates usage()
+%!fail ("test (1,2,3,4)", "called with too many inputs") # too many args
 %!fail ('test ("test", "invalid")', "unknown flag")  # incorrect args
 %!fail ('garbage','garbage.*undefined')  # usage on nonexistent function should be
 
 ## Test 'error' keyword
-%!error test              # no args, generates usage()
-%!error test (1,2,3,4)    # too many args, generates usage()
+%!error <Invalid call> test              # no args, generates usage()
 %!error <unknown flag> test ("test", "invalid"); # incorrect args
-%!error test ("test", "invalid");  # test without pattern
+%!error test ("test", "invalid");        # test without pattern
 %!error <'garbage' undefined> garbage; # usage on nonexistent function is error
 
 ## Test 'warning' keyword
@@ -1064,7 +1063,7 @@
 ## Test 'xtest' keyword
 %!xtest
 %! assert (1, 1);      # Test passes
-%!xtest <53613>
+%!test <53613>
 %! assert (0, 1);      # Test fails
 
 ## Test comment block.  It can contain anything.
@@ -1081,15 +1080,15 @@
 ## All of the following tests should fail.  These tests should
 ## be disabled unless you are developing test() since users don't
 ## like to be presented with known failures.
-## %!test   error("---------Failure tests.  Use test('test','verbose',1)");
-## %!test   assert([a,b,c],[1,3,6]);   # variables have wrong values
+## %!test   error ("---------Failure tests.  Use test('test','verbose',1)");
+## %!test   assert ([a,b,c],[1,3,6]);   # variables have wrong values
 ## %!invalid                   # unknown block type
-## %!error  toeplitz([1,2,3]); # correct usage
+## %!error  toeplitz ([1,2,3]); # correct usage
 ## %!test   syntax errors)     # syntax errors fail properly
 ## %!shared garbage in         # variables must be comma separated
 ## %!error  syntax++error      # error test fails on syntax errors
 ## %!error  "succeeds.";       # error test fails if code succeeds
-## %!error <wrong pattern> error("message")  # error pattern must match
+## %!error <wrong pattern> error ("message")  # error pattern must match
 ## %!demo   with syntax error  # syntax errors in demo fail properly
 ## %!shared a,b,c
 ## %!demo                      # shared variables not available in demo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/time/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/time/addtodate.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/addtodate.m	Sun May 16 09:44:35 2021 +0200
@@ -121,10 +121,9 @@
 %!assert (addtodate ([d d+1], 1, "month"), [d+31 d+1+31])
 
 ## Test input validation
-%!error addtodate ()
-%!error addtodate (1)
-%!error addtodate (1,2)
-%!error addtodate (1,2,3,4)
+%!error <Invalid call> addtodate ()
+%!error <Invalid call> addtodate (1)
+%!error <Invalid call> addtodate (1,2)
 %!error <F must be a single character string> addtodate (1,2,3)
 %!error <F must be a single character string> addtodate (1,2,"month"')
 %!error <Invalid time unit> addtodate (1,2,"abc")
--- a/scripts/time/asctime.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/asctime.m	Sun May 16 09:44:35 2021 +0200
@@ -26,14 +26,14 @@
 ## -*- texinfo -*-
 ## @deftypefn {} {} asctime (@var{tm_struct})
 ## Convert a time structure to a string using the following
-## format: @qcode{"ddd mmm mm HH:MM:SS yyyy@xbackslashchar{}n"}.
+## format: @qcode{"ddd mmm mm HH:MM:SS yyyy@backslashchar{}n"}.
 ##
 ## For example:
 ##
 ## @example
 ## @group
 ## asctime (localtime (time ()))
-##      @result{} "Mon Feb 17 01:15:06 1997@xbackslashchar{}n"
+##      @result{} "Mon Feb 17 01:15:06 1997@backslashchar{}n"
 ## @end group
 ## @end example
 ##
@@ -43,7 +43,7 @@
 
 function retval = asctime (tm_struct)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,5 +58,4 @@
 
 %!assert (asctime (localtime (time ()))(end), "\n")
 
-%!error asctime ()
-%!error asctime (1, 2)
+%!error <Invalid call> asctime ()
--- a/scripts/time/clock.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/clock.m	Sun May 16 09:44:35 2021 +0200
@@ -62,6 +62,6 @@
 
 
 %!test
-%! t1 = clock;
+%! t1 = clock ();
 %! t2 = str2num (strftime ("[%Y, %m, %d, %H, %M, %S]", localtime (time ())));
 %! assert (etime (t1, t2) < 1);
--- a/scripts/time/ctime.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/ctime.m	Sun May 16 09:44:35 2021 +0200
@@ -35,7 +35,7 @@
 ## @example
 ## @group
 ## ctime (time ())
-##    @result{} "Mon Feb 17 01:15:06 1997@xbackslashchar{}n"
+##    @result{} "Mon Feb 17 01:15:06 1997@backslashchar{}n"
 ## @end group
 ## @end example
 ## @seealso{asctime, time, localtime}
@@ -43,7 +43,7 @@
 
 function retval = ctime (t)
 
-  if (nargin != 1)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -58,5 +58,4 @@
 
 %!assert (ctime (time ())(end), "\n")
 
-%!error ctime ()
-%!error ctime (1, 2)
+%!error <Invalid call> ctime ()
--- a/scripts/time/date.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/date.m	Sun May 16 09:44:35 2021 +0200
@@ -40,16 +40,9 @@
 
 function retval = date ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   retval = strftime ("%d-%b-%Y", localtime (time ()));
 
 endfunction
 
 
 %!assert (strcmp (date (), strftime ("%d-%b-%Y", localtime (time ()))))
-
-## Test input validation
-%!error date (1)
--- a/scripts/time/datenum.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/datenum.m	Sun May 16 09:44:35 2021 +0200
@@ -42,16 +42,17 @@
 ## The fractional part, @code{rem (@var{days}, 1)} corresponds to the time
 ## on the given day.
 ##
-## The input may be a date vector (see @code{datevec}),
-## datestr (see @code{datestr}), or directly specified as input.
+## The input may be a date vector (@pxref{XREFdatevec,,@code{datevec}}),
+## date string (@pxref{XREFdatestr,,@code{datestr}}), or directly specified
+## as input.
 ##
 ## When processing input datestrings, @var{f} is the format string used to
-## interpret date strings (see @code{datestr}).  If no format @var{f} is
-## specified, then a relatively slow search is performed through various
-## formats.  It is always preferable to specify the format string @var{f} if
-## it is known.  Formats which do not specify a particular time component
-## will have the value set to zero.  Formats which do not specify a date
-## will default to January 1st of the current year.
+## interpret date strings (@pxref{XREFdatestr,,@code{datestr}}).  If no
+## format @var{f} is specified, then a relatively slow search is performed
+## through various formats.  It is always preferable to specify the format
+## string @var{f} if it is known.  Formats which do not specify a particular
+## time component will have the value set to zero.  Formats which do not
+## specify a date will default to January 1st of the current year.
 ##
 ## @var{p} is the year at the start of the century to which two-digit years
 ## will be referenced.  If not specified, it defaults to the current year
@@ -109,8 +110,7 @@
   persistent monthstart = [306; 337; 0; 31; 61; 92; 122; 153; 184; 214; 245; 275];
   persistent monthlength = [31; 28; 31; 30; 31; 30; 31; 31; 30; 31; 30; 31];
 
-  if (nargin == 0 || nargin > 6
-      || (nargin > 2 && (ischar (year) || iscellstr (year))))
+  if (nargin == 0 || (nargin > 2 && (ischar (year) || iscellstr (year))))
     print_usage ();
   endif
 
@@ -251,8 +251,7 @@
 %!assert (datenum ("5-19, 2001", "mm-dd, yyyy"), 730990)
 
 ## Test input validation
-%!error datenum ()
-%!error datenum (1,2,3,4,5,6,7)
+%!error <Invalid call> datenum ()
 %!error <expected date vector containing> datenum ([1, 2])
 %!error <expected date vector containing> datenum ([1,2,3,4,5,6,7])
 %!error <all inputs must be of class double> datenum (int32 (2000), int32 (1), int32 (1))
--- a/scripts/time/datestr.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/datestr.m	Sun May 16 09:44:35 2021 +0200
@@ -30,9 +30,10 @@
 ## Format the given date/time according to the format @var{f} and return
 ## the result in @var{str}.
 ##
-## @var{date} is a serial date number (see @code{datenum}), a date vector (see
-## @code{datevec}), or a string or cell array of strings.  In the latter case,
-## it is passed to @code{datevec} to guess the input date format.
+## @var{date} is a serial date number (@pxref{XREFdatenum,,@code{datenum}}), a
+## date vector (@pxref{XREFdatevec,,@code{datevec}}), or a string or cell array
+## of strings.  In the latter case, it is passed to @code{datevec} to guess the
+## input date format.
 ##
 ## @var{f} can be an integer which corresponds to one of the codes in the table
 ## below, or a date format string.
@@ -175,7 +176,7 @@
     names_d = {"S", "M", "T", "W", "T", "F", "S"};
   endif
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -368,5 +369,4 @@
 %!                 "00:05:00.000")
 
 ## Test input validation
-%!error datestr ()
-%!error datestr (1, 2, 3, 4)
+%!error <Invalid call> datestr ()
--- a/scripts/time/datevec.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/datevec.m	Sun May 16 09:44:35 2021 +0200
@@ -29,19 +29,19 @@
 ## @deftypefnx {} {@var{v} =} datevec (@var{date}, @var{p})
 ## @deftypefnx {} {@var{v} =} datevec (@var{date}, @var{f}, @var{p})
 ## @deftypefnx {} {[@var{y}, @var{m}, @var{d}, @var{h}, @var{mi}, @var{s}] =} datevec (@dots{})
-## Convert a serial date number (see @code{datenum}) or date string (see
-## @code{datestr}) into a date vector.
+## Convert a serial date number (@pxref{XREFdatenum,,@code{datenum}}) or date
+## string (@pxref{XREFdatestr,,@code{datestr}}) into a date vector.
 ##
 ## A date vector is a row vector with six members, representing the year,
 ## month, day, hour, minute, and seconds respectively.
 ##
 ## @var{f} is the format string used to interpret date strings
-## (see @code{datestr}).  If @var{date} is a string, but no format is
-## specified, then a relatively slow search is performed through various
-## formats.  It is always preferable to specify the format string @var{f} if it
-## is known.  Formats which do not specify a particular time component will
-## have the value set to zero.  Formats which do not specify a date will
-## default to January 1st of the current year.
+## (@pxref{XREFdatestr,,@code{datestr}}).  If @var{date} is a string, but no
+## format is specified, then a relatively slow search is performed through
+## various formats.  It is always preferable to specify the format string
+## @var{f} if it is known.  Formats which do not specify a particular time
+## component will have the value set to zero.  Formats which do not specify a
+## date will default to January 1st of the current year.
 ##
 ## @var{p} is the year at the start of the century to which two-digit years
 ## will be referenced.  If not specified, it defaults to the current year minus
@@ -94,7 +94,7 @@
     std_formats{++nfmt} = "mm/dd/yyyy HH:MM";
   endif
 
-  if (nargin < 1 || nargin > 3)
+  if (nargin < 1)
     print_usage ();
   endif
 
@@ -423,7 +423,6 @@
 %! end_unwind_protect
 
 ## Test input validation
-%!error datevec ()
-%!error datevec (1,2,3,4)
+%!error <Invalid call> datevec ()
 %!error <none of the standard formats match> datevec ("foobar")
 %!error <DATE not parsed correctly with given format> datevec ("foobar", "%d")
--- a/scripts/time/eomday.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/eomday.m	Sun May 16 09:44:35 2021 +0200
@@ -61,6 +61,5 @@
 %!assert (eomday ([2004;2005], [2;2]), [29;28])
 
 ## Test input validation
-%!error eomday ()
-%!error eomday (1)
-%!error eomday (1,2,3)
+%!error <Invalid call> eomday ()
+%!error <Invalid call> eomday (1)
--- a/scripts/time/etime.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/etime.m	Sun May 16 09:44:35 2021 +0200
@@ -80,6 +80,5 @@
 %! assert (etime (t5, t1), 13);
 
 ## Test input validation
-%!error etime ()
-%!error etime (1)
-%!error etime (1, 2, 3)
+%!error <Invalid call> etime ()
+%!error <Invalid call> etime (1)
--- a/scripts/time/is_leap_year.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/is_leap_year.m	Sun May 16 09:44:35 2021 +0200
@@ -43,10 +43,6 @@
 
 function retval = is_leap_year (year)
 
-  if (nargin > 1)
-    print_usage ();
-  endif
-
   if (nargin == 0)
     t = clock ();
     year = t(1);
@@ -63,4 +59,3 @@
 %!assert (is_leap_year (1800), false)
 %!assert (is_leap_year (1600), true)
 
-%!error is_leap_year (1, 2)
--- a/scripts/time/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/addtodate.m \
   %reldir%/asctime.m \
   %reldir%/calendar.m \
--- a/scripts/time/now.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/now.m	Sun May 16 09:44:35 2021 +0200
@@ -26,7 +26,7 @@
 ## -*- texinfo -*-
 ## @deftypefn {} {t =} now ()
 ## Return the current local date/time as a serial day number
-## (see @code{datenum}).
+## (@pxref{XREFdatenum,,@code{datenum}}).
 ##
 ## The integral part, @code{floor (now)} corresponds to the number of days
 ## between today and Jan 1, 0000.
@@ -37,10 +37,6 @@
 
 function t = now ()
 
-  if (nargin != 0)
-    print_usage ();
-  endif
-
   t = datenum (clock ());
 
   ## The following doesn't work (e.g., one hour off on 2005-10-04):
@@ -59,5 +55,3 @@
 %!assert (isnumeric (now ()))
 %!assert (now () > 0)
 %!assert (now () <= now ())
-
-%!error now (1)
--- a/scripts/time/weekday.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/time/weekday.m	Sun May 16 09:44:35 2021 +0200
@@ -55,7 +55,7 @@
 
 function [d, s] = weekday (d, format = "short")
 
-  if (nargin < 1 || nargin > 2)
+  if (nargin < 1)
     print_usage ();
   endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/web/.oct-config	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,1 @@
+encoding=utf-8
--- a/scripts/web/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/web/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,7 @@
 FCN_FILE_DIRS += %reldir%
 
 %canon_reldir%_FCN_FILES = \
+  %reldir%/.oct-config \
   %reldir%/web.m \
   %reldir%/weboptions.m \
   %reldir%/webread.m \
--- a/scripts/web/weboptions.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/web/weboptions.m	Sun May 16 09:44:35 2021 +0200
@@ -160,6 +160,7 @@
   endproperties
 
   methods
+
     function f = weboptions (varargin)
       if (rem (numel (varargin), 2) != 0)
         error ("weboptions: invalid number of arguments");
@@ -244,6 +245,7 @@
           error (["weboptions: Undefined field " field]);
         endif
       endif
+
     endfunction
 
     function f = set.CharacterEncoding (f, value)
@@ -264,7 +266,7 @@
 
     function f = set.Timeout (f, value)
       if (! isreal (value) || ! isscalar (value)
-          || floor(value) != value || value < 0)
+          || floor (value) != value || value < 0)
         error ("weboptions: invalid Timeout value");
       else
         f.Timeout = value;
@@ -355,6 +357,7 @@
     endfunction
 
     function display (f)
+
       Timeout = int2str (f.Timeout);
       Password = repmat ("*", 1, numel (num2str (f.Password)));
 
@@ -393,6 +396,7 @@
                 "\n           HeaderFields: " , HeaderFields,...
                 "\n    CertificateFilename: '", f.CertificateFilename, "'\n"];
       disp (output);
+
     endfunction
 
   endmethods
--- a/scripts/web/webread.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/web/webread.m	Sun May 16 09:44:35 2021 +0200
@@ -48,7 +48,7 @@
 function response = webread (url, varargin)
 
   if (nargin == 0)
-    print_usage();
+    print_usage ();
   endif
 
   if (! (ischar (url) && isrow (url)))
@@ -105,7 +105,7 @@
 
 
 ## Test input validation
-%!error webread ()
+%!error <Invalid call> webread ()
 %!error <URL must be a string> webread (1)
 %!error <URL must be a string> webread (["a";"b"])
 %!error <KEYS and VALUES must be strings> webread ("URL", "NAME1", 5)
--- a/scripts/web/webwrite.m	Sun May 16 09:43:43 2021 +0200
+++ b/scripts/web/webwrite.m	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 function response = webwrite (url, varargin)
 
   if (nargin < 2)
-    print_usage();
+    print_usage ();
   endif
 
   if (! (ischar (url) && isrow (url)))
@@ -94,7 +94,7 @@
     if (ischar (varargin{1}) && isrow (varargin{1}))
       param = strsplit (varargin{1}, {"=", "&"});
       response = __restful_service__ (url, param, options);
-    elseif  (! iscellstr (varargin))
+    elseif (! iscellstr (varargin))
       error ("webwrite: DATA must be a string");
     else
       response = __restful_service__ (url, varargin, options);
@@ -113,8 +113,8 @@
 
 
 ## Test input validation
-%!error webwrite ()
-%!error webwrite ("abc")
+%!error <Invalid call> webwrite ()
+%!error <Invalid call> webwrite ("abc")
 %!error <URL must be a string> webwrite (1, "NAME1", "VALUE1")
 %!error <URL must be a string> webwrite (["a";"b"], "NAME1", "VALUE1")
 %!error <DATA must be a string> webwrite ("URL", 1, weboptions ())
--- a/src/main-cli.cc	Sun May 16 09:43:43 2021 +0200
+++ b/src/main-cli.cc	Sun May 16 09:44:35 2021 +0200
@@ -32,6 +32,12 @@
 #include <iostream>
 #include <string>
 
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+#  include <vector>
+#  include <locale>
+#  include <codecvt>
+#endif
+
 #include "liboctave-build-info.h"
 
 #include "liboctinterp-build-info.h"
@@ -81,9 +87,28 @@
     exit (1);
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+extern "C"
+int
+wmain (int argc, wchar_t **wargv)
+{
+  static char **argv = new char * [argc + 1];
+  std::vector<std::string> argv_str;
+
+  // convert wide character strings to multibyte UTF-8 strings
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
+  for (int i_arg = 0; i_arg < argc; i_arg++)
+    {
+      argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg]));
+      argv[i_arg] = &argv_str[i_arg][0];
+    }
+  argv[argc] = nullptr;
+
+#else
 int
 main (int argc, char **argv)
 {
+#endif
   check_hg_versions ();
 
   octave_block_async_signals ();
--- a/src/main-gui.cc	Sun May 16 09:43:43 2021 +0200
+++ b/src/main-gui.cc	Sun May 16 09:44:35 2021 +0200
@@ -32,6 +32,12 @@
 #include <iostream>
 #include <string>
 
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+#  include <vector>
+#  include <locale>
+#  include <codecvt>
+#endif
+
 #include "liboctave-build-info.h"
 
 #include "liboctinterp-build-info.h"
@@ -94,9 +100,28 @@
     exit (1);
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+extern "C"
+int
+wmain (int argc, wchar_t **wargv)
+{
+  static char **argv = new char * [argc + 1];
+  std::vector<std::string> argv_str;
+
+  // convert wide character strings to multibyte UTF-8 strings
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
+  for (int i_arg = 0; i_arg < argc; i_arg++)
+    {
+      argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg]));
+      argv[i_arg] = &argv_str[i_arg][0];
+    }
+  argv[argc] = nullptr;
+
+#else
 int
 main (int argc, char **argv)
 {
+#endif
   check_hg_versions ();
 
   octave::sys::env::set_program_name (argv[0]);
--- a/src/main.in.cc	Sun May 16 09:43:43 2021 +0200
+++ b/src/main.in.cc	Sun May 16 09:44:35 2021 +0200
@@ -43,6 +43,16 @@
 #include <iostream>
 #include <string>
 
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+#  include <vector>
+#  include <locale>
+#  include <codecvt>
+#endif
+
+// We are linking against static libs so do not decorate with dllimport.
+// FIXME: This should be done by the build system.
+#undef OCTAVE_API
+#define OCTAVE_API
 #include "fcntl-wrappers.h"
 #include "signal-wrappers.h"
 #include "unistd-wrappers.h"
@@ -72,8 +82,13 @@
 #include "shared-fcns.h"
 
 #if defined (HAVE_OCTAVE_QT_GUI) && ! defined (OCTAVE_USE_WINDOWS_API)
+static bool fork_and_exec = true;
+#else
+static bool fork_and_exec = false;
+#endif
 
-// Forward signals to the GUI process.
+// If we fork and exec, we'll need the following signal handling code to
+// forward signals to the GUI process.
 
 static pid_t gui_pid = 0;
 
@@ -151,8 +166,6 @@
   gui_driver_set_signal_handler ("SIGXFSZ", gui_driver_sig_handler);
 }
 
-#endif
-
 static std::string
 get_octave_bindir (void)
 {
@@ -203,12 +216,32 @@
   return tmp;
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+extern "C"
+int
+wmain (int argc, wchar_t **wargv)
+{
+  static char **argv = new char * [argc + 1];
+  std::vector<std::string> argv_str;
+
+  // convert wide character strings to multibyte UTF-8 strings
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
+  for (int i_arg = 0; i_arg < argc; i_arg++)
+    {
+      argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg]));
+      argv[i_arg] = &argv_str[i_arg][0];
+    }
+  argv[argc] = nullptr;
+
+#else
 int
 main (int argc, char **argv)
 {
+#endif
   int retval = 0;
 
   int idx_gui = -1;
+  bool server = false;
   bool start_gui = false;
   bool gui_libs = true;
 
@@ -277,6 +310,13 @@
           start_gui = true;
           idx_gui = i;
         }
+      else if (! strcmp (argv[i], "--experimental-terminal-widget"))
+        {
+          // If we see this option, then we don't fork and exec.
+
+          fork_and_exec = false;
+          new_argv[k++] = argv[i];
+        }
       else if (! strcmp (argv[i], "--persist"))
         {
           // FIXME: How can we reliably detect if this option appears
@@ -287,6 +327,11 @@
           persist_octave = true;
           new_argv[k++] = argv[i];
         }
+      else if (! strcmp (argv[i], "--server"))
+        {
+          server = true;
+          new_argv[k++] = argv[i];
+        }
       else if (! strcmp (argv[i], "--eval") ||
                (strlen (argv[i]) > 0 && argv[i][0] != '-'))
         {
@@ -346,6 +391,13 @@
           return 1;
         }
 
+      if (server)
+        {
+          std::cerr << "octave: conflicting options: --server and --gui"
+                    << std::endl;
+          return 1;
+        }
+
 #if ! defined (HAVE_OCTAVE_QT_GUI)
       std::cerr << "octave: GUI features missing or disabled in this build"
                 << std::endl;
@@ -411,9 +463,7 @@
   octave_block_async_signals ();
   octave_block_signal_by_name ("SIGTSTP");
 
-#if defined (HAVE_OCTAVE_QT_GUI) && ! defined (OCTAVE_USE_WINDOWS_API)
-
-  if (gui_libs && start_gui)
+  if (fork_and_exec && gui_libs && start_gui)
     {
       // Fork and exec when starting the GUI so that we will call
       // setsid to give up the controlling terminal (if any) and so that
@@ -491,14 +541,6 @@
         std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
     }
 
-#else
-
-  retval = octave_exec (file, new_argv);
-
-  if (retval < 0)
-    std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
-
-#endif
 
   return retval;
 }
--- a/src/mkoctfile.in.cc	Sun May 16 09:43:43 2021 +0200
+++ b/src/mkoctfile.in.cc	Sun May 16 09:44:35 2021 +0200
@@ -40,6 +40,11 @@
 #include <vector>
 #include <cstdlib>
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <locale>
+#  include <codecvt>
+#endif
+
 // Programming note:  The CROSS macro here refers to building a
 // cross-compiler aware version of mkoctfile that can be used to cross
 // compile .oct file for Windows builds of Octave, not that mkoctfile
@@ -60,14 +65,16 @@
 #    define OCTAVE_UNUSED
 #  endif
 #else
+// We are linking against static libs so do not decorate with dllimport.
+// FIXME: This should be done by the build system.
+#  undef OCTAVE_API
+#  define OCTAVE_API
 #  include "mkostemps-wrapper.h"
 #  include "uniconv-wrappers.h"
 #  include "unistd-wrappers.h"
 #  include "wait-wrappers.h"
 #endif
 
-static std::map<std::string, std::string> vars;
-
 #if ! defined (OCTAVE_VERSION)
 #  define OCTAVE_VERSION %OCTAVE_CONF_VERSION%
 #endif
@@ -90,14 +97,6 @@
   return mkostemps (tmpl, suffixlen, 0);
 }
 
-static char *
-octave_u8_conv_to_encoding (const char *tocode, const uint8_t *src,
-                            std::size_t srclen, std::size_t *lengthp)
-{
-  // FIXME: Do we need to provide the conversion here?
-  return nullptr;
-}
-
 static int
 octave_unlink_wrapper (const char *nm)
 {
@@ -161,10 +160,11 @@
 {
 #if defined (OCTAVE_REPLACE_PREFIX)
   const std::string match = "${prefix}";
+  const std::string repl = prepend_octave_exec_home ("");
   std::size_t pos = s.find (match);
   while (pos != std::string::npos )
     {
-      s.replace(pos, match.length (), prepend_octave_exec_home (""));
+      s.replace(pos, match.length (), repl);
       pos = s.find (match);
     }
 #endif
@@ -172,11 +172,13 @@
   return s;
 }
 
-static void
-initialize (void)
+static std::map<std::string, std::string>
+make_vars_map (bool link_stand_alone, bool verbose, bool debug)
 {
   set_octave_home ();
 
+  std::map<std::string, std::string> vars;
+
   vars["OCTAVE_HOME"] = Voctave_home;
   vars["OCTAVE_EXEC_HOME"] = Voctave_exec_home;
 
@@ -229,14 +231,14 @@
     = get_variable ("OCTLIBDIR",
                     prepend_octave_exec_home (%OCTAVE_CONF_OCTLIBDIR%));
 
+  std::string DEFAULT_INCFLAGS;
+
 #if defined (OCTAVE_USE_WINDOWS_API)
-  std::string DEFAULT_INCFLAGS
-    = "-I" + quote_path (vars["OCTINCLUDEDIR"] + R"(\..)")
-      + " -I" + quote_path (vars["OCTINCLUDEDIR"]);
+  DEFAULT_INCFLAGS = "-I" + quote_path (vars["OCTINCLUDEDIR"] + R"(\..)")
+                     + " -I" + quote_path (vars["OCTINCLUDEDIR"]);
 #else
-  std::string DEFAULT_INCFLAGS
-    = "-I" + quote_path (vars["OCTINCLUDEDIR"] + "/..")
-      + " -I" + quote_path (vars["OCTINCLUDEDIR"]);
+  DEFAULT_INCFLAGS = "-I" + quote_path (vars["OCTINCLUDEDIR"] + "/..")
+                     + " -I" + quote_path (vars["OCTINCLUDEDIR"]);
 #endif
 
   if (vars["INCLUDEDIR"] != "/usr/include")
@@ -244,8 +246,7 @@
 
   std::string DEFAULT_LDFLAGS;
 
-#if (defined (OCTAVE_USE_WINDOWS_API) || defined (CROSS)) || (defined __APPLE__ && defined __MACH__)
-
+#if (defined (OCTAVE_USE_WINDOWS_API) || defined (CROSS) || defined (OCTAVE_LINK_ALL_DEPS))
   // We'll be linking the files we compile with -loctinterp and -loctave,
   // so we need to know where to find them.
   DEFAULT_LDFLAGS += "-L" + quote_path (vars["OCTLIBDIR"]);
@@ -266,16 +267,22 @@
   vars["FPICFLAG"] = get_variable ("FPICFLAG", %OCTAVE_CONF_FPICFLAG%);
 
   vars["CC"] = get_variable ("CC", %OCTAVE_CONF_MKOCTFILE_CC%);
+  if (verbose && vars["CC"] == "cc-msvc")
+    vars["CC"] += " -d";
 
   vars["CFLAGS"] = get_variable ("CFLAGS", %OCTAVE_CONF_CFLAGS%);
 
   vars["CPICFLAG"] = get_variable ("CPICFLAG", %OCTAVE_CONF_CPICFLAG%);
 
   vars["CXX"] = get_variable ("CXX", %OCTAVE_CONF_MKOCTFILE_CXX%);
+  if (verbose && vars["CXX"] == "cc-msvc")
+    vars["CXX"] += " -d";
 
   vars["CXXFLAGS"] = get_variable ("CXXFLAGS", %OCTAVE_CONF_CXXFLAGS%);
 
   vars["CXXLD"] = get_variable ("CXXLD", vars["CXX"]);
+  if (verbose && vars["CXXLD"] == "cc-msvc")
+    vars["CXXLD"] += " -d";
 
   vars["CXXPICFLAG"] = get_variable ("CXXPICFLAG", %OCTAVE_CONF_CXXPICFLAG%);
 
@@ -298,6 +305,9 @@
   vars["DL_LDFLAGS"] = get_variable ("DL_LDFLAGS",
                                      %OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%);
 
+  if (! link_stand_alone)
+    DEFAULT_LDFLAGS += ' ' + vars["DL_LDFLAGS"];
+
   vars["RDYNAMIC_FLAG"] = get_variable ("RDYNAMIC_FLAG",
                                         %OCTAVE_CONF_RDYNAMIC_FLAG%);
 
@@ -341,8 +351,7 @@
     = get_variable ("OCT_LINK_OPTS",
                     replace_prefix (%OCTAVE_CONF_OCT_LINK_OPTS%));
 
-  vars["LDFLAGS"] = get_variable ("LDFLAGS",
-                                  replace_prefix (%OCTAVE_CONF_LDFLAGS%));
+  vars["LDFLAGS"] = get_variable ("LDFLAGS", DEFAULT_LDFLAGS);
 
   vars["LD_STATIC_FLAG"] = get_variable ("LD_STATIC_FLAG",
                                          %OCTAVE_CONF_LD_STATIC_FLAG%);
@@ -350,17 +359,23 @@
   // FIXME: Remove LFLAGS in Octave 8.0
   vars["LFLAGS"] = get_variable ("LFLAGS", DEFAULT_LDFLAGS);
   if (vars["LFLAGS"] != DEFAULT_LDFLAGS)
-    std::cerr << "warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
+    std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
 
   vars["F77_INTEGER8_FLAG"] = get_variable ("F77_INTEGER8_FLAG",
                                             %OCTAVE_CONF_F77_INTEGER_8_FLAG%);
   vars["ALL_FFLAGS"] = vars["FFLAGS"] + ' ' + vars["F77_INTEGER8_FLAG"];
+  if (debug)
+    vars["ALL_FFLAGS"] += " -g";
 
   vars["ALL_CFLAGS"]
     = vars["INCFLAGS"] + ' ' + vars["XTRA_CFLAGS"] + ' ' + vars["CFLAGS"];
+  if (debug)
+    vars["ALL_CFLAGS"] += " -g";
 
   vars["ALL_CXXFLAGS"]
     = vars["INCFLAGS"] + ' ' + vars["XTRA_CXXFLAGS"] + ' ' + vars["CXXFLAGS"];
+  if (debug)
+    vars["ALL_CXXFLAGS"] += " -g";
 
   vars["ALL_LDFLAGS"]
     = vars["LD_STATIC_FLAG"] + ' ' + vars["CPICFLAG"] + ' ' + vars["LDFLAGS"];
@@ -371,14 +386,14 @@
 
   vars["FFTW_LIBS"] = vars["FFTW3_LDFLAGS"] + ' ' + vars["FFTW3_LIBS"] + ' '
                       + vars["FFTW3F_LDFLAGS"] + ' ' + vars["FFTW3F_LIBS"];
+
+  return vars;
 }
 
 static std::string usage_msg = "usage: mkoctfile [options] file ...";
 
 static std::string version_msg = "mkoctfile, version " OCTAVE_VERSION;
 
-static bool debug = false;
-
 static std::string help_msg =
   "\n"
   "Options:\n"
@@ -566,7 +581,7 @@
 }
 
 static int
-run_command (const std::string& cmd, bool printonly = false)
+run_command (const std::string& cmd, bool verbose, bool printonly = false)
 {
   if (printonly)
     {
@@ -574,9 +589,10 @@
       return 0;
     }
 
-  if (debug)
+  if (verbose)
     std::cout << cmd << std::endl;
 
+  // FIXME: Call _wsystem on Windows or octave::sys::system.
   int result = system (cmd.c_str ());
 
   if (octave_wifexited_wrapper (result))
@@ -632,6 +648,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";
@@ -658,11 +700,28 @@
     octave_unlink_wrapper (file.c_str ());
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+extern "C"
+int
+wmain (int argc, wchar_t **wargv)
+{
+  static char **argv = new char * [argc + 1];
+  std::vector<std::string> argv_str;
+
+  // convert wide character strings to multibyte UTF-8 strings
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
+  for (int i_arg = 0; i_arg < argc; i_arg++)
+    {
+      argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg]));
+      argv[i_arg] = &argv_str[i_arg][0];
+    }
+  argv[argc] = nullptr;
+
+#else
 int
 main (int argc, char **argv)
 {
-  initialize ();
-
+#endif
   if (argc == 1)
     {
       std::cout << usage_msg << std::endl;
@@ -681,6 +740,9 @@
   std::string output_ext = ".oct";
   std::string objfiles, libfiles, octfile, outputfile;
   std::string incflags, defs, ldflags, pass_on_options;
+  std::string var_to_print;
+  bool debug = false;
+  bool verbose = false;
   bool strip = false;
   bool no_oct_file_strip_on_this_platform = is_true ("%NO_OCT_FILE_STRIP%");
   bool compile_only = false;
@@ -688,6 +750,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++)
     {
@@ -727,13 +794,7 @@
       else if (arg == "-d" || arg == "-debug" || arg == "--debug"
                || arg == "-v" || arg == "-verbose" ||  arg == "--verbose")
         {
-          debug = true;
-          if (vars["CC"] == "cc-msvc")
-            vars["CC"] += " -d";
-          if (vars["CXX"] == "cc-msvc")
-            vars["CXX"] += " -d";
-          if (vars["CXXLD"] == "cc-msvc")
-            vars["CXXLD"] += " -d";
+          verbose = true;
         }
       else if (arg == "-silent" ||  arg == "--silent")
         {
@@ -766,7 +827,28 @@
         }
       else if (arg == "-largeArrayDims" || arg == "-compatibleArrayDims")
         {
-          std::cerr << "warning: -largeArrayDims and -compatibleArrayDims are accepted for compatibility, but ignored" << std::endl;
+          std::cerr << "mkoctfile: warning: -largeArrayDims and -compatibleArrayDims are accepted for compatibility, but ignored" << std::endl;
+        }
+      else if (arg == "-R2017b")
+        {
+          if (r2018a_option)
+            {
+              std::cerr << "mkoctfile: only one of -R2017b and -R2018a may be used" << std::endl;
+              return 1;
+            }
+
+          r2017b_option = true;
+        }
+      else if (arg == "-R2018a")
+        {
+          if (r2017b_option)
+            {
+              std::cerr << "mkoctfile: only one of -R2017b and -R2018a may be used" << std::endl;
+              return 1;
+            }
+
+          r2018a_option = true;
+          mx_has_interleaved_complex = true;
         }
       else if (starts_with (arg, "-Wl,") || starts_with (arg, "-l")
                || starts_with (arg, "-L") || starts_with (arg, "-R"))
@@ -803,13 +885,17 @@
         {
           if (i < argc-1)
             {
-              arg = argv[++i];
+              ++i;
+
               // FIXME: Remove LFLAGS checking in Octave 7.0
-              if (arg == "LFLAGS")
-                std::cerr << "warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
+              if (! strcmp (argv[i], "LFLAGS"))
+                std::cerr << "mkoctfile: warning: LFLAGS is deprecated and will be removed in a future version of Octave, use LDFLAGS instead" << std::endl;
 
-              std::cout << vars[arg] << std::endl;
-              return 0;
+              if (! var_to_print.empty ())
+                std::cerr << "mkoctfile: warning: only one '" << arg
+                          << "' option will be processed" << std::endl;
+              else
+                var_to_print = argv[i];
             }
           else
             std::cerr << "mkoctfile: --print requires argument" << std::endl;
@@ -828,9 +914,7 @@
         }
       else if (arg == "-g")
         {
-          vars["ALL_CFLAGS"] += " -g";
-          vars["ALL_CXXFLAGS"] += " -g";
-          vars["ALL_FFLAGS"] += " -g";
+          debug = true;
         }
       else if (arg == "-link-stand-alone" || arg == "--link-stand-alone")
         {
@@ -838,6 +922,8 @@
         }
       else if (arg == "-mex" || arg == "--mex")
         {
+          creating_mex_file = true;
+
           incflags += " -I.";
 #if defined (_MSC_VER)
           ldflags += " -Wl,-export:mexFunction";
@@ -878,10 +964,54 @@
         octfile = file;
     }
 
-  if (output_ext ==  ".mex"
-      && vars["ALL_CFLAGS"].find ("-g") != std::string::npos)
+  std::map<std::string, std::string> vars
+    = make_vars_map (link_stand_alone, verbose, debug);
+
+  if (! var_to_print.empty ())
+    {
+      if (vars.find (var_to_print) == vars.end ())
+        {
+          std::cerr << "mkoctfile: unknown variable '" << var_to_print << "'"
+                    << std::endl;
+          return 1;
+        }
+
+      std::cout << vars[var_to_print] << std::endl;
+
+      return 0;
+    }
+
+  if (creating_mex_file)
     {
-      defs += " -DMEX_DEBUG";
+      if (vars["ALL_CFLAGS"].find ("-g") != std::string::npos)
+        defs += " -DMEX_DEBUG";
+
+      if (mx_has_interleaved_complex)
+        {
+          defs += " -DMX_HAS_INTERLEAVED_COMPLEX=1";
+
+          if (! compile_only)
+            {
+              // Create tmp C source file that defines an extern symbol
+              // that can be checked when loading the mex file to
+              // determine that the file was compiled expecting
+              // interleaved complex values.
+
+              std::string tmp_file = create_interleaved_complex_file ();
+
+              cfiles.push_back (tmp_file);
+            }
+        }
+    }
+  else
+    {
+      if (r2017b_option)
+        std::cerr << "mkoctfile: warning: -R2017b option ignored unless creating mex file"
+                  << std::endl;
+
+      if (r2018a_option)
+        std::cerr << "mkoctfile: warning: -R2018a option ignored unless creating mex file"
+                  << std::endl;
     }
 
   if (compile_only && output_file_option
@@ -919,6 +1049,10 @@
 
   if (depend)
     {
+#if defined (OCTAVE_USE_WINDOWS_API) && ! defined (_UNICODE)
+      std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
+#endif
+
       for (const auto& f : cfiles)
         {
           std::string dfile = basename (f, true) + ".d", line;
@@ -930,33 +1064,34 @@
                + vars["CPPFLAGS"] + ' ' + vars["ALL_CFLAGS"] + ' '
                + incflags  + ' ' + defs + ' ' + quote_path (f));
 
-          // FIXME: Use wide character API for popen on Windows.
+#if defined (OCTAVE_USE_WINDOWS_API)
+          FILE *fd;
+          try
+            {
+              std::wstring wcmd = wchar_conv.from_bytes (cmd);
+              fd = ::_wpopen (wcmd.c_str (), L"r");
+            }
+          catch (const std::range_error& e)
+            {
+              fd = ::popen (cmd.c_str (), "r");
+            }
+
+          std::ofstream fo;
+          try
+            {
+              std::wstring wfile = wchar_conv.from_bytes (dfile);
+              fo.open (wfile.c_str ());
+            }
+          catch (const std::range_error& e)
+            {
+              fo.open (dfile.c_str ());
+            }
+#else
           FILE *fd = popen (cmd.c_str (), "r");
 
-#if defined (OCTAVE_USE_WINDOWS_API)
-          // FIXME: liboctinterp isn't linked in to mkoctfile.
-          // So we cannot use octave::sys::ofstream. Instead we fall back
-          // on using the functions available from libwrappers.
-          std::size_t srclen = dfile.length ();
-          const uint8_t *src = reinterpret_cast<const uint8_t *>
-                               (dfile.c_str ());
-
-          std::size_t length = 0;
-          wchar_t *wchar = reinterpret_cast<wchar_t *>
-                           (octave_u8_conv_to_encoding ("wchar_t", src, srclen,
-                                                        &length));
-
-          std::ofstream fo;
-          if (wchar != nullptr)
-            {
-              fo.open (wchar);
-              free (static_cast<void *> (wchar));
-            }
-          else
-            fo.open (dfile.c_str ());
-#else
           std::ofstream fo (dfile.c_str ());
 #endif
+
           std::size_t pos;
           while (! feof (fd))
             {
@@ -989,33 +1124,34 @@
                + vars["CPPFLAGS"] + ' ' + vars["ALL_CXXFLAGS"] + ' '
                + incflags  + ' ' + defs + ' ' + quote_path (f));
 
-          // FIXME: Use wide character API for popen on Windows.
+#if defined (OCTAVE_USE_WINDOWS_API)
+          FILE *fd;
+          try
+            {
+              std::wstring wcmd = wchar_conv.from_bytes (cmd);
+              fd = ::_wpopen (wcmd.c_str (), L"r");
+            }
+          catch (const std::range_error& e)
+            {
+              fd = ::popen (cmd.c_str (), "r");
+            }
+
+          std::ofstream fo;
+          try
+            {
+              std::wstring wfile = wchar_conv.from_bytes (dfile);
+              fo.open (wfile.c_str ());
+            }
+          catch (const std::range_error& e)
+            {
+              fo.open (dfile.c_str ());
+            }
+#else
           FILE *fd = popen (cmd.c_str (), "r");
 
-#if defined (OCTAVE_USE_WINDOWS_API)
-          // FIXME: liboctinterp isn't linked in to mkoctfile.
-          // So we cannot use octave::sys::ofstream. Instead we fall back
-          // on using the functions available from libwrappers.
-          std::size_t srclen = dfile.length ();
-          const uint8_t *src = reinterpret_cast<const uint8_t *>
-                               (dfile.c_str ());
-
-          std::size_t length = 0;
-          wchar_t *wchar = reinterpret_cast<wchar_t *>
-                           (octave_u8_conv_to_encoding ("wchar_t", src, srclen,
-                                                        &length));
-
-          std::ofstream fo;
-          if (wchar != nullptr)
-            {
-              fo.open (wchar);
-              free (static_cast<void *> (wchar));
-            }
-          else
-            fo.open (dfile.c_str ());
-#else
           std::ofstream fo (dfile.c_str ());
 #endif
+
           std::size_t pos;
           while (! feof (fd))
             {
@@ -1066,7 +1202,7 @@
                + vars["ALL_FFLAGS"] + ' ' + incflags + ' ' + defs + ' '
                + pass_on_options + ' ' + f + " -o " + o);
 
-          int status = run_command (cmd, printonly);
+          int status = run_command (cmd, verbose, printonly);
 
           if (status)
             return status;
@@ -1106,7 +1242,7 @@
                + pass_on_options + ' ' + incflags + ' ' + defs + ' '
                + quote_path (f) + " -o " + quote_path (o));
 
-          int status = run_command (cmd, printonly);
+          int status = run_command (cmd, verbose, printonly);
 
           if (status)
             return status;
@@ -1146,7 +1282,7 @@
                + pass_on_options + ' ' + incflags + ' ' + defs + ' '
                + quote_path (f) + " -o " + quote_path (o));
 
-          int status = run_command (cmd, printonly);
+          int status = run_command (cmd, verbose, printonly);
 
           if (status)
             return status;
@@ -1187,7 +1323,7 @@
                + vars["LFLAGS"] + ' ' + octave_libs + ' '
                + vars["OCTAVE_LINK_OPTS"] + ' ' + vars["OCTAVE_LINK_DEPS"]);
 
-          int status = run_command (cmd, printonly);
+          int status = run_command (cmd, verbose, printonly);
 
           clean_up_tmp_files (tmp_objfiles);
 
@@ -1221,7 +1357,7 @@
         cmd += ' ' + vars["FLIBS"];
 #endif
 
-      int status = run_command (cmd, printonly);
+      int status = run_command (cmd, verbose, printonly);
 
       clean_up_tmp_files (tmp_objfiles);
 
@@ -1233,7 +1369,7 @@
     {
       std::string cmd = "strip " + octfile;
 
-      int status = run_command (cmd, printonly);
+      int status = run_command (cmd, verbose, printonly);
 
       if (status)
         return status;
--- a/src/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/src/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -38,6 +38,7 @@
 
 noinst_HEADERS += \
   %reldir%/display-available.h \
+  %reldir%/octave-qsvghandler.h \
   %reldir%/shared-fcns.h
 
 OCTAVE_VERSION_LINKS += %reldir%/octave-cli-$(version)$(EXEEXT)
@@ -73,7 +74,8 @@
 %canon_reldir%_octave_LDFLAGS = \
   $(NO_UNDEFINED_LDFLAG) \
   $(OCTAVE_LINK_OPTS) \
-  $(WARN_LDFLAGS)
+  $(WARN_LDFLAGS) \
+  $(OCTAVE_UNICODE_EXE_LDFLAGS)
 
 if AMCOND_BUILD_QT_GUI
   OCTAVE_CPPFLAGS = -DHAVE_OCTAVE_QT_GUI
@@ -93,7 +95,8 @@
 %canon_reldir%_octave_cli_LDFLAGS = \
   $(NO_UNDEFINED_LDFLAG) \
   $(OCTAVE_LINK_OPTS) \
-  $(WARN_LDFLAGS)
+  $(WARN_LDFLAGS) \
+  $(OCTAVE_UNICODE_EXE_LDFLAGS)
 
 %canon_reldir%_octave_cli_CPPFLAGS = \
   $(SRC_DIR_CPPFLAGS) \
@@ -118,7 +121,8 @@
 %canon_reldir%_octave_gui_LDFLAGS = \
   $(NO_UNDEFINED_LDFLAG) \
   $(OCTAVE_GUI_LINK_OPTS) \
-  $(WARN_LDFLAGS)
+  $(WARN_LDFLAGS) \
+  $(OCTAVE_UNICODE_EXE_LDFLAGS)
 
 %canon_reldir%_octave_svgconvert_SOURCES = %reldir%/octave-svgconvert.cc
 
@@ -126,7 +130,9 @@
 
 %canon_reldir%_octave_svgconvert_LDADD = $(QT_LIBS)
 
-%canon_reldir%_octave_svgconvert_LDFLAGS = $(QT_LDFLAGS)
+%canon_reldir%_octave_svgconvert_LDFLAGS = \
+  $(QT_LDFLAGS) \
+  $(OCTAVE_UNICODE_EXE_LDFLAGS)
 
 %canon_reldir%_mkoctfile_SOURCES =
 
@@ -136,6 +142,9 @@
   liboctave/wrappers/libwrappers.la \
   libgnu/libgnu.la $(LIBS)
 
+%canon_reldir%_mkoctfile_LDFLAGS = \
+  $(OCTAVE_UNICODE_EXE_LDFLAGS)
+
 %canon_reldir%_mkoctfile_CPPFLAGS = \
   $(SRC_DIR_CPPFLAGS) \
   $(OCTAVE_CPPFLAGS)
@@ -149,6 +158,9 @@
   libgnu/libgnu.la \
   $(LIBS)
 
+%canon_reldir%_octave_config_LDFLAGS = \
+  $(OCTAVE_UNICODE_EXE_LDFLAGS)
+
 %canon_reldir%_octave_config_CPPFLAGS = \
   $(SRC_DIR_CPPFLAGS) \
   $(OCTAVE_CPPFLAGS)
--- a/src/octave-config.in.cc	Sun May 16 09:43:43 2021 +0200
+++ b/src/octave-config.in.cc	Sun May 16 09:44:35 2021 +0200
@@ -35,6 +35,12 @@
 #include <algorithm>
 #include <cstdlib>
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <vector>
+#  include <locale>
+#  include <codecvt>
+#endif
+
 #if ! defined (OCTAVE_PREFIX)
 #  define OCTAVE_PREFIX %OCTAVE_PREFIX%
 #endif
@@ -139,9 +145,28 @@
   vars["STARTUPFILEDIR"] = prepend_octave_home (%OCTAVE_STARTUPFILEDIR%);
 }
 
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+extern "C"
+int
+wmain (int argc, wchar_t **wargv)
+{
+  static char **argv = new char * [argc + 1];
+  std::vector<std::string> argv_str;
+
+  // convert wide character strings to multibyte UTF-8 strings
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
+  for (int i_arg = 0; i_arg < argc; i_arg++)
+    {
+      argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg]));
+      argv[i_arg] = &argv_str[i_arg][0];
+    }
+  argv[argc] = nullptr;
+
+#else
 int
 main (int argc, char **argv)
 {
+#endif
   initialize ();
 
   if (argc == 1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/octave-qsvghandler.h	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,755 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt SVG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// --------------------------------------------------------------------------
+// Build a QPainterPath from the "d" attribute of a path element
+// These functions are extracted from Qt-5.12 sources (qtsvghandler.cpp)
+// Modifications:
+//   * use static_cast<qreal> to avoid old style cast warning.
+// --------------------------------------------------------------------------
+
+#include <QPainterPath>
+
+static inline bool isDigit(ushort ch)
+{
+    static quint16 magic = 0x3ff;
+    return ((ch >> 4) == 3) && (magic >> (ch & 15));
+}
+
+static qreal toDouble(const QChar *&str)
+{
+    const int maxLen = 255;//technically doubles can go til 308+ but whatever
+    char temp[maxLen+1];
+    int pos = 0;
+
+    if (*str == QLatin1Char('-')) {
+        temp[pos++] = '-';
+        ++str;
+    } else if (*str == QLatin1Char('+')) {
+        ++str;
+    }
+    while (isDigit(str->unicode()) && pos < maxLen) {
+        temp[pos++] = str->toLatin1();
+        ++str;
+    }
+    if (*str == QLatin1Char('.') && pos < maxLen) {
+        temp[pos++] = '.';
+        ++str;
+    }
+    while (isDigit(str->unicode()) && pos < maxLen) {
+        temp[pos++] = str->toLatin1();
+        ++str;
+    }
+    bool exponent = false;
+    if ((*str == QLatin1Char('e') || *str == QLatin1Char('E')) && pos < maxLen) {
+        exponent = true;
+        temp[pos++] = 'e';
+        ++str;
+        if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) {
+            temp[pos++] = str->toLatin1();
+            ++str;
+        }
+        while (isDigit(str->unicode()) && pos < maxLen) {
+            temp[pos++] = str->toLatin1();
+            ++str;
+        }
+    }
+
+    temp[pos] = '\0';
+
+    qreal val;
+    if (!exponent && pos < 10) {
+        int ival = 0;
+        const char *t = temp;
+        bool neg = false;
+        if(*t == '-') {
+            neg = true;
+            ++t;
+        }
+        while(*t && *t != '.') {
+            ival *= 10;
+            ival += (*t) - '0';
+            ++t;
+        }
+        if(*t == '.') {
+            ++t;
+            int div = 1;
+            while(*t) {
+                ival *= 10;
+                ival += (*t) - '0';
+                div *= 10;
+                ++t;
+            }
+            val = static_cast<qreal> (ival)/static_cast<qreal> (div);
+        } else {
+            val = ival;
+        }
+        if (neg)
+            val = -val;
+    } else {
+        val = QByteArray::fromRawData(temp, pos).toDouble();
+    }
+    return val;
+
+}
+
+static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points)
+{
+    while (str->isSpace())
+        ++str;
+    while (isDigit(str->unicode()) ||
+           *str == QLatin1Char('-') || *str == QLatin1Char('+') ||
+           *str == QLatin1Char('.')) {
+
+        points.append(toDouble(str));
+
+        while (str->isSpace())
+            ++str;
+        if (*str == QLatin1Char(','))
+            ++str;
+
+        //eat the rest of space
+        while (str->isSpace())
+            ++str;
+    }
+}
+static void pathArcSegment(QPainterPath &path,
+                           qreal xc, qreal yc,
+                           qreal th0, qreal th1,
+                           qreal rx, qreal ry, qreal xAxisRotation)
+{
+    qreal sinTh, cosTh;
+    qreal a00, a01, a10, a11;
+    qreal x1, y1, x2, y2, x3, y3;
+    qreal t;
+    qreal thHalf;
+
+    sinTh = qSin(xAxisRotation * (3.141592653589793 / 180.0));
+    cosTh = qCos(xAxisRotation * (3.141592653589793 / 180.0));
+
+    a00 =  cosTh * rx;
+    a01 = -sinTh * ry;
+    a10 =  sinTh * rx;
+    a11 =  cosTh * ry;
+
+    thHalf = 0.5 * (th1 - th0);
+    t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf);
+    x1 = xc + qCos(th0) - t * qSin(th0);
+    y1 = yc + qSin(th0) + t * qCos(th0);
+    x3 = xc + qCos(th1);
+    y3 = yc + qSin(th1);
+    x2 = x3 + t * qSin(th1);
+    y2 = y3 - t * qCos(th1);
+
+    path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
+                 a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
+                 a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
+}
+
+// the arc handling code underneath is from XSVG (BSD license)
+/*
+ * Copyright  2002 USC/Information Sciences Institute
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Information Sciences Institute not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Information Sciences Institute
+ * makes no representations about the suitability of this software for
+ * any purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES
+ * INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+static void pathArc(QPainterPath &path,
+                    qreal               rx,
+                    qreal               ry,
+                    qreal               x_axis_rotation,
+                    int         large_arc_flag,
+                    int         sweep_flag,
+                    qreal               x,
+                    qreal               y,
+                    qreal curx, qreal cury)
+{
+    qreal sin_th, cos_th;
+    qreal a00, a01, a10, a11;
+    qreal x0, y0, x1, y1, xc, yc;
+    qreal d, sfactor, sfactor_sq;
+    qreal th0, th1, th_arc;
+    int i, n_segs;
+    qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check;
+
+    rx = qAbs(rx);
+    ry = qAbs(ry);
+
+    sin_th = qSin(x_axis_rotation * (3.141592653589793 / 180.0));
+    cos_th = qCos(x_axis_rotation * (3.141592653589793 / 180.0));
+
+    dx = (curx - x) / 2.0;
+    dy = (cury - y) / 2.0;
+    dx1 =  cos_th * dx + sin_th * dy;
+    dy1 = -sin_th * dx + cos_th * dy;
+    Pr1 = rx * rx;
+    Pr2 = ry * ry;
+    Px = dx1 * dx1;
+    Py = dy1 * dy1;
+    /* Spec : check if radii are large enough */
+    check = Px / Pr1 + Py / Pr2;
+    if (check > 1) {
+        rx = rx * qSqrt(check);
+        ry = ry * qSqrt(check);
+    }
+
+    a00 =  cos_th / rx;
+    a01 =  sin_th / rx;
+    a10 = -sin_th / ry;
+    a11 =  cos_th / ry;
+    x0 = a00 * curx + a01 * cury;
+    y0 = a10 * curx + a11 * cury;
+    x1 = a00 * x + a01 * y;
+    y1 = a10 * x + a11 * y;
+    /* (x0, y0) is current point in transformed coordinate space.
+       (x1, y1) is new point in transformed coordinate space.
+
+       The arc fits a unit-radius circle in this space.
+    */
+    d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
+    sfactor_sq = 1.0 / d - 0.25;
+    if (sfactor_sq < 0) sfactor_sq = 0;
+    sfactor = qSqrt(sfactor_sq);
+    if (sweep_flag == large_arc_flag) sfactor = -sfactor;
+    xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
+    yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
+    /* (xc, yc) is center of the circle. */
+
+    th0 = qAtan2(y0 - yc, x0 - xc);
+    th1 = qAtan2(y1 - yc, x1 - xc);
+
+    th_arc = th1 - th0;
+    if (th_arc < 0 && sweep_flag)
+        th_arc += 2 * 3.141592653589793;
+    else if (th_arc > 0 && !sweep_flag)
+        th_arc -= 2 * 3.141592653589793;
+
+    n_segs = qCeil(qAbs(th_arc / (3.141592653589793 * 0.5 + 0.001)));
+
+    for (i = 0; i < n_segs; i++) {
+        pathArcSegment(path, xc, yc,
+                       th0 + i * th_arc / n_segs,
+                       th0 + (i + 1) * th_arc / n_segs,
+                       rx, ry, x_axis_rotation);
+    }
+}
+
+static QTransform parseTransformationMatrix(const QStringRef &value)
+{
+    if (value.isEmpty())
+        return QTransform();
+
+    QTransform matrix;
+    const QChar *str = value.constData();
+    const QChar *end = str + value.length();
+
+    while (str < end) {
+        if (str->isSpace() || *str == QLatin1Char(',')) {
+            ++str;
+            continue;
+        }
+        enum State {
+            Matrix,
+            Translate,
+            Rotate,
+            Scale,
+            SkewX,
+            SkewY
+        };
+        State state = Matrix;
+        if (*str == QLatin1Char('m')) {  //matrix
+            const char *ident = "atrix";
+            for (int i = 0; i < 5; ++i)
+                if (*(++str) != QLatin1Char(ident[i]))
+                    goto error;
+            ++str;
+            state = Matrix;
+        } else if (*str == QLatin1Char('t')) { //translate
+            const char *ident = "ranslate";
+            for (int i = 0; i < 8; ++i)
+                if (*(++str) != QLatin1Char(ident[i]))
+                    goto error;
+            ++str;
+            state = Translate;
+        } else if (*str == QLatin1Char('r')) { //rotate
+            const char *ident = "otate";
+            for (int i = 0; i < 5; ++i)
+                if (*(++str) != QLatin1Char(ident[i]))
+                    goto error;
+            ++str;
+            state = Rotate;
+        } else if (*str == QLatin1Char('s')) { //scale, skewX, skewY
+            ++str;
+            if (*str == QLatin1Char('c')) {
+                const char *ident = "ale";
+                for (int i = 0; i < 3; ++i)
+                    if (*(++str) != QLatin1Char(ident[i]))
+                        goto error;
+                ++str;
+                state = Scale;
+            } else if (*str == QLatin1Char('k')) {
+                if (*(++str) != QLatin1Char('e'))
+                    goto error;
+                if (*(++str) != QLatin1Char('w'))
+                    goto error;
+                ++str;
+                if (*str == QLatin1Char('X'))
+                    state = SkewX;
+                else if (*str == QLatin1Char('Y'))
+                    state = SkewY;
+                else
+                    goto error;
+                ++str;
+            } else {
+                goto error;
+            }
+        } else {
+            goto error;
+        }
+
+
+        while (str < end && str->isSpace())
+            ++str;
+        if (*str != QLatin1Char('('))
+            goto error;
+        ++str;
+        QVarLengthArray<qreal, 8> points;
+        parseNumbersArray(str, points);
+        if (*str != QLatin1Char(')'))
+            goto error;
+        ++str;
+
+        if(state == Matrix) {
+            if(points.count() != 6)
+                goto error;
+            matrix = QTransform(points[0], points[1],
+                                points[2], points[3],
+                                points[4], points[5]) * matrix;
+        } else if (state == Translate) {
+            if (points.count() == 1)
+                matrix.translate(points[0], 0);
+            else if (points.count() == 2)
+                matrix.translate(points[0], points[1]);
+            else
+                goto error;
+        } else if (state == Rotate) {
+            if(points.count() == 1) {
+                matrix.rotate(points[0]);
+            } else if (points.count() == 3) {
+                matrix.translate(points[1], points[2]);
+                matrix.rotate(points[0]);
+                matrix.translate(-points[1], -points[2]);
+            } else {
+                goto error;
+            }
+        } else if (state == Scale) {
+            if (points.count() < 1 || points.count() > 2)
+                goto error;
+            qreal sx = points[0];
+            qreal sy = sx;
+            if(points.count() == 2)
+                sy = points[1];
+            matrix.scale(sx, sy);
+        } else if (state == SkewX) {
+            if (points.count() != 1)
+                goto error;
+            const qreal deg2rad = qreal(0.017453292519943295769);
+            matrix.shear(qTan(points[0]*deg2rad), 0);
+        } else if (state == SkewY) {
+            if (points.count() != 1)
+                goto error;
+            const qreal deg2rad = qreal(0.017453292519943295769);
+            matrix.shear(0, qTan(points[0]*deg2rad));
+        }
+    }
+  error:
+    return matrix;
+}
+
+static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
+{
+    qreal x0 = 0, y0 = 0;              // starting point
+    qreal x = 0, y = 0;                // current point
+    char lastMode = 0;
+    QPointF ctrlPt;
+    const QChar *str = dataStr.constData();
+    const QChar *end = str + dataStr.size();
+
+    while (str != end) {
+        while (str->isSpace() && (str + 1) != end)
+            ++str;
+        QChar pathElem = *str;
+        ++str;
+        QChar endc = *end;
+        *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee
+        QVarLengthArray<qreal, 8> arg;
+        parseNumbersArray(str, arg);
+        *const_cast<QChar *>(end) = endc;
+        if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
+            arg.append(0);//dummy
+        const qreal *num = arg.constData();
+        int count = arg.count();
+        while (count > 0) {
+            qreal offsetX = x;        // correction offsets
+            qreal offsetY = y;        // for relative commands
+            switch (pathElem.unicode()) {
+            case 'm': {
+                if (count < 2) {
+                    num++;
+                    count--;
+                    break;
+                }
+                x = x0 = num[0] + offsetX;
+                y = y0 = num[1] + offsetY;
+                num += 2;
+                count -= 2;
+                path.moveTo(x0, y0);
+
+                 // As per 1.2  spec 8.3.2 The "moveto" commands
+                 // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
+                 // the subsequent pairs shall be treated as implicit 'lineto' commands.
+                 pathElem = QLatin1Char('l');
+            }
+                break;
+            case 'M': {
+                if (count < 2) {
+                    num++;
+                    count--;
+                    break;
+                }
+                x = x0 = num[0];
+                y = y0 = num[1];
+                num += 2;
+                count -= 2;
+                path.moveTo(x0, y0);
+
+                // As per 1.2  spec 8.3.2 The "moveto" commands
+                // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
+                // the subsequent pairs shall be treated as implicit 'lineto' commands.
+                pathElem = QLatin1Char('L');
+            }
+                break;
+            case 'z':
+            case 'Z': {
+                x = x0;
+                y = y0;
+                count--; // skip dummy
+                num++;
+                path.closeSubpath();
+            }
+                break;
+            case 'l': {
+                if (count < 2) {
+                    num++;
+                    count--;
+                    break;
+                }
+                x = num[0] + offsetX;
+                y = num[1] + offsetY;
+                num += 2;
+                count -= 2;
+                path.lineTo(x, y);
+
+            }
+                break;
+            case 'L': {
+                if (count < 2) {
+                    num++;
+                    count--;
+                    break;
+                }
+                x = num[0];
+                y = num[1];
+                num += 2;
+                count -= 2;
+                path.lineTo(x, y);
+            }
+                break;
+            case 'h': {
+                x = num[0] + offsetX;
+                num++;
+                count--;
+                path.lineTo(x, y);
+            }
+                break;
+            case 'H': {
+                x = num[0];
+                num++;
+                count--;
+                path.lineTo(x, y);
+            }
+                break;
+            case 'v': {
+                y = num[0] + offsetY;
+                num++;
+                count--;
+                path.lineTo(x, y);
+            }
+                break;
+            case 'V': {
+                y = num[0];
+                num++;
+                count--;
+                path.lineTo(x, y);
+            }
+                break;
+            case 'c': {
+                if (count < 6) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                QPointF c1(num[0] + offsetX, num[1] + offsetY);
+                QPointF c2(num[2] + offsetX, num[3] + offsetY);
+                QPointF e(num[4] + offsetX, num[5] + offsetY);
+                num += 6;
+                count -= 6;
+                path.cubicTo(c1, c2, e);
+                ctrlPt = c2;
+                x = e.x();
+                y = e.y();
+                break;
+            }
+            case 'C': {
+                if (count < 6) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                QPointF c1(num[0], num[1]);
+                QPointF c2(num[2], num[3]);
+                QPointF e(num[4], num[5]);
+                num += 6;
+                count -= 6;
+                path.cubicTo(c1, c2, e);
+                ctrlPt = c2;
+                x = e.x();
+                y = e.y();
+                break;
+            }
+            case 's': {
+                if (count < 4) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                QPointF c1;
+                if (lastMode == 'c' || lastMode == 'C' ||
+                    lastMode == 's' || lastMode == 'S')
+                    c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+                else
+                    c1 = QPointF(x, y);
+                QPointF c2(num[0] + offsetX, num[1] + offsetY);
+                QPointF e(num[2] + offsetX, num[3] + offsetY);
+                num += 4;
+                count -= 4;
+                path.cubicTo(c1, c2, e);
+                ctrlPt = c2;
+                x = e.x();
+                y = e.y();
+                break;
+            }
+            case 'S': {
+                if (count < 4) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                QPointF c1;
+                if (lastMode == 'c' || lastMode == 'C' ||
+                    lastMode == 's' || lastMode == 'S')
+                    c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+                else
+                    c1 = QPointF(x, y);
+                QPointF c2(num[0], num[1]);
+                QPointF e(num[2], num[3]);
+                num += 4;
+                count -= 4;
+                path.cubicTo(c1, c2, e);
+                ctrlPt = c2;
+                x = e.x();
+                y = e.y();
+                break;
+            }
+            case 'q': {
+                if (count < 4) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                QPointF c(num[0] + offsetX, num[1] + offsetY);
+                QPointF e(num[2] + offsetX, num[3] + offsetY);
+                num += 4;
+                count -= 4;
+                path.quadTo(c, e);
+                ctrlPt = c;
+                x = e.x();
+                y = e.y();
+                break;
+            }
+            case 'Q': {
+                if (count < 4) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                QPointF c(num[0], num[1]);
+                QPointF e(num[2], num[3]);
+                num += 4;
+                count -= 4;
+                path.quadTo(c, e);
+                ctrlPt = c;
+                x = e.x();
+                y = e.y();
+                break;
+            }
+            case 't': {
+                if (count < 2) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                QPointF e(num[0] + offsetX, num[1] + offsetY);
+                num += 2;
+                count -= 2;
+                QPointF c;
+                if (lastMode == 'q' || lastMode == 'Q' ||
+                    lastMode == 't' || lastMode == 'T')
+                    c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+                else
+                    c = QPointF(x, y);
+                path.quadTo(c, e);
+                ctrlPt = c;
+                x = e.x();
+                y = e.y();
+                break;
+            }
+            case 'T': {
+                if (count < 2) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                QPointF e(num[0], num[1]);
+                num += 2;
+                count -= 2;
+                QPointF c;
+                if (lastMode == 'q' || lastMode == 'Q' ||
+                    lastMode == 't' || lastMode == 'T')
+                    c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
+                else
+                    c = QPointF(x, y);
+                path.quadTo(c, e);
+                ctrlPt = c;
+                x = e.x();
+                y = e.y();
+                break;
+            }
+            case 'a': {
+                if (count < 7) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                qreal rx = (*num++);
+                qreal ry = (*num++);
+                qreal xAxisRotation = (*num++);
+                qreal largeArcFlag  = (*num++);
+                qreal sweepFlag = (*num++);
+                qreal ex = (*num++) + offsetX;
+                qreal ey = (*num++) + offsetY;
+                count -= 7;
+                qreal curx = x;
+                qreal cury = y;
+                pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
+                        int(sweepFlag), ex, ey, curx, cury);
+
+                x = ex;
+                y = ey;
+            }
+                break;
+            case 'A': {
+                if (count < 7) {
+                    num += count;
+                    count = 0;
+                    break;
+                }
+                qreal rx = (*num++);
+                qreal ry = (*num++);
+                qreal xAxisRotation = (*num++);
+                qreal largeArcFlag  = (*num++);
+                qreal sweepFlag = (*num++);
+                qreal ex = (*num++);
+                qreal ey = (*num++);
+                count -= 7;
+                qreal curx = x;
+                qreal cury = y;
+                pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
+                        int(sweepFlag), ex, ey, curx, cury);
+
+                x = ex;
+                y = ey;
+            }
+                break;
+            default:
+                return false;
+            }
+            lastMode = pathElem.toLatin1();
+        }
+    }
+    return true;
+}
--- a/src/octave-svgconvert.cc	Sun May 16 09:43:43 2021 +0200
+++ b/src/octave-svgconvert.cc	Sun May 16 09:44:35 2021 +0200
@@ -23,8 +23,18 @@
 //
 ////////////////////////////////////////////////////////////////////////
 
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
 #include <iostream>
 
+#if defined (OCTAVE_USE_WINDOWS_API)
+#  include <vector>
+#  include <locale>
+#  include <codecvt>
+#endif
+
 #include <QtCore>
 #include <QtXml>
 
@@ -35,49 +45,41 @@
 #include <QPrinter>
 #include <QRegExp>
 
+// Include a set of path rendering functions extracted from Qt-5.12 source
+#include "octave-qsvghandler.h"
+
+// Render to pdf
 class pdfpainter : public QPainter
 {
 public:
-  pdfpainter (QString fname, QRectF sizepix, double dpi)
-    : m_fname (fname), m_sizef (sizepix), m_dpi (dpi), m_printer ()
+  pdfpainter (QString fname, QRectF sz)
+      :  m_printer ()
   {
-    double scl = get_scale ();
-    m_sizef.setWidth (m_sizef.width () * scl);
-    m_sizef.setHeight (m_sizef.height () * scl);
-
     // Printer settings
     m_printer.setOutputFormat (QPrinter::PdfFormat);
     m_printer.setFontEmbeddingEnabled (true);
-    m_printer.setOutputFileName (get_fname ());
+    m_printer.setOutputFileName (fname);
     m_printer.setFullPage (true);
-    m_printer.setPaperSize (get_rectf ().size (), QPrinter::DevicePixel);
+#if defined (HAVE_QPRINTER_SETPAGESIZE)
+    m_printer.setPageSize (QPageSize (sz.size (), QPageSize::Point,
+                                      QString ("custom"),
+                                      QPageSize::ExactMatch));
+#else
+    m_printer.setPaperSize (sz.size (), QPrinter::Point);
+#endif
 
     // Painter settings
     begin (&m_printer);
-    setViewport (get_rect ());
-    scale (get_scale (), get_scale ());
+    setWindow (sz.toRect ());
   }
 
-  ~pdfpainter (void) { }
-
-  QString get_fname (void) const { return m_fname; }
-
-  QRectF get_rectf (void) const { return m_sizef; }
-
-  QRect get_rect (void) const { return m_sizef.toRect (); }
-
-  double get_scale (void) const { return m_dpi / 72.0; }
-
-  void finish (void) { end (); }
+  ~pdfpainter (void) { end (); }
 
 private:
-  QString m_fname;
-  QRectF m_sizef;
-  double m_dpi;
   QPrinter m_printer;
 };
 
-// String conversion functions
+// String conversion functions+QVector<double> qstr2vectorf (QString str)
 QVector<double> qstr2vectorf (QString str)
 {
   QVector<double> pts;
@@ -344,6 +346,10 @@
   static QFont font;
   static double dx = 0, dy = 0;
 
+  // Store path defined in <defs> in a map
+  static bool in_defs = false;
+  static QMap< QString, QPainterPath> path_map;
+
   for (int i = 0; i < nodes.count (); i++)
     {
       QDomNode node = nodes.at (i);
@@ -360,79 +366,158 @@
         }
       else if (elt.tagName () == "g")
         {
-          bool current_clipstate = painter.hasClipping ();
-          QRegion current_clippath = painter.clipRegion ();
-
-          QString str = elt.attribute ("clip-path");
-          if (! str.isEmpty ())
-            {
-              QVector<QPoint> pts = clippath[get_field (str, "url")];
-              if (! pts.isEmpty ())
-                {
-                  painter.setClipRegion (QRegion (QPolygon (pts)));
-                  painter.setClipping (true);
-                }
-            }
-
-          draw (elt, painter);
-
-          // Restore previous clipping settings
-          painter.setClipRegion (current_clippath);
-          painter.setClipping (current_clipstate);
-        }
-      else if (elt.tagName () == "text")
-        {
-          // Font
-          font = QFont ();
           QString str = elt.attribute ("font-family");
           if (! str.isEmpty ())
-            font.setFamily (elt.attribute ("font-family"));
+            {
+              // Font
+              font = QFont ();
+              font.setFamily (elt.attribute ("font-family"));
+
+              str = elt.attribute ("font-weight");
+              if (! str.isEmpty () && str != "normal")
+                font.setWeight (QFont::Bold);
+
+              str = elt.attribute ("font-style");
+              if (! str.isEmpty () && str != "normal")
+                font.setStyle (QFont::StyleItalic);
 
-          str = elt.attribute ("font-weight");
-          if (! str.isEmpty () && str != "normal")
-            font.setWeight (QFont::Bold);
+              str = elt.attribute ("font-size");
+              if (! str.isEmpty ())
+                font.setPixelSize (str.toDouble ());
+
+              painter.setFont (font);
 
-          str = elt.attribute ("font-style");
-          if (! str.isEmpty () && str != "normal")
-            font.setStyle (QFont::StyleItalic);
+              // Translation and rotation
+              painter.save ();
+              str = get_field (elt.attribute ("transform"), "translate");
+              if (! str.isEmpty ())
+                {
+                  QStringList trans = str.split (",");
+                  dx = trans[0].toDouble ();
+                  dy = trans[1].toDouble ();
 
-          str = elt.attribute ("font-size");
-          if (! str.isEmpty ())
-            font.setPixelSize (str.toDouble ());
-
-          painter.setFont (font);
+                  str = get_field (elt.attribute ("transform"), "rotate");
+                  if (! str.isEmpty ())
+                    {
+                      QStringList rot = str.split (",");
+                      painter.translate (dx+rot[1].toDouble (),
+                                         dy+rot[2].toDouble ());
+                      painter.rotate (rot[0].toDouble ());
+                      dx = rot[1].toDouble ();
+                      dy = rot[2].toDouble ();
+                    }
+                  else
+                    {
+                      painter.translate (dx, dy);
+                      dx = 0;
+                      dy = 0;
+                    }
+                }
 
-          // Translation and rotation
-          painter.save ();
-          str = get_field (elt.attribute ("transform"), "translate");
-          if (! str.isEmpty ())
+              draw (elt, painter);
+              painter.restore ();
+            }
+          else
             {
-              QStringList trans = str.split (",");
-              dx = trans[0].toDouble ();
-              dy = trans[1].toDouble ();
+              bool current_clipstate = painter.hasClipping ();
+              QRegion current_clippath = painter.clipRegion ();
 
-              str = get_field (elt.attribute ("transform"), "rotate");
+              str = elt.attribute ("clip-path");
+              if (! str.isEmpty ())
+                {
+                  QVector<QPoint> pts = clippath[get_field (str, "url")];
+                  if (! pts.isEmpty ())
+                    {
+                      painter.setClipRegion (QRegion (QPolygon (pts)));
+                      painter.setClipping (true);
+                    }
+                }
+
+              // Fill color
+              str = get_field (elt.attribute ("fill"), "rgb");
               if (! str.isEmpty ())
                 {
-                  QStringList rot = str.split (",");
-                  painter.translate (dx+rot[1].toDouble (),
-                                     dy+rot[2].toDouble ());
-                  painter.rotate (rot[0].toDouble ());
-                  dx = rot[1].toDouble ();
-                  dy = rot[2].toDouble ();
+                  QStringList clist = str.split (",");
+                  painter.setBrush (QColor (clist[0].toInt (),
+                                            clist[1].toInt (),
+                                            clist[2].toInt ()));
+                }
+
+              // Transform
+              str = elt.attribute ("transform");
+              painter.save ();
+              if (! str.isEmpty ())
+                {
+                  QStringRef tf (&str);
+                  QTransform  tform =
+                    parseTransformationMatrix (tf) * painter.transform ();
+                  painter.setTransform (tform);
                 }
-              else
+
+              draw (elt, painter);
+
+              // Restore previous clipping settings
+              painter.restore  ();
+              painter.setClipRegion (current_clippath);
+              painter.setClipping (current_clipstate);
+            }
+        }
+      else if (elt.tagName () == "defs")
+        {
+          in_defs = true;
+          draw (elt, painter);
+          in_defs = false;
+        }
+      else if (elt.tagName () == "path")
+        {
+          // Store QPainterPath for latter use
+          QString id = elt.attribute ("id");
+          if (! id.isEmpty ())
+            {
+              QString d = elt.attribute ("d");
+
+              if (! d.isEmpty ())
                 {
-                  painter.translate (dx, dy);
-                  dx = 0;
-                  dy = 0;
+                  QStringRef data (&d);
+                  QPainterPath path;
+                  if (! parsePathDataFast (data, path))
+                    continue; // Something went wrong, pass
+                  else if (path.isEmpty ())
+                    std::cout << "Empty path for data:"
+                              << d.toStdString () << std::endl;
+                  else if (in_defs)
+                    path_map["#" + id] = path;
+                  else
+                    painter.drawPath (path);
+
+
+                  if (path_map["#" + id].isEmpty ())
+                    std::cout << "Empty path for data:"
+                              << d.toStdString () << std::endl;
                 }
             }
+        }
+      else if (elt.tagName () == "use")
+        {
+          painter.setPen (Qt::NoPen);
 
-          draw (elt, painter);
-          painter.restore ();
+          QString str = elt.attribute ("xlink:href");
+          if (! str.isEmpty () && str.size () > 2)
+            {
+              QPainterPath path = path_map[str];
+              if (! path.isEmpty ())
+                {
+                  str = elt.attribute ("x");
+                  double x = elt.attribute ("x").toDouble ();
+                  str = elt.attribute ("y");
+                  double y = elt.attribute ("y").toDouble ();
+                  painter.translate (x, y);
+                  painter.drawPath (path);
+                  painter.translate (-x, -y);
+                }
+            }
         }
-      else if (elt.tagName () == "tspan")
+      else if (elt.tagName () == "text")
         {
           // Font
           QFont saved_font (font);
@@ -504,9 +589,9 @@
           str = elt.attribute ("stroke-width");
           if (! str.isEmpty ())
             {
-              double w = str.toDouble () * painter.get_scale ();
+              double w = str.toDouble ();
               if (w > 0)
-                pen.setWidthF (w / painter.get_scale ());
+                pen.setWidthF (w);
             }
 
           str = elt.attribute ("stroke-linecap");
@@ -562,9 +647,8 @@
               if (! str.isEmpty ())
                 {
                   QVector<double> m = qstr2vectorf (str);
-                  double scl = painter.get_scale ();
-                  QTransform tform(m[0]*scl, m[1]*scl, m[2]*scl,
-                                   m[3]*scl, m[4]*scl, m[5]*scl);
+                  QTransform tform(m[0], m[1], m[2],
+                                   m[3], m[4], m[5]);
                   painter.setTransform (tform);
                 }
 
@@ -574,6 +658,27 @@
               painter.restore  ();
             }
         }
+      else if (elt.tagName () == "rect")
+        {
+          // Color
+          QColor col (Qt::black);
+          QString str = elt.attribute ("fill");
+          if (! str.isEmpty ())
+            col = QColor (str);
+
+          // Position
+          double x = elt.attribute ("x").toDouble ();
+          double y = elt.attribute ("y").toDouble ();
+
+          // Size
+          double wd = elt.attribute ("width").toDouble ();
+          double hg = elt.attribute ("height").toDouble ();
+
+          painter.setBrush (col);
+          painter.setPen (Qt::NoPen);
+
+          painter.drawRect (QRectF (x, y, wd, hg));
+        }
       else if (elt.tagName () == "polygon")
         {
           if (! clippath_id.isEmpty ())
@@ -669,7 +774,7 @@
               if (! str.isEmpty ())
                 {
                   double alpha = str.toDouble ();
-                  if (alpha != 1.0 && str.toDouble () >= 0.0)
+                  if (alpha != 1.0 && alpha >= 0.0)
                     color.setAlphaF (alpha);
                 }
 
@@ -678,7 +783,7 @@
 
               if (color != current_color)
                 {
-                  // Reconstruct the previous series of triangle
+                  // Reconstruct the previous series of triangles
                   QList<QPolygonF> polygons = current_polygon.reconstruct ();
                   collection.push_back (QPair<QList<QDomNode>,QList<QPolygonF> >
                                         (replaced_nodes, polygons));
@@ -716,8 +821,28 @@
     replace_polygons (parent_elt, collection[ii].first, collection[ii].second);
 }
 
-int main(int argc, char *argv[])
+#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+extern "C"
+int
+wmain (int argc, wchar_t **wargv)
 {
+  static char **argv = new char * [argc + 1];
+  std::vector<std::string> argv_str;
+
+  // convert wide character strings to multibyte UTF-8 strings
+  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
+  for (int i_arg = 0; i_arg < argc; i_arg++)
+    {
+      argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg]));
+      argv[i_arg] = &argv_str[i_arg][0];
+    }
+  argv[argc] = nullptr;
+
+#else
+int
+main (int argc, char **argv)
+{
+#endif
   const char *doc = "See \"octave-svgconvert -h\"";
   const char *help = "Usage:\n\
 octave-svgconvert infile fmt dpi font reconstruct outfile\n\n\
@@ -759,7 +884,7 @@
       // Read from stdin
       if (! file.open (stdin, QIODevice::ReadOnly | QIODevice::Text))
         {
-          std::cerr << "Unable read from stdin\n";
+          std::cerr << "Unable to read from stdin\n";
           std::cerr << doc;
           return -1;
         }
@@ -771,8 +896,7 @@
   if (! document.setContent (&file, false, &msg))
     {
       std::cerr << "Failed to parse XML contents" << std::endl
-                << msg.toStdString ();
-      std::cerr << doc;
+                << msg.toStdString () << std::endl;
       file.close();
       return -1;
     }
@@ -787,14 +911,9 @@
       return -1;
     }
 
-  // Resolution
-  double dpi = QString (argv[3]).toDouble ();
-  if (dpi <= 0.0)
-    {
-      std::cerr << "DPI must be positive\n";
-      return -1;
-    }
-
+  // Resolution (Currently unused). Keep the DPI argument in case
+  // we implement raster outputs.
+  // double dpi = QString (argv[3]).toDouble ();
 
   // Get the viewport from the root element
   QDomElement root = document.firstChildElement();
@@ -841,10 +960,9 @@
   if (! strcmp (argv[2], "pdf"))
     {
       // PDF painter
-      pdfpainter painter (fout.fileName (), vp, dpi);
+      pdfpainter painter (fout.fileName (), vp);
 
       draw (root, painter);
-      painter.finish ();
     }
   else
     {
--- a/src/shared-fcns.h	Sun May 16 09:43:43 2021 +0200
+++ b/src/shared-fcns.h	Sun May 16 09:44:35 2021 +0200
@@ -34,13 +34,15 @@
 
 #if defined (OCTAVE_USE_WINDOWS_API)
 
-#include <windows.h>
-#include <tlhelp32.h>
+#  include <windows.h>
+#  include <tlhelp32.h>
+#  include <locale>
+#  include <codecvt>
 
-#if defined (_MSC_VER)
-#  define popen _popen
-#  define pclose _pclose
-#endif
+#  if defined (_MSC_VER)
+#    define popen _popen
+#    define pclose _pclose
+#  endif
 
 static std::string
 w32_get_octave_home (void)
@@ -49,12 +51,16 @@
 
   std::string bin_dir;
 
-  char namebuf[MAX_PATH+1];
-  if (GetModuleFileName (GetModuleHandle (nullptr), namebuf, MAX_PATH))
+  wchar_t namebuf[MAX_PATH+1];
+  DWORD n_size
+    = GetModuleFileNameW (GetModuleHandle (nullptr), namebuf, MAX_PATH);
+  if (n_size < MAX_PATH)
     {
-      namebuf[MAX_PATH] = '\0';
+      // convert wide character string to multibyte UTF-8 string
+      std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
+      std::string exe_name
+        = wchar_conv.to_bytes (std::wstring (namebuf, n_size));
 
-      std::string exe_name = namebuf;
       std::size_t pos = exe_name.rfind ('\\');
 
       if (pos != std::string::npos)
--- a/test/args.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/args.tst	Sun May 16 09:44:35 2021 +0200
@@ -219,7 +219,7 @@
 %! f()
 
 ## struct
-%!function f (x = struct("a", 3))
+%!function f (x = struct ("a", 3))
 %!  assert (x, struct ("a", 3));
 %!endfunction
 %!test
--- a/test/bug-35448/fA.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-35448/fA.m	Sun May 16 09:44:35 2021 +0200
@@ -1,7 +1,7 @@
-# fA.m
+## fA.m
 function y = fA (x, f)
   global gfun
-  if nargin < 2
+  if (nargin < 2)
     y = fA (x, gfun);
   else
     w = feval (f, x);
--- a/test/bug-35448/fB.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-35448/fB.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# fB.m
+## fB.m
 function y = fB (x)
   y = x;
 endfunction
--- a/test/bug-35448/fC.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-35448/fC.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# fC.m
+## fC.m
 function y = fC (x)
   y = x;
 endfunction
--- a/test/bug-36025/@testclass/one.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-36025/@testclass/one.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-% function ONE return item "X"
+%% function ONE return item "X"
 
 function a = one (m)
   a = m.x;
--- a/test/bug-36025/@testclass/two.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-36025/@testclass/two.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-% function TWO returns item "Y"
+%% function TWO returns item "Y"
 
 function a = one (m)
   a = m.y;
--- a/test/bug-38236/df_vr.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-38236/df_vr.m	Sun May 16 09:44:35 2021 +0200
@@ -1,2 +1,2 @@
-# df_vr.m
+## df_vr.m
 vr = 7;
--- a/test/bug-38236/u_vr.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-38236/u_vr.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# u_vr.m
+## u_vr.m
 
 ## define and exectute "__demo__" once
 eval ("function __demo__ ();  df_vr;  v = vr * 2; endfunction");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-40117.tst	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,76 @@
+########################################################################
+##
+## Copyright (C) 2020-2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+%!function __mktestfun_40117__ (file, varargin)
+%!  unwind_protect
+%!    fid = fopen (file, "w");
+%!    fprintf (fid, "%s\n", varargin{:});
+%!  unwind_protect_cleanup
+%!    if (fid > 0)
+%!      fclose (fid);
+%!    endif
+%!  end_unwind_protect
+%!endfunction
+
+%!test <*40117>
+%! unwind_protect
+%!   tmp_dir = tempname ();
+%!   mkdir (tmp_dir);
+%!   a_dir = fullfile (tmp_dir, "a");
+%!   a_private_dir = fullfile (a_dir, "private");
+%!   mkdir (a_dir);
+%!   mkdir (a_private_dir);
+%!   __mktestfun_40117__ (fullfile (a_dir, "main_40117.m"),
+%!                        "function r = main_40117 ()",
+%!                        "  r = p1_40117 ();",
+%!                        "endfunction");
+%!   __mktestfun_40117__ (fullfile (a_private_dir, "p1_40117.m"),
+%!                        "function r = p1_40117 ()",
+%!                        "  r = p2_40117 ();",
+%!                        "endfunction");
+%!   __mktestfun_40117__ (fullfile (a_private_dir, "p2_40117.m"),
+%!                        "function r = p2_40117 ()",
+%!                        "  r = 'a_p2_40117';",
+%!                        "endfunction");
+%!   addpath (a_dir);
+%!   assert (main_40117 (), "a_p2_40117");
+%!
+%!   ## Update the secondary private function, attempting to avoid
+%!   ## filesystem timestamp resolution problems.
+%!   pause (1);
+%!   __mktestfun_40117__ (fullfile (a_private_dir, "p2_40117.m"),
+%!                        "function r = p2_40117 ()",
+%!                        "  r = 'new function!';",
+%!                        "endfunction");
+%!
+%!   ## Force new functions to be found.
+%!   rehash ();
+%!
+%!   assert (main_40117 (), "new function!");
+%! unwind_protect_cleanup
+%!   rmpath (a_dir);
+%!   confirm_recursive_rmdir (false, "local");
+%!   rmdir (tmp_dir, "s");
+%! end_unwind_protect
--- a/test/bug-47680/super_bug47680.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-47680/super_bug47680.m	Sun May 16 09:44:35 2021 +0200
@@ -1,7 +1,7 @@
 classdef super_bug47680
   properties
     tag;
-  end
+  endproperties
   methods
     function obj = super_bug47680 (x)
       obj.tag = x;
--- a/test/bug-50014/bug-50014.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-50014/bug-50014.tst	Sun May 16 09:44:35 2021 +0200
@@ -26,7 +26,7 @@
 %!error <duplicate subfunction or nested function name>
 %! duplicate_nested_function ()
 
-%!assert (duplicate_nested_in_subfunction_ok (), 3);
+%!assert (duplicate_nested_in_subfunction_ok (), 3)
 
 %!error <duplicate subfunction or nested function name>
 %! duplicate_nested_parent_function ()
@@ -52,4 +52,4 @@
 %!error <duplicate subfunction or nested function name>
 %! duplicate_subfunction_old_syntax ()
 
-%!assert (duplicate_subfunction_separate_scope_ok (), 3);
+%!assert (duplicate_subfunction_separate_scope_ok (), 3)
--- a/test/bug-50014/duplicate_parent_nested2.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-50014/duplicate_parent_nested2.m	Sun May 16 09:44:35 2021 +0200
@@ -4,8 +4,8 @@
     function bug ()
     endfunction
   endfunction
-  function bug () ## no error here
-    function bug () ## error here (duplicates parent name)
+  function bug ()  # no error here
+    function bug ()  # error here (duplicates parent name)
     endfunction
   endfunction
 endfunction
--- a/test/bug-51532/+package_bug51532/foo.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-51532/+package_bug51532/foo.m	Sun May 16 09:44:35 2021 +0200
@@ -1,3 +1,3 @@
 function retval = foo (val)
   retval = val;
-end
+endfunction
--- a/test/bug-52851/bug-52851.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-52851/bug-52851.tst	Sun May 16 09:44:35 2021 +0200
@@ -1,15 +1,15 @@
-%!test <52851>
+%!test <*52851>
 %! script1
 %! assert (r11, 1);
 %! assert (r21, 2);
 %! assert (r22, 2);
 
-%!test <52851>
+%!test <*52851>
 %! script2
 %! assert (r1, 1);
 %! assert (r2, 2);
 
-%!test <52851>
+%!test <*52851>
 %! flag = true;
 %! script3
 %! assert (r, 1);
@@ -17,7 +17,7 @@
 %! script3
 %! assert (r, 2);
 
-%!test <52851>
+%!test <*52851>
 %! script4
 %! assert (r1, 1);
 %! assert (r2, 2);
--- a/test/bug-54995/@testclass54995/testclass54995.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-54995/@testclass54995/testclass54995.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
 function obj = testclass54995 ()
   obj = struct ("x", eye (4));
-  obj = class(obj, "testclass54995");
+  obj = class (obj, "testclass54995");
 endfunction
--- a/test/bug-55321.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-55321.tst	Sun May 16 09:44:35 2021 +0200
@@ -23,7 +23,7 @@
 ##
 ########################################################################
 
-%!function cb_children (hg)
+%!function cb_children (hg, ~)
 %!  hl = get (hg, "children");
 %!  color = get (hl, "color");
 %!  set (hl, "userdata", isequal (color, [1 0 0]));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-56068/bug-56068.tst	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,9 @@
+%!test
+%! res = textscan (evalc ("bug_56068"), "%s", "delimiter", "\n");
+%! f_cell = textscan (fileread ("bug_56068.m"), "%s", "delimiter", "\n");
+%! f_echo = cellfun (@(x) sprintf ([PS4 "%s"], x), ...
+%!                   f_cell{1}([2,3,4,5,8,9,10,11]), ...
+%!                   "uniformoutput", false);
+%!
+%! assert (numel (res{1}), 15);
+%! assert (all (strcmp (res{1}([2,3,5,7,10,11,13,15]), f_echo)));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-56068/bug_56068.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,11 @@
+a = 1 + 1
+echo on
+b = 2 + 1
+B = 2 + 1
+echo
+c = 3 + 1
+C = 3 + 1
+echo
+d = 4 + 1
+D = 4 + 1
+echo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-56068/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,5 @@
+bug_56068_TEST_FILES = \
+  %reldir%/bug-56068.tst \
+  %reldir%/bug_56068.m
+
+TEST_FILES += $(bug_56068_TEST_FILES)
--- a/test/bug-58593/myclass2.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/bug-58593/myclass2.m	Sun May 16 09:44:35 2021 +0200
@@ -13,16 +13,16 @@
       case '.'
         switch (S(1).subs)
         case 'data'
-          % Transform: obj.data --> obj.data_
+          %% Transform: obj.data --> obj.data_
           r = obj.data_;
           if (length (S) > 1)
             r = subsref (r, S(2:end));
           end
         case 'alldata'
-          % Transform: obj.data --> obj.data_(1:end)
-          % This statement should trigger *builtin* subsref *twice* (one
-          % for the evaluation of 'end', and the other for the whole rvalue).
-          % 'end' here is also builtin 'end'
+          %% Transform: obj.data --> obj.data_(1:end)
+          %% This statement should trigger *builtin* subsref *twice* (one
+          %% for the evaluation of 'end', and the other for the whole rvalue).
+          %% 'end' here is also builtin 'end'
           r = obj.data_(1:end);
 
           if (length (S) > 1)
@@ -32,7 +32,7 @@
           error ('Incorrect usage');
         end
       case '()'
-        % Transform: obj(index) --> obj.data_(index)
+        %% Transform: obj(index) --> obj.data_(index)
         r = subsref (obj.data_, S);
       otherwise
         error ('Incorrect usage');
@@ -44,25 +44,25 @@
       case '.'
         switch (S(1).subs)
         case 'data'
-          % Transform: obj.data --> obj.data_
-          if length(S)>1
+          %% Transform: obj.data --> obj.data_
+          if (length (S)>1)
             B = subsasgn (obj.data_, S(2:end), B);
           end
           obj.data_ = B;
         case 'alldata'
-          % Transform: obj.data --> obj.data_(1:end)
-          if length(S)>1
+          %% Transform: obj.data --> obj.data_(1:end)
+          if (length (S)>1)
             B = subsasgn (obj.data_(1:end), S(2:end), B);
           end
-          % This statement should trigger *builtin* subsref to evaluate 'end',
-          % then *builtin* subsasgn for the whole assignment expression
-          % 'end' here is also builtin 'end'
+          %% This statement should trigger *builtin* subsref to evaluate 'end',
+          %% then *builtin* subsasgn for the whole assignment expression
+          %% 'end' here is also builtin 'end'
           obj.data_(1:end) = B;
         otherwise
-          error('Incorrect usage');
+          error ('Incorrect usage');
         end
       case '()'
-        % Transform: obj(index) --> obj.data_(index)
+        %% Transform: obj(index) --> obj.data_(index)
         obj.data_ = subsasgn (obj.data_, S, B);
       otherwise
         error ('Incorrect usage');
@@ -70,7 +70,7 @@
     end
 
     function r = end (obj, k, n)
-      % We subtract 1 from the "real" end of obj.data_
+      %% We subtract 1 from the "real" end of obj.data_
       r = builtin ('end', obj.data_, k, n) - 1;
     end
   end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bug-59950.tst	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,49 @@
+########################################################################
+##
+## Copyright (C) 2021 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/>.
+##
+########################################################################
+
+## The following tests are for undocumented Matlab behavior.
+
+%!shared x
+%! x = 13;
+%!assert <*59950>  (exist (''), 0)
+%!assert <*59950>  (exist ([]), 0)
+%!assert <*59950>  (exist ({}), 0)
+%!assert <*59950>  (exist (1:0), 0)
+%!assert <*59950>  (exist ('', 'var'), 0)
+%!assert <*59950>  (exist ([], 'builtin'), 0)
+%!assert <*59950>  (exist ({}, 'dir'), 0)
+%!assert <*59950>  (exist (1:0, 'file'), 0)
+%!error exist (containers.Map ())
+%!error exist (containers.Map ())
+%!assert <*59950>  (exist ('x', ''), 0)
+%!assert <*59950>  (exist ('x', []), 0)
+%!assert <*59950>  (exist ('x', {}), 0)
+%!assert <*59950>  (exist ('x', struct ([])), 0)
+%!error exist ('x', containers.Map ())
+%!assert <*59950> (exist (containers.Map (), ''), 0)
+%!assert <*59950> (exist (containers.Map (), []), 0)
+%!assert <*59950> (exist (containers.Map (), {}), 0)
+%!assert <*59950> (exist (containers.Map (), struct ([])), 0)
+%!error exist (containers.Map (), containers.Map ())
--- a/test/classdef/classdef.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/classdef/classdef.tst	Sun May 16 09:44:35 2021 +0200
@@ -55,9 +55,9 @@
 %!assert (p.principle == 50e3)
 %!assert (p.amount, amt, eps ())
 %!assert (amount (p), amt, eps ())
-%!xtest <55961>
+%!test <55961>
 %! assert (properties (p), {'rate'; 'term'; 'principle'});
-%!xtest <*55858>
+%!test <*55858>
 %! assert (methods (p), {'amount'; 'foo_value_class'});
 %!assert (isempty (foo_value_class().rate))
 %!error <property 'rate' is not constant> foo_value_class.rate
@@ -135,7 +135,7 @@
 %! assert (isequal (obj(2:end), 5:7))
 %! assert (isequal (obj.x, [7 5 6 7]))
 
-%!xtest <54966>
+%!test <54966>
 %! obj = foo_subsref_subsasgn (1);
 %! obj{1:3} = 5:7;
 %! assert (isequal ([obj{1:3}], 5:7))
@@ -171,7 +171,7 @@
 %! assert (isequal (obj.x(2:end), 5:7))
 %! assert (isequal (obj.x, [7 5 6 7]))
 
-%!xtest <54966>
+%!test <54966>
 %! obj = foo_subsref_subsasgn (1);
 %! obj.x{1:3} = 5:7;
 %! assert (isequal ([obj.x{1:3}], 5:7))
@@ -187,7 +187,7 @@
 %! obj{2}{2} = 4;
 %! assert (obj{2}{2} == 4);
 
-%!xtest <54966>
+%!test <54966>
 %! obj = foo_subsref_subsasgn (2);
 %! obj{1:2}(1:2) = ones (2);
 %! assert (isequal (obj{1:2}(1:2), ones (2)));
--- a/test/classdef/foo_subsref_subsasgn.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classdef/foo_subsref_subsasgn.m	Sun May 16 09:44:35 2021 +0200
@@ -18,7 +18,7 @@
 
     function ind = end (obj, k, n)
       sz = size (obj.x);
-      if k < n
+      if (k < n)
         ind = sz(k);
       else
         ind = prod (sz(k:end));
@@ -31,7 +31,7 @@
           if (S(1).type == "()")
             varargout = {obj.x(S(1).subs{1})};
           elseif (S(1).type == "{}")
-            % Note in ML R2018b "x{1:3}" expects "nargout == 3".
+            %% Note in ML R2018b "x{1:3}" expects "nargout == 3".
             varargout = num2cell (obj.x(S(1).subs{1}));
           elseif (S(1).type == "." && S(1).subs == 'x')
             varargout = {obj.x};
@@ -40,7 +40,7 @@
               'foo_subsref_subsasgn: Invalid syntax');
           end
         case 2
-          % Note in ML R2018b "x(1)(1)" is not allowed.
+          %% Note in ML R2018b "x(1)(1)" is not allowed.
           if (S(1).type == "{}" && (S(2).type == "{}" || S(2).type == "()"))
             varargout = {obj.x(S(1).subs{1}, S(2).subs{1})};
           elseif (S(1).type == "." && S(1).subs == 'x' ...
@@ -68,7 +68,7 @@
               'foo_subsref_subsasgn: Invalid syntax');
           end
         case 2
-          % Note in ML R2018b "x(1)(1)" is not allowed.
+          %% Note in ML R2018b "x(1)(1)" is not allowed.
           if (S(1).type == "{}" && (S(2).type == "{}" || S(2).type == "()"))
             obj.x(S(1).subs{1}, S(2).subs{1}) = varargin{1};
           elseif (S(1).type == "." && S(1).subs == 'x' ...
--- a/test/classes/@Blork/Blork.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Blork/Blork.m	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,5 @@
 function s = Blork (bleek)
-% Test class.
+%% Test class.
 
   if (nargin == 1 && isa (bleek, 'Blork'))
     s = bleek;
--- a/test/classes/@Blork/get.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Blork/get.m	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'bleek'
       v = s.bleek;
     otherwise
--- a/test/classes/@Blork/set.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Blork/set.m	Sun May 16 09:44:35 2021 +0200
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'bleek'
         s.bleek = propValue;
       otherwise
--- a/test/classes/@CPrecedenceTester1/CPrecedenceTester1.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@CPrecedenceTester1/CPrecedenceTester1.m	Sun May 16 09:44:35 2021 +0200
@@ -3,6 +3,6 @@
   x = struct ('useless_data', pi);
   x = class (x, 'CPrecedenceTester1');
 
-  % don't change anything as far as precedence is concerned
+  %% don't change anything as far as precedence is concerned
 
 end
--- a/test/classes/@CPrecedenceTester2/CPrecedenceTester2.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@CPrecedenceTester2/CPrecedenceTester2.m	Sun May 16 09:44:35 2021 +0200
@@ -3,7 +3,7 @@
   x = struct ('useless_data', pi^2);
   x = class (x, 'CPrecedenceTester2');
 
-  switch flag
+  switch (flag)
     case 1  % CPrecedencetester2 > Snork
       superiorto ('Snork');
     case 2  % CPrecedencetester2 < Snork
--- a/test/classes/@CPrecedenceTester3/CPrecedenceTester3.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@CPrecedenceTester3/CPrecedenceTester3.m	Sun May 16 09:44:35 2021 +0200
@@ -3,7 +3,7 @@
   x = struct ('useless_data', pi^3);
   x = class (x, 'CPrecedenceTester3');
 
-  switch flag
+  switch (flag)
     case 1  % CPrecedencetester3 > Snork
       superiorto ('Snork');
     case 2  % CPrecedencetester3 < Snork
--- a/test/classes/@Cork/Cork.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Cork/Cork.m	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,5 @@
 function s = Cork (click)
-% Test class.
+%% Test class.
 
   if (nargin == 1 && isa (click, 'Cork'))
     s = click;
--- a/test/classes/@Cork/get.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Cork/get.m	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'click'
       v = s.click;
     otherwise
--- a/test/classes/@Cork/set.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Cork/set.m	Sun May 16 09:44:35 2021 +0200
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'click'
         s.click = propValue;
       otherwise
--- a/test/classes/@Dork/display.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Dork/display.m	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,5 @@
 function display (s)
-%  Display the critical info for an amplifier
+%%  Display the critical info for an amplifier
 
    gick = get (s, 'gick');
    disp ([inputname(1),'.gick = ']);
--- a/test/classes/@Dork/get.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Dork/get.m	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'gack'
       v = s.gack;
     otherwise
--- a/test/classes/@Dork/set.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Dork/set.m	Sun May 16 09:44:35 2021 +0200
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'gack'
         s.gack = propValue;
       otherwise
--- a/test/classes/@Gork/display.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Gork/display.m	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,5 @@
 function display (s)
-%  Display the critical info for a Gork.
+%%  Display the critical info for a Gork.
 
    dork_base = s.Dork
    %pork_base = s.Pork
--- a/test/classes/@Gork/get.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Gork/get.m	Sun May 16 09:44:35 2021 +0200
@@ -1,13 +1,13 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'cork'
       v = s.Cork;
     case 'gark'
       v = s.gark;
     otherwise
-      % Note that get/set for multiple parents is hard.  We only do one
-      % branch of the parent tree just to test this stuff out.
+      %% Note that get/set for multiple parents is hard.  We only do one
+      %% branch of the parent tree just to test this stuff out.
       v = get (s.Dork,propName);
   end
 
--- a/test/classes/@Gork/set.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Gork/set.m	Sun May 16 09:44:35 2021 +0200
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'cork'
         if (isa (propValue, 'Cork'))
           s.Cork = propValue;
@@ -15,8 +15,8 @@
       case 'gark'
         s.gark = propValue;
       otherwise
-        % Note that get/set for multiple parents is hard.  We only do one
-        % branch of the parent tree just to test this stuff out.
+        %% Note that get/set for multiple parents is hard.  We only do one
+        %% branch of the parent tree just to test this stuff out.
         s.Dork = set (s.Dork, propName, propValue);
     end
   end
--- a/test/classes/@Gork/subsasgn.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Gork/subsasgn.m	Sun May 16 09:44:35 2021 +0200
@@ -1,8 +1,8 @@
 function g = subsasgn (g, s, x)
 
-  switch s.type
+  switch (s.type)
   case '.'
-    switch s.subs
+    switch (s.subs)
     case 'gyrk'
       g.gyrk = x;
     end
--- a/test/classes/@Gork/subsref.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Gork/subsref.m	Sun May 16 09:44:35 2021 +0200
@@ -1,8 +1,8 @@
 function x = subsref (g, s)
 
-  switch s.type
+  switch (s.type)
   case '.'
-    switch s.subs
+    switch (s.subs)
     case 'gyrk'
       x = g.gyrk;
     end
--- a/test/classes/@Pork/display.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Pork/display.m	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,5 @@
 function display (s)
-%  Display the critical info for an amplifier
+%%  Display the critical info for an amplifier
 
    geek = get (s, 'geek');
    disp ([inputname(1),'.geek = ']);
--- a/test/classes/@Pork/get.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Pork/get.m	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'gurk'
       v = s.gurk;
     otherwise
--- a/test/classes/@Pork/set.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Pork/set.m	Sun May 16 09:44:35 2021 +0200
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'gurk'
         s.gurk = propValue;
       otherwise
--- a/test/classes/@Sneetch/Sneetch.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Sneetch/Sneetch.m	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,5 @@
 function s = Sneetch (mcbean)
-% Test class: should produce error.
+%% Test class: should produce error.
 
   if (nargin == 1 && isa (mcbean, 'Sneetch'))
     s = mcbean;
--- a/test/classes/@Snork/Snork.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Snork/Snork.m	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,5 @@
 function s = Snork (gick)
-% Test class.
+%% Test class.
 
   if (nargin == 1 && isa (gick, 'Snork'))
     s = gick;
--- a/test/classes/@Snork/end.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Snork/end.m	Sun May 16 09:44:35 2021 +0200
@@ -1,7 +1,7 @@
 function r = end (snk, index_pos, num_indices)
 
   if (num_indices ~= 1)
-    error ('Snork object may only have one index')
+    error ('Snork object may only have one index');
   end
 
   r = length (snk.cack);
--- a/test/classes/@Snork/get.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Snork/get.m	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'gick'
       v = s.gick;
     otherwise
--- a/test/classes/@Snork/set.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Snork/set.m	Sun May 16 09:44:35 2021 +0200
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'gick'
         s.gick = propValue;
       otherwise
--- a/test/classes/@Spork/Spork.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Spork/Spork.m	Sun May 16 09:44:35 2021 +0200
@@ -1,5 +1,5 @@
 function s = Spork (geek)
-% Test class.
+%% Test class.
 
     if (nargin == 1 && isa (geek, 'Spork'))
       s = geek;
--- a/test/classes/@Spork/get.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Spork/get.m	Sun May 16 09:44:35 2021 +0200
@@ -1,6 +1,6 @@
 function v = get (s, propName)
 
-  switch propName
+  switch (propName)
     case 'geek'
       v = s.geek;
     otherwise
--- a/test/classes/@Spork/set.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/@Spork/set.m	Sun May 16 09:44:35 2021 +0200
@@ -5,7 +5,7 @@
     propName  = propArgs{1};
     propValue = propArgs{2};
     propArgs  = propArgs(3:end);
-    switch propName
+    switch (propName)
       case 'geek'
         s.geek = propValue;
       otherwise
--- a/test/classes/classes.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/classes/classes.tst	Sun May 16 09:44:35 2021 +0200
@@ -65,9 +65,9 @@
 %! assert (isobject (snk));
 %! assert (isequal (class (snk), 'Snork'));
 %! assert (isa (snk, 'Snork'));
-%! assert (!isa (snk, 'Sneetch'));
+%! assert (! isa (snk, 'Sneetch'));
 %! assert (ismethod (snk, 'gick'));
-%! assert (!ismethod (snk, 'bletch'));
+%! assert (! ismethod (snk, 'bletch'));
 %! assert (exist ('snk') == 1);
 %! assert (exist ('blink') == 0);
 %!test snk1 = Snork (snk);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/@legacy_colon_op/colon.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,7 @@
+function r = colon (a, b, c)
+  if (nargin == 2)
+    r = sprintf ("%s:%s", class (a), class (b));
+  else
+    r = sprintf ("%s:%s:%s", class (a), class (b), class (c));
+  endif
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/@legacy_colon_op/legacy_colon_op.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,3 @@
+function obj = legacy_colon_op ()
+  obj = class (struct (), "legacy_colon_op");
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/colon-op.tst	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,25 @@
+%!test
+%! x = colon_op ();
+%! assert (x:2:3, "colon_op:double:double");
+%! assert (1:x:3, "double:colon_op:double");
+%! assert (1:2:x, "double:double:colon_op");
+%! assert (x:x:3, "colon_op:colon_op:double");
+%! assert (1:x:x, "double:colon_op:colon_op");
+%! assert (x:2:x, "colon_op:double:colon_op");
+%! assert (x:x:x, "colon_op:colon_op:colon_op");
+%! assert (x:2, "colon_op:double");
+%! assert (1:x, "double:colon_op");
+%! assert (x:x, "colon_op:colon_op");
+
+%!test
+%! x = legacy_colon_op ();
+%! assert (x:2:3, "legacy_colon_op:double:double");
+%! assert (1:x:3, "double:legacy_colon_op:double");
+%! assert (1:2:x, "double:double:legacy_colon_op");
+%! assert (x:x:3, "legacy_colon_op:legacy_colon_op:double");
+%! assert (1:x:x, "double:legacy_colon_op:legacy_colon_op");
+%! assert (x:2:x, "legacy_colon_op:double:legacy_colon_op");
+%! assert (x:x:x, "legacy_colon_op:legacy_colon_op:legacy_colon_op");
+%! assert (x:2, "legacy_colon_op:double");
+%! assert (1:x, "double:legacy_colon_op");
+%! assert (x:x, "legacy_colon_op:legacy_colon_op");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/colon_op.m	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,11 @@
+classdef colon_op
+  methods
+    function r = colon (a, b, c)
+      if (nargin == 2)
+        r = sprintf ("%s:%s", class (a), class (b));
+      else
+        r = sprintf ("%s:%s:%s", class (a), class (b), class (c));
+      endif
+    endfunction
+  endmethods
+endclassdef
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/colon-op/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,7 @@
+colon_op_TEST_FILES = \
+  %reldir%/@legacy_colon_op/colon.m \
+  %reldir%/@legacy_colon_op/legacy_colon_op.m \
+  %reldir%/colon-op.tst \
+  %reldir%/colon_op.m
+
+TEST_FILES += $(colon_op_TEST_FILES)
--- a/test/command.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/command.tst	Sun May 16 09:44:35 2021 +0200
@@ -174,5 +174,5 @@
 %! command_test w(m,1)   % edge weights
 %! assert (cmd_out, '|w(m,1)|');
 %!test
-%! command_test x2( size( x ) )
-%! assert (cmd_out, '|x2( size( x ) )|');
+%! command_test x2( size ( x ) )
+%! assert (cmd_out, '|x2( size ( x ) )|');
--- a/test/complex.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/complex.tst	Sun May 16 09:44:35 2021 +0200
@@ -43,9 +43,9 @@
 
 ## bug #43313, -1 is both '>' and '==' to (-1 - 0i)
 %!test
-%! assert (complex(-1,0) == complex(-1,-0), true);
-%! assert (complex(-1,0) > complex(-1,-0), false);
-%! assert (complex(-1,0) < complex(-1,-0), false);
+%! assert (complex (-1,0) == complex (-1,-0), true);
+%! assert (complex (-1,0) > complex (-1,-0), false);
+%! assert (complex (-1,0) < complex (-1,-0), false);
 
 ## Test that sort and issorted both agree on boundary case
 %!test
--- a/test/ctor-vs-method/@parent/parent.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/ctor-vs-method/@parent/parent.m	Sun May 16 09:44:35 2021 +0200
@@ -3,12 +3,12 @@
   if (nargin == 0)
     rot = class (struct (), 'parent');
   else
-    switch class (a)
+    switch (class (a))
       case 'parent'
         %% copy constructor
         rot = a;
       otherwise
-        error ('type mismatch in parent constructor')
+        error ('type mismatch in parent constructor');
     end
   end
   __trace__ ('end parent/parent');
--- a/test/deprecate-props.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/deprecate-props.tst	Sun May 16 09:44:35 2021 +0200
@@ -37,25 +37,3 @@
 %!    endif
 %!  endif
 %!endfunction
-
-## text/uicontrol/uipanel/uibuttongroup/uitable  "oblique" value for
-## "fontangle" property was deprecated in 5.0, remove from version 7:
-##   * remove "oblique" options in graphics.in.h, QtHandlesUtils.cc,
-##     and ft-text-renderer.cc
-##   * remove warnings from update_fontangle in graphics.in.h
-%!test
-%! hf = figure ("visible", "off");
-%! unwind_protect
-%!   ht = text ();
-%!   testprop (ht, "fontangle", "7.0", "oblique");
-%!   hui = uicontrol ();
-%!   testprop (hui, "fontangle", "7.0", "oblique");
-%!   hui = uipanel ();
-%!   testprop (hui, "fontangle", "7.0", "oblique");
-%!   hui = uibuttongroup ();
-%!   testprop (hui, "fontangle", "7.0", "oblique");
-%!   hui = uitable ();
-%!   testprop (hui, "fontangle", "7.0", "oblique");
-%! unwind_protect_cleanup
-%!   close (hf);
-%! end_unwind_protect
--- a/test/diag-perm.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/diag-perm.tst	Sun May 16 09:44:35 2021 +0200
@@ -178,6 +178,8 @@
 %! assert (diag (D1D2), d1 .* d2);
 
 ## slicing
+## preserving diagonal matrix type is not possible if indices are
+## general matrix objects.
 %!test
 %! m = 13;
 %! n = 6;
@@ -185,7 +187,11 @@
 %! d = rand (mn, 1);
 %! D = diag (d, m, n);
 %! Dslice = D (1:(m-3), 1:(n-2));
-%! assert (typeinfo (Dslice), "diagonal matrix");
+%! if (disable_range ())
+%!   assert (typeinfo (Dslice), "matrix");
+%! else
+%!   assert (typeinfo (Dslice), "diagonal matrix");
+%! endif
 
 ## preserve dense matrix structure when scaling
 %!assert (typeinfo (rand (8) * (3 * eye (8))), "matrix")
@@ -226,7 +232,7 @@
 %! A = sprand (n, n, .5);
 %! scalefact = rand (n-2, 1);
 %! Dr = diag (scalefact, n, n-2);
-%! assert (full (Dr \ A), Dr \ full(A));
+%! assert (full (Dr \ A), Dr \ full (A));
 
 ## sparse inverse column scaling with a zero factor
 %!test
@@ -236,15 +242,15 @@
 %! Dc = diag (scalefact);
 %! scalefact(n-1) = Inf;
 %! Dc(n-1, n-1) = 0;
-%! assert (full (A / Dc), full(A) / Dc);
+%! assert (full (A / Dc), full (A) / Dc);
 
 ## short sparse inverse column scaling
 %!test
 %! n = 7;
 %! A = sprand (n, n, .5);
-%! scalefact = rand (1, n-2) + I () * rand(1, n-2);
+%! scalefact = rand (1, n-2) + I () * rand (1, n-2);
 %! Dc = diag (scalefact, n-2, n);
-%! assert (full (A / Dc), full(A) / Dc);
+%! assert (full (A / Dc), full (A) / Dc);
 
 ## adding sparse and diagonal stays sparse
 %!test
--- a/test/eval-catch.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/eval-catch.tst	Sun May 16 09:44:35 2021 +0200
@@ -35,12 +35,12 @@
 
 %!test
 %! eval ("clear a; a; str = '';", "str=lasterr;");
-%! assert (lasterr()(1:13), "'a' undefined");
+%! assert (lasterr ()(1:13), "'a' undefined");
 %! assert (str(1:13), "'a' undefined");
 
 %!test
 %! eval ("error ('user-defined error'); str = '';", "str = lasterr;");
-%! assert (lasterr()(1:18), "user-defined error");
+%! assert (lasterr ()(1:18), "user-defined error");
 %! assert (str(1:18), "user-defined error");
 
 %!function ms = mangle (s)
--- a/test/eval-command.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/eval-command.tst	Sun May 16 09:44:35 2021 +0200
@@ -175,9 +175,9 @@
 
 %!shared evalin_value
 %! evalin_value = "this is the caller";
-%!assert <59847> (f_eval_fun (), "this is the caller");
-%!assert <59847> (g_eval_fun (), "this is the caller");
-%!assert <59847> (h_eval_fun (), "this is h_eval_fun");
+%!assert <*59847> (f_eval_fun (), "this is the caller");
+%!assert <*59847> (g_eval_fun (), "this is the caller");
+%!assert <*59847> (h_eval_fun (), "this is h_eval_fun");
 
 %!function r = f_asgn_fun ()
 %!  asgnin_value = "this is f_asgn_fun";
@@ -195,17 +195,17 @@
 %!  r = asgnin_value;
 %!endfunction
 
-%!test <59847>
+%!test <*59847>
 %! asgnin_value = "this is the caller";
 %! assert (f_asgn_fun (), "this is f_asgn_fun");
 %! assert (asgnin_value, "f value");
 
-%!test <59847>
+%!test <*59847>
 %! asgnin_value = "this is the caller";
 %! assert (g_asgn_fun (), "this is g_asgn_fun");
 %! assert (asgnin_value, "f value");
 
-%!test <59847>
+%!test <*59847>
 %! asgnin_value = "this is the caller";
 %! assert (h_asgn_fun (), "f value");
 %! assert (asgnin_value, "this is the caller");
--- a/test/fcn-handle/package-function.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/fcn-handle/package-function.tst	Sun May 16 09:44:35 2021 +0200
@@ -33,4 +33,4 @@
 
 ## Also test without function handle.
 %!assert <*55975> (pkga.pkgb.f1 (), "pkg f1");
-%!assert (pkga.pkgb.f2 (), "pkg f2");
+%!assert (pkga.pkgb.f2 (), "pkg f2")
--- a/test/fcn-handle/static-method.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/fcn-handle/static-method.tst	Sun May 16 09:44:35 2021 +0200
@@ -33,4 +33,4 @@
 
 ## Also test without function handle.
 %!assert <*55975> (pkga.pkgb.bug51709_a.smeth (), "pkg bug51709_a");
-%!assert (pkga.pkgb.bug51709_b.smeth (), "pkg bug51709_b");
+%!assert (pkga.pkgb.bug51709_b.smeth (), "pkg bug51709_b")
--- a/test/for.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/for.tst	Sun May 16 09:44:35 2021 +0200
@@ -161,3 +161,45 @@
 %! endfor
 %! assert (cnt, 0);
 %! assert (k, cell (0,3));
+
+%!test <*45143>
+%! warning ("on", "Octave:infinite-loop", "local");
+%! fail ("for i = 0:inf; break; end", "warning",
+%!       "FOR loop limit is infinite");
+%!
+%! fail ("for i = 0:-1:-inf; break; end", "warning",
+%!       "FOR loop limit is infinite");
+
+%!test <*45143>
+%! warning ("on", "Octave:infinite-loop", "local");
+%! k = 0;
+%! for i = 1:Inf
+%!   if (++k > 10)
+%!     break;
+%!   endif
+%! endfor
+%! assert (i, 11);
+%!
+%! k = 0;
+%! for i = -1:-1:-Inf
+%!   if (++k > 10)
+%!     break;
+%!   endif
+%! endfor
+%! assert (i, -11);
+%!
+%! k = 0;
+%! for i = 1:-Inf
+%!   if (++k > 10)
+%!     break;
+%!   endif
+%! endfor
+%! assert (i, zeros (1,0));
+%!
+%! k = 0;
+%! for i = 0:-1:Inf
+%!   if (++k > 10)
+%!     break;
+%!   endif
+%! endfor
+%! assert (i, zeros (1,0));
--- a/test/func.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/func.tst	Sun May 16 09:44:35 2021 +0200
@@ -81,8 +81,8 @@
 %!
 %!    y = feval (fn, m, varargin{:});
 %!    y2 = feval (fn, reshape (mn, size (m)), varargin{:});
-%!    if (!strcmp (class (y), class (m)) ||
-%!         issparse (y) != issparse (m) || !size_equal (y, y2))
+%!    if (! strcmp (class (y), class (m)) ||
+%!         issparse (y) != issparse (m) || ! size_equal (y, y2))
 %!      error ("failed for type %s\n", typ{i});
 %!    endif
 %!    if (!(strcmp (typ{i}, "cell") || strcmp (typ{i}, "struct")) &&
@@ -211,5 +211,14 @@
 %!  retval = in1;
 %!endfunction
 
-%!error <can't make function parameter retval persistent> __fnpersist1__ (1);
-%!error <can't make function parameter in1 persistent> __fnpersist2__ (1);
+%!error <can't make function parameter retval persistent> __fnpersist1__ (1)
+%!error <can't make function parameter in1 persistent> __fnpersist2__ (1)
+
+## Check nargin, nargout validation by interpreter
+%!function __fn_nargout0__ (in1)
+%!endfunction
+%!function [out1] = __fn_nargin2__ (in1, in2)
+%!endfunction
+
+%!error <function called with too many outputs> r = __fn_nargout0__ ()
+%!error <function called with too many inputs>  r = __fn_nargin2__ (1,2,3)
--- a/test/if.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/if.tst	Sun May 16 09:44:35 2021 +0200
@@ -107,15 +107,15 @@
 %! assert (x, 13);
 
 ## test "is_true" of different data types
-%!error diag (NaN) || 0;
+%!error diag (NaN) || 0
 %!test
 %! d1 = diag ([])    || 0;
 %! d2 = diag (1)     || 0;
 %! d3 = diag ([1 2]) || 0;
 %! assert ([d1 d2 d3], [false true false]);
 
-%!error sparse (NaN) || 0;
-%!error sparse ([1 1 ; 1 NaN]) || 0;
+%!error sparse (NaN) || 0
+%!error sparse ([1 1 ; 1 NaN]) || 0
 %!test
 %! s1 = sparse ([])  || 0;
 %! s2 = sparse (1)   || 0;
@@ -133,5 +133,5 @@
 %! c1 = [2i 4i] || 0;
 %! c2 = [22 4i] || 0;
 %! c3 = i || 0;
-%! c4 = complex(0) || 0;
+%! c4 = complex (0) || 0;
 %! assert ([c1 c2 c3 c4], [true true true false]);
--- a/test/index.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/index.tst	Sun May 16 09:44:35 2021 +0200
@@ -513,8 +513,8 @@
 %!error <index \(2\): out of bound 1>                1(2)
 %!error <index \(1\): out of bound 0>                [](1)
 %!error <index \(-1\): subscripts>                   1(1)(-1)(1)
-%!error <index \(_,1\): out of bound 0 \(dimensions are 5x0\)> zeros(5,0)(3,1)
-%!error <index \(3,_\): out of bound 0 \(dimensions are 0x5\)> zeros(0,5)(3,1)
+%!error <index \(_,1\): out of bound 0 \(dimensions are 5x0\)> zeros (5,0)(3,1)
+%!error <index \(3,_\): out of bound 0 \(dimensions are 0x5\)> zeros (0,5)(3,1)
 %!
 %!shared abc
 %! abc = [1, 2];
@@ -539,8 +539,8 @@
 %!error <=: nonconformant arguments \(op1 is 1x1, op2 is 1x5\)> abc(3,5) = 1:5
 
 ##  Test diagonal matrices, and access of function results
-%!error <index \(_,_,5\): out of bound 1 \(dimensions are 3x3\)> eye(3)(2,3,5)
-%!error <index \(-2,_\): subscripts>               eye(4)(-2,3)
+%!error <index \(_,_,5\): out of bound 1 \(dimensions are 3x3\)> eye (3)(2,3,5)
+%!error <index \(-2,_\): subscripts>               eye (4)(-2,3)
 
 ##  Test cells
 %!shared abc
@@ -558,7 +558,7 @@
 
 ##  Test sparse matrices
 %!shared abc
-%! abc = sparse(3,3);
+%! abc = sparse (3,3);
 %!error <abc\(-1\): subscripts>                abc(-1)
 %!error <abc\(-1\): subscripts>                abc(-1) = 1
 %!error <abc\(-1,_\): subscripts>              abc(-1,1)
@@ -578,7 +578,7 @@
 %! abc = [1 2];
 %!error <abc\(0\+1i\): subscripts must be real>     abc(i)
 %! abc = [1 2; 3 4];
-%!error <abc\(1\+0i\): subscripts must be real>     abc(complex(1))
+%!error <abc\(1\+0i\): subscripts must be real>     abc(complex (1))
 %!error <abc\(1\+0.5i,_\): subscripts must be real> abc(1+0.5*i,3)
 %!error <abc\(_,0-2i\): subscripts must be real>    abc(2,0-2*i)
 
@@ -587,6 +587,6 @@
 %! a(1,1,1).b(1) = 3;
 
 %!test <*39789>
-%! c = cell(1,1,1);
+%! c = cell (1,1,1);
 %! c{1,1,1} = zeros(5, 2);
 %! c{1,1,1}(:, 1) = 1;
--- a/test/inline-fcn.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/inline-fcn.tst	Sun May 16 09:44:35 2021 +0200
@@ -6,7 +6,7 @@
 %!assert (fn (6), 37)
 %!assert (feval (inline ("sum (x(:))"), [1 2; 3 4]), 10)
 %!assert (feval (inline ("sqrt (x^2 + y^2)", "x", "y"), 3, 4), 5)
-%!assert (feval (inline ("exp (P1*x) + P2", 3), 3, 4, 5), exp(3*4) + 5)
+%!assert (feval (inline ("exp (P1*x) + P2", 3), 3, 4, 5), exp (3*4) + 5)
 
 ## Test input validation
 %!error inline ()
--- a/test/integer.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/integer.tst	Sun May 16 09:44:35 2021 +0200
@@ -50,3 +50,111 @@
 %!   xdiv = clsmax / 0.5;
 %!   assert (xdiv, clsmax);
 %! endfor
+
+## Tests for binary constants
+%!assert (0b1, uint8 (2^0))
+%!assert (0b10000000, uint8 (2^7))
+%!assert (0b11111111, intmax ("uint8"))
+%!assert (0b100000000, uint16 (2^8))
+%!assert (0b1000000000000000, uint16 (2^15))
+%!assert (0b1111111111111111, intmax ("uint16"))
+%!assert (0b10000000000000000, uint32 (2^16))
+%!assert (0b10000000000000000000000000000000, uint32 (2^31))
+%!assert (0b11111111111111111111111111111111, intmax ("uint32"))
+%!assert (0b100000000000000000000000000000000, uint64 (2^32))
+%!assert (0b1000000000000000000000000000000000000000000000000000000000000000, uint64 (2^63))
+%!assert (0b1111111111111111111111111111111111111111111111111111111111111111, intmax ("uint64"))
+%!error <too many digits for binary constant> eval ("0b11111111111111111111111111111111111111111111111111111111111111111")
+
+%!assert (0b1u16, uint16 (2^0))
+%!assert (0b10000000u16, uint16 (2^7))
+
+%!assert (0b1u32, uint32 (2^0))
+%!assert (0b10000000u32, uint32 (2^7))
+%!assert (0b1000000000000000u32, uint32 (2^15))
+
+%!assert (0b1u64, uint64 (2^0))
+%!assert (0b10000000u64, uint64 (2^7))
+%!assert (0b1000000000000000u64, uint64 (2^15))
+%!assert (0b10000000000000000000000000000000u64, uint64 (2^31))
+
+%!assert (0b1s16, int16 (2^0))
+%!assert (0b10000000s16, int16 (2^7))
+
+%!assert (0b1s32, int32 (2^0))
+%!assert (0b10000000s32, int32 (2^7))
+%!assert (0b1000000000000000s32, int32 (2^15))
+
+%!assert (0b1s64, int64 (2^0))
+%!assert (0b10000000s64, int64 (2^7))
+%!assert (0b1000000000000000s64, int64 (2^15))
+%!assert (0b10000000000000000000000000000000s64, int64 (2^31))
+
+## Tests for hexadecimal constants
+%!assert (0x1, uint8 (2^0))
+%!assert (0x80, uint8 (2^7))
+%!assert (0xff, intmax ("uint8"))
+%!assert (0x100, uint16 (2^8))
+%!assert (0x8000, uint16 (2^15))
+%!assert (0xffff, intmax ("uint16"))
+%!assert (0x10000, uint32 (2^16))
+%!assert (0x80000000, uint32 (2^31))
+%!assert (0xffffffff, intmax ("uint32"))
+%!assert (0x100000000, uint64 (2^32))
+%!assert (0x8000000000000000, uint64 (2^63))
+%!assert (0xffffffffffffffff, intmax ("uint64"))
+%!error <too many digits for hexadecimal constant> eval ("0xfffffffffffffffff")
+
+%!assert (0x1u16, uint16 (2^0))
+%!assert (0x80u16, uint16 (2^7))
+
+%!assert (0x1u32, uint32 (2^0))
+%!assert (0x80u32, uint32 (2^7))
+%!assert (0x8000u32, uint32 (2^15))
+
+%!assert (0x1u64, uint64 (2^0))
+%!assert (0x80u64, uint64 (2^7))
+%!assert (0x8000u64, uint64 (2^15))
+%!assert (0x80000000u64, uint64 (2^31))
+
+%!assert (0x1s16, int16 (2^0))
+%!assert (0x80s16, int16 (2^7))
+
+%!assert (0x1s32, int32 (2^0))
+%!assert (0x80s32, int32 (2^7))
+%!assert (0x8000s32, int32 (2^15))
+
+%!assert (0x1s64, int64 (2^0))
+%!assert (0x80s64, int64 (2^7))
+%!assert (0x8000s64, int64 (2^15))
+%!assert (0x80000000s64, int64 (2^31))
+
+## Tests for decimal constants with extreme values
+
+%!assert (uint64 (9007199254740992), uint64 (flintmax ()))
+%!assert (int64 (9007199254740992), int64 (flintmax ()))
+%!assert (uint64 (-9007199254740992), uint64 (-flintmax ()))
+%!assert (int64 (-9007199254740992), int64 (-flintmax ()))
+
+%!assert (uint64 (9007199254740993), uint64 (flintmax ())+1)
+%!assert (int64 (9007199254740993), int64 (flintmax ())+1)
+%!assert (uint64 (-9007199254740993), uint64 (-flintmax ())-1)
+%!assert (int64 (-9007199254740993), int64 (-flintmax ())-1)
+
+%!assert (uint64 (18446744073709551615), intmax ("uint64"))
+
+%!assert (int64 (9223372036854775807), intmax ("int64"))
+%!assert (int64 (-9223372036854775808), intmin ("int64"))
+
+%!test
+%! a = int64 ([9223372036854775803; 9223372036854775804; 9223372036854775805; 9223372036854775806; 9223372036854775807]);
+%! bval = int64 (9223372036854775807);
+%! b = [bval; bval; bval; bval; bval];
+%! assert (a, b);
+
+%!test
+%! a = int64 ([int64(9223372036854775803); 9223372036854775804; 9223372036854775805; 9223372036854775806; 9223372036854775807]);
+%! b0val = int64 (9223372036854775803);
+%! bval = int64 (9223372036854775807);
+%! b = [b0val; bval; bval; bval; bval];
+%! assert (a, b);
--- a/test/io.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/io.tst	Sun May 16 09:44:35 2021 +0200
@@ -196,7 +196,7 @@
 %! [load_status, load_files] = testls (1);
 %!
 %! for f = [save_files, load_files]
-%!   unlink (f{1});
+%!   sts = unlink (f{1});
 %! endfor
 %!
 %! assert (save_status && load_status);
@@ -228,7 +228,7 @@
 %!   assert (s64, s64t);
 %!   assert (u64, u64t);
 %! unwind_protect_cleanup
-%!   unlink (h5file);
+%!   sts = unlink (h5file);
 %! end_unwind_protect
 
 %!test
@@ -256,7 +256,7 @@
 %!       "-struct", "STR", "matrix_fld", "str*_fld");
 %! STR = load (struct_dat);
 %!
-%! assert (!isfield (STR,"scalar_fld") && ...
+%! assert (! isfield (STR,"scalar_fld") && ...
 %!         STR.matrix_fld == [1.1,2;3,4] && ...
 %!         STR.string_fld == "Octave" && ...
 %!         STR.struct_fld.x == 0 && ...
@@ -346,7 +346,7 @@
 %! assert (msg, "sscanf: format failed to match");
 %! assert (pos, 2);
 
-%!xtest <47413>
+%!test <47413>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! if (! ismac ()), return; endif
 %! [val, count, msg, pos] = sscanf ("3I2", "%f");
@@ -362,7 +362,7 @@
 %! assert (msg, "sscanf: format failed to match");
 %! assert (pos, 2);
 
-%!xtest <47413>
+%!test <47413>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! if (! ismac ()), return; endif
 %! [val, count, msg, pos] = sscanf ("3In2", "%f");
@@ -378,7 +378,7 @@
 %! assert (msg, "");
 %! assert (pos, 6);
 
-%!xtest <47413>
+%!test <47413>
 %! ## Same test code as above, but intended only for test statistics on Mac.
 %! if (! ismac ()), return; endif
 %! [val, count, msg, pos] = sscanf ("3Inf2", "%f");
@@ -407,11 +407,11 @@
 %% Note use fprintf so output not sent to stdout
 %!test
 %! nm = tempname ();
-%! fid1 = fopen (nm,"w");
+%! fid1 = fopen (nm, "w");
 %! x = fprintf (fid1, "%s: %d\n", "test", 1);
 %! fclose (fid1);
-%! fid2 = fopen (nm,"r");
-%! str = fscanf (fid2,"%s");
+%! fid2 = fopen (nm, "r");
+%! str = fscanf (fid2, "%s");
 %! fclose (fid2);
 %! unlink (nm);
 %! assert (x, 8);
--- a/test/jit.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/jit.tst	Sun May 16 09:44:35 2021 +0200
@@ -192,17 +192,17 @@
 %! assert (abs (result - 1/9) < 1e-5);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! temp = 1+1i;
-# %! nan = NaN;
-# %! while (1)
-# %!   temp = temp - 1i;
-# %!   temp = temp * nan;
-# %!   break;
-# %! endwhile
-# %! assert (imag (temp), 0);
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! temp = 1+1i;
+## %! nan = NaN;
+## %! while (1)
+## %!   temp = temp - 1i;
+## %!   temp = temp * nan;
+## %!   break;
+## %! endwhile
+## %! assert (imag (temp), 0);
+## %! assert (jit_failcnt, 0);
 
 %!testif HAVE_LLVM
 %! jit_failcnt (0);
@@ -217,15 +217,15 @@
 %! assert (imag (temp), 0);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! temp = 1+1i;
-# %! while (1)
-# %!   temp = temp * 5;
-# %!   break;
-# %! endwhile
-# %! assert (temp, 5+5i);
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! temp = 1+1i;
+## %! while (1)
+## %!   temp = temp * 5;
+## %!   break;
+## %! endwhile
+## %! assert (temp, 5+5i);
+## %! assert (jit_failcnt, 0);
 
 %!testif HAVE_LLVM
 %! jit_failcnt (0);
@@ -249,22 +249,22 @@
 %! assert (sum (mat) == total);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! nr = 1001;
-# %! mat = [3 1 5];
-# %! try
-# %!   for i = 1:nr
-# %!     if (i > 500)
-# %!       result = mat(100);
-# %!     else
-# %!       result = i;
-# %!     endif
-# %!   endfor
-# %! catch
-# %! end_try_catch
-# %! assert (result == 500);
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! nr = 1001;
+## %! mat = [3 1 5];
+## %! try
+## %!   for i = 1:nr
+## %!     if (i > 500)
+## %!       result = mat(100);
+## %!     else
+## %!       result = i;
+## %!     endif
+## %!   endfor
+## %! catch
+## %! end_try_catch
+## %! assert (result == 500);
+## %! assert (jit_failcnt, 0);
 
 %!function result = gen_test (n)
 %!  result = double (rand (1, n) > .01);
@@ -388,14 +388,14 @@
 %! endfor
 %!endfunction
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! lasterr ("");
-# %! try
-# %!   test_divide ();
-# %! end_try_catch
-# %! assert (strcmp (lasterr (), "division by zero"));
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! lasterr ("");
+## %! try
+## %!   test_divide ();
+## %! end_try_catch
+## %! assert (strcmp (lasterr (), "division by zero"));
+## %! assert (jit_failcnt, 0);
 
 %!testif HAVE_LLVM
 %! jit_failcnt (0);
@@ -459,17 +459,17 @@
 %! assert (a == 9);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! num = 2;
-# %! a = zeros (1, num);
-# %! i = 1;
-# %! while i <= num
-# %!   a(i) = norm (eye (i));
-# %!   ++i;
-# %! endwhile
-# %! assert (a, ones (1, num));
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! num = 2;
+## %! a = zeros (1, num);
+## %! i = 1;
+## %! while i <= num
+## %!   a(i) = norm (eye (i));
+## %!   ++i;
+## %! endwhile
+## %! assert (a, ones (1, num));
+## %! assert (jit_failcnt, 0);
 
 %!function test_compute_idom ()
 %! while (li <= length (l1) && si <= length (s1))
@@ -539,7 +539,7 @@
 %! assert (b, 1);
 %! assert (jit_failcnt, 0);
 
-%!xtest <53615>
+%!test <53615>
 %! ## FIXME: No support for functions with complex input prototypes
 %! if (! __have_feature__ ("ENABLE_JIT"))
 %!   return;
@@ -572,7 +572,7 @@
 %!shared id
 %! id = @(x) x;
 
-%!xtest <53615>
+%!test <53615>
 %! ## FIXME: No support for functions with complex input prototypes
 %! if (! __have_feature__ ("ENABLE_JIT"))
 %!   return;
@@ -583,14 +583,14 @@
 %! assert (id (1, 2), 1);
 %! assert (jit_failcnt, 0);
 
-# %!testif HAVE_LLVM
-# %! jit_failcnt (0);
-# %! lasterr ("");
-# %! try
-# %!   id ();
-# %! end_try_catch
-# %! assert (strncmp (lasterr (), "'x' undefined near", 18));
-# %! assert (jit_failcnt, 0);
+## %!testif HAVE_LLVM
+## %! jit_failcnt (0);
+## %! lasterr ("");
+## %! try
+## %!   id ();
+## %! end_try_catch
+## %! assert (strncmp (lasterr (), "'x' undefined near", 18));
+## %! assert (jit_failcnt, 0);
 
 ## Restore JIT settings
 %!testif HAVE_LLVM
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/json/jsondecode_BIST.tst	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,556 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Unit tests for jsondecode()
+%%
+%% Code in libinterp/corefcn/jsondecode.cc
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Note: This script is intended to also run under Matlab to verify
+%%       compatibility.  Preserve Matlab-formatting when making changes.
+
+%%% Test 1: decode null values
+
+%% null, in non-numeric arrays -> Empty double []
+%!testif HAVE_RAPIDJSON
+%! json = '["str", 5, null, true]';
+%! exp  = {'str'; 5; []; true};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% null, in numeric arrays to NaN (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '[1, 2, null, 3]';
+%! exp  = [1; 2; NaN; 3];
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% corner case: array of null values
+%!testif HAVE_RAPIDJSON
+%! json = '[null, null, null]';
+%! exp  = [NaN; NaN; NaN];
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%%% Test 2: Decode scalar Boolean, Number, and String values
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsondecode ('true'), logical (1)));
+%! assert (isa (jsondecode ('true'), 'logical'));
+%! assert (isequal (jsondecode ('false'), logical (0)));
+%! assert (isa (jsondecode ('false'), 'logical'));
+%! assert (isequal (jsondecode ('123.45'), 123.45));
+%! assert (isequal (jsondecode ('"hello there"'), 'hello there'));
+
+%%% Test 3: Decode Array of Booleans, Numbers, and Strings values
+
+%% vectors are always rendered as column vectors
+%!testif HAVE_RAPIDJSON
+%! json = '[true, true, false, true]';
+%! exp  = logical ([1; 1; 0; 1]);
+%! obs  = jsondecode (json);
+%! assert (isa (obs, 'logical'));
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON <*59135>
+%! json = '[[true, true], [false, true]]';
+%! exp  = logical ([1, 1; 0, 1]);
+%! obs  = jsondecode (json);
+%! assert (isa (obs, 'logical'));
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '["true", "true", "false", "true"]';
+%! exp  = {'true'; 'true'; 'false'; 'true'};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '["foo", "bar", ["foo", "bar"]]';
+%! exp  = {'foo'; 'bar'; {'foo'; 'bar'}};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% vectors are always rendered as column vectors
+%!testif HAVE_RAPIDJSON
+%! json = '[15000, 5, 12.25, 1502302.3012]';
+%! exp  = [15000; 5; 12.25; 1502302.3012];
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% row vectors are preserved by adding one level of hierarchy
+%% extracted from JSONio
+%!testif HAVE_RAPIDJSON
+%! json = '[[1,2]]';
+%! exp  = [1, 2];
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% If same dimensions -> transform to an array (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '[[1, 2], [3, 4]]';
+%! exp  = [1, 2; 3, 4];
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% extracted from JSONio
+%!testif HAVE_RAPIDJSON
+%! json = '[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]';
+%! exp  = cat (3, [1, 3; 5, 7], [2, 4; 6, 8]);
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% try different dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! json = '[[[1, 2, -1], [3, 4, null]], [[5, 6, Inf], [7, 8, -Inf]]]';
+%! exp  = cat (3, [1, 3; 5, 7], [2, 4; 6, 8], [-1, NaN; Inf, -Inf]);
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% try different dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! json = '[[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]';
+%! exp  = cat (3, [1, 3; 5, 7; 9, 11], [2, 4; 6, 8; 10, 12]);
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% try higher dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! json = ['[[[[1,-1], [2,-2]],[[3,-3],[4,-4]]],[[[5,-5],[6,-6]],[[7,-7],', ...
+%!         '[8,-8]]],[[[9,-9], [10,-10]],[[11,-11],[12,-12]]],', ...
+%!         '[[[13,-13],[14,-14]],[[15,-15],[16,-16]]]]'];
+%! var1 = cat (3, [1, 3; 5, 7; 9, 11; 13, 15], [2, 4; 6, 8; 10, 12; 14, 16]);
+%! var2 = cat (3, [-1, -3; -5, -7; -9, -11; -13, -15], ...
+%!             [-2, -4; -6, -8; -10, -12; -14, -16]);
+%! exp  = cat (4, var1, var2);
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '[[true, false], [true, false], [true, false]]';
+%! exp  = logical ([1 0; 1 0; 1 0]);
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% If different dimensions -> transform to a cell array (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '[[1, 2], [3, 4, 5]]';
+%! exp  = {[1; 2]; [3; 4; 5]};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% extracted from JSONio
+%%!testif HAVE_RAPIDJSON
+%! json = '[1, 2, [3, 4]]';
+%! exp  = {1; 2; [3; 4]};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '[true, false, [true, false, false]]';
+%! exp  = {true; false; logical([1; 0; 0])};
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+%! assert (isa (obs{1}, 'logical'));
+%! assert (isa (obs{2}, 'logical'));
+%! assert (isa (obs{3}, 'logical'));
+
+%%% Test 4: decode JSON Objects
+
+%% Check decoding of Boolean, Number, and String values inside an Object
+%!testif HAVE_RAPIDJSON
+%! json = '{"number": 3.14, "string": "foobar", "boolean": false}';
+%! exp  = struct ('number', 3.14, 'string', 'foobar', 'boolean', false);
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+%! assert (isa (obs.boolean, 'logical'));
+
+%% Check decoding of null values and arrays inside an object & makeValidName
+%!testif HAVE_RAPIDJSON
+%! json = [ '{"nonnumeric array": ["str", 5, null],' ...
+%!          '"numeric array": [1, 2, null]}' ];
+%! exp  = struct ('nonnumericArray', {{'str'; 5; []}}, ...
+%!                'numericArray', {[1; 2; NaN]});
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% Check decoding of objects inside an object & makeValidName (from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '{"object": {"  field 1   ": 1, "field-   2": 2, "3field": 3, "": 1}}';
+%! exp  = struct ('object', ...
+%!                struct ('field1', 1, 'field_2', 2, 'x3field', 3, 'x', 1));
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Check decoding of empty objects, empty arrays, and Inf inside an object
+%!testif HAVE_RAPIDJSON
+%! json = '{"a": Inf, "b": [], "c": {}}';
+%! exp  = struct ('a', Inf, 'b', [], 'c', struct ());
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Check decoding of string arrays inside an object & makeValidName
+%% extracted from JSONio
+%!testif HAVE_RAPIDJSON
+%! json = '{"%string.array": ["Statistical","Parametric","Mapping"]}';
+%! exp  = struct ('x_string_array', ...
+%!                {{'Statistical'; 'Parametric'; 'Mapping'}});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% extracted from jsonlab
+%!testif HAVE_RAPIDJSON
+%! json = ['{' , ...
+%!     '"glossary": { ', ...
+%!         '"title": "example glossary",', ...
+%! 		'"GlossDiv": {', ...
+%!             '"title": "S",', ...
+%! 			'"GlossList": {', ...
+%!                 '"GlossEntry": {', ...
+%!                     '"ID": "SGML",', ...
+%! 					'"SortAs": "SGML",', ...
+%! 					'"GlossTerm": "Standard Generalized Markup Language",', ...
+%! 					'"Acronym": "SGML",', ...
+%! 					'"Abbrev": "ISO 8879:1986",', ...
+%! 					'"GlossDef": {', ...
+%!                         '"para": "A meta-markup language, ', ...
+%!                         'used to create markup languages such as DocBook.",', ...
+%! 						'"GlossSeeAlso": ["GML", "XML"]', ...
+%!                     '},', ...
+%! 					'"GlossSee": "markup"', ...
+%!                 '}', ...
+%!             '}', ...
+%!         '}', ...
+%!     '}', ...
+%! '}'];
+%! var1 = struct ('para', ['A meta-markup language, used to create ' ...
+%!                         'markup languages such as DocBook.'], ...
+%!                'GlossSeeAlso', {{'GML'; 'XML'}});
+%! var2 = struct ('ID', 'SGML', 'SortAs', 'SGML', ...
+%!                'GlossTerm', 'Standard Generalized Markup Language', ...
+%!                'Acronym', 'SGML', 'Abbrev', 'ISO 8879:1986', ...
+%!                'GlossDef', var1, 'GlossSee', 'markup');
+%! exp  = struct ('glossary', ...
+%!                struct ('title', 'example glossary', ...
+%!                        'GlossDiv', struct ('title', 'S', ...
+%!                                            'GlossList', ...
+%!                                            struct ('GlossEntry', var2))));
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%%% Test 5: decode Array of JSON objects
+
+%% Arrays with the same field names in the same order (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '{"structarray": [{"a":1,"b":2},{"a":3,"b":4}]}';
+%! exp  = struct ('structarray', struct ('a', {1; 3}, 'b', {2; 4}));
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Different field names before calling makeValidName, BUT the same after
+%% calling it, resulting in structarray.
+%! json = [ '[', ...
+%!       '{', ...
+%!         '"i*d": 0,', ...
+%!         '"12name": "Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"i/d": 1,', ...
+%!         '"12name": "Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"i+d": 2,', ...
+%!         '"12name": "Jewel"', ...
+%!       '}', ...
+%!     ']'];
+%! exp  = struct ('i_d', {0; 1; 2}, ...
+%!                'x12name', {'Osborn'; 'Mcdowell'; 'Jewel'});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Arrays with the same field names in the same order.
+%% JSON text is generated from json-generator.com
+%!testif HAVE_RAPIDJSON
+%! json = ['[', ...
+%!   '{', ...
+%!     '"x_id": "5ee28980fc9ab3",', ...
+%!     '"index": 0,', ...
+%!     '"guid": "b229d1de-f94a",', ...
+%!     '"latitude": -17.124067,', ...
+%!     '"longitude": -61.161831,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Collins"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Hays"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Griffin"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{', ...
+%!     '"x_id": "5ee28980dd7250",', ...
+%!     '"index": 1,', ...
+%!     '"guid": "39cee338-01fb",', ...
+%!     '"latitude": 13.205994,', ...
+%!     '"longitude": -37.276231,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Jewel"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{', ...
+%!     '"x_id": "5ee289802422ac",', ...
+%!     '"index": 2,', ...
+%!     '"guid": "3db8d55a-663e",', ...
+%!     '"latitude": -35.453456,', ...
+%!     '"longitude": 14.080287,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Socorro"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Darla"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Leanne"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '}', ...
+%! ']'];
+%! var1 = struct ('id', {0; 1; 2}, 'name', {'Collins'; 'Hays'; 'Griffin'});
+%! var2 = struct ('id', {0; 1; 2}, 'name', {'Osborn'; 'Mcdowell'; 'Jewel'});
+%! var3 = struct ('id', {0; 1; 2}, 'name', {'Socorro'; 'Darla'; 'Leanne'});
+%! exp  = struct (...
+%!   'x_id', {'5ee28980fc9ab3'; '5ee28980dd7250'; '5ee289802422ac'}, ...
+%!   'index', {0; 1; 2}, ...
+%!   'guid', {'b229d1de-f94a'; '39cee338-01fb'; '3db8d55a-663e'}, ...
+%!   'latitude', {-17.124067; 13.205994; -35.453456}, ...
+%!   'longitude', {-61.161831; -37.276231; 14.080287}, ...
+%!   'friends', {var1; var2; var3});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Arrays with the same field names in different order (extracted from JSONio)
+%% Results in cell array, rather than struct array
+%!testif HAVE_RAPIDJSON
+%! json = '{"cellarray": [{"a":1,"b":2},{"b":3,"a":4}]}';
+%! exp  = struct ('cellarray', {{struct('a', 1, 'b', 2); ...
+%!                               struct('b', 3, 'a', 4)}});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Arrays with different field names (extracted from JSONio)
+%!testif HAVE_RAPIDJSON
+%! json = '{"cellarray": [{"a":1,"b":2},{"a":3,"c":4}]}';
+%! exp  = struct ('cellarray', {{struct('a', 1, 'b', 2); ...
+%!                               struct('a', 3, 'c', 4)}});
+%! obs  = jsondecode (json);
+%! assert (isequal (obs, exp));
+
+%% Arrays with different field names and a big test
+%!testif HAVE_RAPIDJSON
+%! json = ['[', ...
+%!   '{', ...
+%!     '"x_id": "5ee28980fc9ab3",', ...
+%!     '"index": 0,', ...
+%!     '"guid": "b229d1de-f94a",', ...
+%!     '"latitude": -17.124067,', ...
+%!     '"longitude": -61.161831,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Collins"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Hays"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Griffin"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{"numeric array": ["str", 5, null], "nonnumeric array": [1, 2, null]},', ...
+%!   '{', ...
+%!      '"firstName": "John",', ...
+%!      '"lastName": "Smith",', ...
+%!      '"age": 25,', ...
+%!      '"address":', ...
+%!      '{', ...
+%!          '"streetAddress": "21 2nd Street",', ...
+%!          '"city": "New York",', ...
+%!          '"state": "NY"', ...
+%!      '},', ...
+%!      '"phoneNumber":', ...
+%!          '{', ...
+%!            '"type": "home",', ...
+%!            '"number": "212 555-1234"', ...
+%!          '}', ...
+%!  '}]'];
+%! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ...
+%!                'guid', 'b229d1de-f94a', 'latitude', -17.124067, ...
+%!                'longitude', -61.161831, ...
+%!                'friends', ...
+%!                struct ('id', {0; 1; 2}, ...
+%!                        'name', {'Collins'; 'Hays'; 'Griffin'}));
+%! var2 = struct ('numericArray', {{'str'; 5; []}}, ...
+%!                'nonnumericArray', {[1; 2; NaN]});
+%! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ...
+%!                'address', ...
+%!                struct ('streetAddress', '21 2nd Street', ...
+%!                        'city', 'New York', 'state', 'NY'), ...
+%!                'phoneNumber', ...
+%!                struct ('type', 'home', 'number', '212 555-1234'));
+%! exp = {var1; var2; var3};
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%%% Test 6: decode Array of different JSON data types
+
+%!testif HAVE_RAPIDJSON
+%! json = ['[null, true, Inf, 2531.023, "hello there", ', ...
+%!   '{', ...
+%!     '"x_id": "5ee28980dd7250",', ...
+%!     '"index": 1,', ...
+%!     '"guid": "39cee338-01fb",', ...
+%!     '"latitude": 13.205994,', ...
+%!     '"longitude": -37.276231,', ...
+%!     '"friends": [', ...
+%!       '{', ...
+%!         '"id": 0,', ...
+%!         '"name": "Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 1,', ...
+%!         '"name": "Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id": 2,', ...
+%!         '"name": "Jewel"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '}]'];
+%! var =  struct ('x_id', '5ee28980dd7250', 'index', 1, ...
+%!                'guid', '39cee338-01fb', 'latitude', 13.205994, ...
+%!                'longitude', -37.276231,
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Osborn'; 'Mcdowell'; 'Jewel'}));
+%! exp = {[]; 1; Inf; 2531.023; 'hello there'; var};
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%% Array of arrays
+%!testif HAVE_RAPIDJSON
+%! json = ['[["str", Inf, null], [1, 2, null], ["foo", "bar", ["foo", "bar"]],', ...
+%!   '[[[1, 2], [3, 4]], [[5, 6], [7, 8]]],' , ...
+%!   '[', ...
+%!     '{', ...
+%!       '"x_id": "5ee28980fc9ab3",', ...
+%!       '"index": 0,', ...
+%!       '"guid": "b229d1de-f94a",', ...
+%!       '"latitude": -17.124067,', ...
+%!       '"longitude": -61.161831,', ...
+%!       '"friends": [', ...
+%!         '{', ...
+%!           '"id": 0,', ...
+%!           '"name": "Collins"', ...
+%!         '},', ...
+%!         '{', ...
+%!           '"id": 1,', ...
+%!           '"name": "Hays"', ...
+%!         '},', ...
+%!         '{', ...
+%!           '"id": 2,', ...
+%!           '"name": "Griffin"', ...
+%!         '}', ...
+%!       ']', ...
+%!     '},', ...
+%!     '{"numeric array": ["str", 5, null], "nonnumeric array": [1, 2, null]},', ...
+%!     '{', ...
+%!        '"firstName": "John",', ...
+%!        '"lastName": "Smith",', ...
+%!        '"age": 25,', ...
+%!        '"address":', ...
+%!        '{', ...
+%!            '"streetAddress": "21 2nd Street",', ...
+%!            '"city": "New York",', ...
+%!            '"state": "NY"', ...
+%!        '},', ...
+%!        '"phoneNumber":', ...
+%!            '{', ...
+%!              '"type": "home",', ...
+%!              '"number": "212 555-1234"', ...
+%!            '}', ...
+%!    '}]]'];
+%! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ...
+%!                'guid', 'b229d1de-f94a', 'latitude', -17.124067, ...
+%!                'longitude', -61.161831, ...
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Collins'; 'Hays'; 'Griffin'}));
+%! var2 = struct ('numericArray', {{'str'; 5; []}}, ...
+%!                'nonnumericArray', {[1; 2; NaN]});
+%! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ...
+%!                'address', ...
+%!                struct ('streetAddress', '21 2nd Street', ...
+%!                        'city', 'New York', 'state', 'NY'), ...
+%!                'phoneNumber', ...
+%!                struct ('type', 'home', 'number', '212 555-1234'));
+%! exp = {{'str'; Inf; []}; [1; 2; NaN]; {'foo'; 'bar'; {'foo'; 'bar'}};
+%!        cat(3, [1, 3; 5, 7], [2, 4; 6, 8]); {var1; var2 ;var3}};
+%! obs  = jsondecode (json);
+%! assert (isequaln (obs, exp));
+
+%%% Test 7: Check "ReplacementStyle" and "Prefix" options
+
+%!testif HAVE_RAPIDJSON
+%! json = '{"1a": {"1*a": {"1+*/-a": {"1#a": {}}}}}';
+%! exp  = struct ('n1a', ...
+%!                struct ('n1a', struct ('n1a', struct ('n1a', struct ()))));
+%! obs  = jsondecode (json, "ReplacementStyle", "delete", ...
+%!                          "Prefix", "_", "Prefix", "n");
+%! assert (isequal (obs, exp));
+
+%% Check forwarding of "ReplacementStyle" and "Prefix" options inside arrays
+%!testif HAVE_RAPIDJSON
+%! json = [ '[', ...
+%!       '{', ...
+%!         '"i*d": 0,', ...
+%!         '"12name": "Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"i*d": 1,', ...
+%!         '"12name": "Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"i*d": 2,', ...
+%!         '"12name": "Jewel"', ...
+%!       '}', ...
+%!     ']'];
+%! exp  = struct ('i0x2Ad', {0; 1; 2}, ...
+%!                'm_12name', {'Osborn'; 'Mcdowell'; 'Jewel'});
+%! obs  = jsondecode (json, "ReplacementStyle", "hex", "Prefix", "m_");
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! json = '{"cell*array": [{"1a":1,"b*1":2},{"1a":3,"b/2":4}]}';
+%! exp  = struct ('cell_array', {{struct('x_1a', 1, 'b_1', 2); ...
+%!                                struct('x_1a', 3, 'b_2', 4)}});
+%! obs  = jsondecode (json, "ReplacementStyle", "underscore", "Prefix", "x_");
+%! assert (isequal (obs, exp));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/json/jsonencode_BIST.tst	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,658 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Unit tests for jsonencode()
+%%
+%% Code in libinterp/corefcn/jsonencode.cc
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Note: This script is intended to also run under Matlab to verify
+%%       compatibility.  Preserve Matlab-formatting when making changes.
+
+%% Some tests here are just the reverse of tests in jsondecode with
+%% some modifications.
+
+%%% Test 1: Encode logical and numeric scalars, NaN, NA, and Inf
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (logical (1)), 'true'));
+%! assert (isequal (jsonencode (logical (0)), 'false'));
+%! assert (isequal (jsonencode (50.025), '50.025'));
+%! assert (isequal (jsonencode (NaN), 'null'));
+%! assert (isequal (jsonencode (NA), 'null'));    % Octave-only test
+%! assert (isequal (jsonencode (Inf), 'null'));
+%! assert (isequal (jsonencode (-Inf), 'null'));
+
+%% Customized encoding of Nan, NA, Inf, -Inf
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (NaN, 'ConvertInfAndNaN', true), 'null'));
+%! % Octave-only test for NA
+%! assert (isequal (jsonencode (NA, 'ConvertInfAndNaN', true), 'null'));
+%! assert (isequal (jsonencode (Inf, 'ConvertInfAndNaN', true), 'null'));
+%! assert (isequal (jsonencode (-Inf, 'ConvertInfAndNaN', true), 'null'));
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (NaN, 'ConvertInfAndNaN', false), 'NaN'));
+%! % Octave-only test for NA
+%! assert (isequal (jsonencode (NA, 'ConvertInfAndNaN', false), 'NaN'));
+%! assert (isequal (jsonencode (Inf, 'ConvertInfAndNaN', false), 'Infinity'));
+%! assert (isequal (jsonencode (-Inf, 'ConvertInfAndNaN', false), '-Infinity'));
+
+%%% Test 2: encode character vectors and arrays
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (''), '""'));
+%! assert (isequal (jsonencode ('hello there'), '"hello there"'));
+%! assert (isequal (jsonencode (['foo'; 'bar']), '["foo","bar"]'));
+%! assert (isequal (jsonencode (['foo', 'bar'; 'foo', 'bar']), ...
+%!                  '["foobar","foobar"]'));
+
+%% Escape characters inside single-quoted and double-quoted strings
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode ('\0\a\b\t\n\v\f\r'), ...
+%!                              '"\\0\\a\\b\\t\\n\\v\\f\\r"'));
+%! % FIXME: Matlab produces a double-escaped string as above.
+%! assert (isequal (jsonencode ("\a\b\t\n\v\f\r"), ...
+%!                              '"\u0007\b\t\n\u000B\f\r"'));
+
+%!testif HAVE_RAPIDJSON
+%! data = [[['foo'; 'bar']; ['foo'; 'bar']], [['foo'; 'bar']; ['foo'; 'bar']]];
+%! exp  = '["foofoo","barbar","foofoo","barbar"]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, ['a', 'b'; 'c', 'd'], ['e', 'f'; 'g', 'h']);
+%! exp  = '[["ab","ef"],["cd","gh"]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try different dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, ['a', 'b'; 'c', 'd'; '1', '2'], ...
+%!                ['e', 'f'; 'g', 'h'; '3', '4']);
+%! exp  = '[["ab","ef"],["cd","gh"],["12","34"]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try higher dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! charmat1 = cat (3, ['1', '3'; '5', '7'; '9', 'e'; 'f', 'g'], ...
+%!                    ['2', '4'; '6', '8'; 'a', 'b'; 'c', 'd']);
+%! charmat2 = cat (3, ['1', '3'; '5', '7'; '9', 'e'; 'f', 'g'], ...
+%!                    ['2', '4'; '6', '8'; 'a', 'b'; 'c', 'd']);
+%! data = cat (4, charmat1, charmat2);
+%! exp  = [ '[[["13","13"],["24","24"]],[["57","57"],["68","68"]],', ...
+%!          '[["9e","9e"],["ab","ab"]],[["fg","fg"],["cd","cd"]]]' ];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try different dimensions for an array with one of its dimensions equals one
+%!testif HAVE_RAPIDJSON
+%! data = cat (4, ['a'; 'b'], ['c'; 'd']);
+%! exp  = '[[["a","c"]],[["b","d"]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% High dimension, but still a vector, is reduced to a vector
+%!testif HAVE_RAPIDJSON
+%! data = cat (8, ['a'], ['c']);
+%! exp  = '"ac"';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = cat (8, ['a'; 'b'; '1'], ['c'; 'd'; '2']);
+%! exp  = '[[[[[[["a","c"]]]]]],[[[[[["b","d"]]]]]],[[[[[["1","2"]]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%%% Test 3: encode numeric and logical arrays (with NaN and Inf)
+
+%% Test simple vectors
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode ([]), '[]'));
+%! assert (isequal (jsonencode ([1, 2, 3, 4]), '[1,2,3,4]'));
+%! assert (isequal (jsonencode ([true; false; true]), '[true,false,true]'));
+
+%% Test arrays
+%!testif HAVE_RAPIDJSON
+%! data = [1, NaN; 3, 4];
+%! exp  = '[[1,null],[3,4]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, [NaN, 3; 5, Inf], [2, 4; -Inf, 8]);
+%! exp  = '[[[null,2],[3,4]],[[5,null],[null,8]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Customized encoding of Nan, Inf, -Inf
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, [1, NaN; 5, 7], [2, Inf; 6, -Inf]);
+%! exp  = '[[[1,2],[NaN,Infinity]],[[5,6],[7,-Infinity]]]';
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%% Try different dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, [1, 3; 5, 7], [2, 4; 6, 8], [-1, NaN; Inf, -Inf]);
+%! exp  = '[[[1,2,-1],[3,4,NaN]],[[5,6,Infinity],[7,8,-Infinity]]]';
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%% Try different dimensions for the array with one of its dimensions equals one
+%!testif HAVE_RAPIDJSON
+%! data = cat (3, [1; 7; 11], [4; 8; 12]);
+%! exp  = '[[[1,4]],[[7,8]],[[11,12]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! array1 = cat (3, [5, 7], [2, 4]);
+%! array2 = cat (3, [-1, -3], [-2, -4]);
+%! data = cat (4, array1, array2);
+%! exp  = '[[[[5,-1],[2,-2]],[[7,-3],[4,-4]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = cat (4, [1, 3; 5, 7], [-1, -3; -5, -7]);
+%! exp  = '[[[[1,-1]],[[3,-3]]],[[[5,-5]],[[7,-7]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% High-dimension vector is reduced to just a vector
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 1, 1, 1, 1, 6]);
+%! exp  = '[1,1,1,1,1,1]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 2, 2, 2]);
+%! exp  = '[[[[[1,1],[1,1]],[[1,1],[1,1]]],[[[1,1],[1,1]],[[1,1],[1,1]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 2, 1, 2]);
+%! exp  = '[[[[[1,1]],[[1,1]]],[[[1,1]],[[1,1]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 1, 2, 1, 2]);
+%! exp  = '[[[[[[1,1]],[[1,1]]]],[[[[1,1]],[[1,1]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 1, 2, 1, 2, 1, 2]);
+%! exp  = '[[[[[[[1,1]],[[1,1]]]],[[[[1,1]],[[1,1]]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 2, 1, 1, 2]);
+%! exp  = '[[[[[[1,1]]],[[[1,1]]]],[[[[1,1]]],[[[1,1]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 2, 1, 3, 1, 1, 1, 2]);
+%! exp  = ['[[[[[[[[1,1]]]],[[[[1,1]]]],[[[[1,1]]]]]],[[[[[[1,1]]]],', ...
+%!         '[[[[1,1]]]],[[[[1,1]]]]]]]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 1, 1, 1, 2, 1, 1, 1, 2]);
+%! exp  = '[[[[[[[[[1,1]]]],[[[[1,1]]]]]]]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 3, 2, 1, 1, 2, 1, 2, 2]);
+%! exp  = ['[[[[[[[[[1,1],[1,1]]],[[[1,1],[1,1]]]]]],[[[[[[1,1],', ...
+%!         '[1,1]]],[[[1,1],[1,1]]]]]]],[[[[[[[1,1],[1,1]]],[[[1,', ...
+%!         '1],[1,1]]]]]],[[[[[[1,1],[1,1]]],[[[1,1],[1,1]]]]]]],', ...
+%!         '[[[[[[[1,1],[1,1]]],[[[1,1],[1,1]]]]]],[[[[[[1,1],[1,', ...
+%!         '1]]],[[[1,1],[1,1]]]]]]]]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = ones ([1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 2]);
+%! exp  =  ['[[[[[[[[[[[[[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]],', ...
+%!          '[[[[[[[[1,1]]]]]]]]],[[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]', ...
+%!          ']]],[[[[[[[[1,1]]]]]]]]]],[[[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]', ...
+%!          ']]]]]]],[[[[[[[[1,1]]]]]]]]],[[[[[[[[[1,1]]]]]]]],[[[[[[', ...
+%!          '[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]]]]]]],[[[[[[[[[[[[[1,1]', ...
+%!          ']]]]]]],[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]]],[[[[[[[[', ...
+%!          '[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]]]],[[[', ...
+%!          '[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]]],', ...
+%!          '[[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]]]]]]],[[[[[[[[1,1]]', ...
+%!          ']]]]]]]]]]]]]]]]]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try higher dimensions for the array
+%!testif HAVE_RAPIDJSON
+%! var1 = cat (3, [1, 3; 5, 7; 9, 11; 13, 15], [2, 4; 6, 8; 10, 12; 14, 16]);
+%! var2 = cat (3, [-1, -3; -5, -7; -9, -11; -13, -15], ...
+%!                [-2, -4; -6, -8; -10, -12; -14, -16]);
+%! data = cat (4, var1, var2);
+%! exp  = ['[[[[1,-1],[2,-2]],[[3,-3],[4,-4]]],[[[5,-5],[6,-6]],[[7,-7],', ...
+%!         '[8,-8]]],[[[9,-9],[10,-10]],[[11,-11],[12,-12]]],', ...
+%!         '[[[13,-13],[14,-14]],[[15,-15],[16,-16]]]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Try logical array (tests above were all with numeric data)
+
+%% 2-D logical array
+%!testif HAVE_RAPIDJSON
+%! data = [true, false; true, false; true, false];
+%! exp  = '[[true,false],[true,false],[true,false]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% N-D logical array
+%!testif HAVE_RAPIDJSON <*59198>
+%! data = true (2,2,2);
+%! data(1,1,2) = false;
+%! exp  = '[[[true,false],[true,true]],[[true,true],[true,true]]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%%% Test 4: encode containers.Map
+
+%% KeyType must be char to encode objects of containers.Map
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode (containers.Map ('1', [1, 2, 3])), ...
+%!                  '{"1":[1,2,3]}'));
+
+%!testif HAVE_RAPIDJSON
+%! data = containers.Map ({'foo'; 'bar'; 'baz'}, [1, 2, 3]);
+%! exp  = '{"bar":2,"baz":3,"foo":1}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON
+%! data = containers.Map ({'foo'; 'bar'; 'baz'}, ...
+%!                        {{1, 'hello', NaN}, true, [2, 3, 4]});
+%! exp  = '{"bar":true,"baz":[2,3,4],"foo":[1,"hello",NaN]}';
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%%% Test 5: encode scalar structs
+
+%% Check the encoding of Boolean, Number, and String values inside a struct
+%!testif HAVE_RAPIDJSON
+%! data = struct ('number', 3.14, 'string', 'foobar', 'boolean', false);
+%! exp  = '{"number":3.14,"string":"foobar","boolean":false}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Check the encoding of NaN, NA, Inf, and -Inf values inside a struct
+%!testif HAVE_RAPIDJSON
+%! % Octave-only test because of NA value
+%! data = struct ('numericArray', [7, NaN, NA, Inf, -Inf]);
+%! exp  = '{"numericArray":[7,null,null,null,null]}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Customized encoding of Nan, NA, Inf, -Inf
+%!testif HAVE_RAPIDJSON
+%! data = struct ('numericArray', [7, NaN, NA, Inf, -Inf]);
+%! exp  = '{"numericArray":[7,NaN,NaN,Infinity,-Infinity]}';
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%% Check the encoding of structs inside a struct
+%!testif HAVE_RAPIDJSON
+%! data = struct ('object', struct ('field1', 1, 'field2', 2, 'field3', 3));
+%! exp  = '{"object":{"field1":1,"field2":2,"field3":3}}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Check the encoding of empty structs and empty arrays inside a struct
+%!testif HAVE_RAPIDJSON
+%! data = struct ('a', Inf, 'b', [], 'c', struct ());
+%! exp  = '{"a":null,"b":[],"c":{}}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% a big test
+%!testif HAVE_RAPIDJSON
+%! var1 = struct ('para', ['A meta-markup language, used to create ' ...
+%!                         'markup languages such as DocBook.'], ...
+%!                'GlossSeeAlso', {{'GML'; 'XML'}});
+%! var2 = struct ('ID', 'SGML', 'SortAs', 'SGML', ...
+%!                'GlossTerm', 'Standard Generalized Markup Language', ...
+%!                'Acronym', 'SGML', 'Abbrev', 'ISO 8879:1986', ...
+%!                'GlossDef', var1, 'GlossSee', 'markup');
+%! data  = struct ('glossary', ...
+%!                struct ('title', 'example glossary', ...
+%!                        'GlossDiv', struct ('title', 'S', ...
+%!                                            'GlossList', ...
+%!                                            struct ('GlossEntry', var2))));
+%! exp = ['{' , ...
+%!     '"glossary":{', ...
+%!         '"title":"example glossary",', ...
+%! 		'"GlossDiv":{', ...
+%!             '"title":"S",', ...
+%! 			'"GlossList":{', ...
+%!                 '"GlossEntry":{', ...
+%!                     '"ID":"SGML",', ...
+%! 					'"SortAs":"SGML",', ...
+%! 					'"GlossTerm":"Standard Generalized Markup Language",', ...
+%! 					'"Acronym":"SGML",', ...
+%! 					'"Abbrev":"ISO 8879:1986",', ...
+%! 					'"GlossDef":{', ...
+%!                         '"para":"A meta-markup language, ', ...
+%!                         'used to create markup languages such as DocBook.",', ...
+%! 						'"GlossSeeAlso":["GML","XML"]', ...
+%!                     '},', ...
+%! 					'"GlossSee":"markup"', ...
+%!                 '}', ...
+%!             '}', ...
+%!         '}', ...
+%!     '}', ...
+%! '}'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%%% Test 6: Encode struct arrays
+
+%!testif HAVE_RAPIDJSON
+%! data = struct ('structarray', struct ('a', {1; 3}, 'b', {2; 4}));
+%! exp  = '{"structarray":[{"a":1,"b":2},{"a":3,"b":4}]}';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% another big Test
+%!testif HAVE_RAPIDJSON
+%! var1 = struct ('id', {0; 1; 2}, 'name', {'Collins'; 'Hays'; 'Griffin'});
+%! var2 = struct ('id', {0; 1; 2}, 'name', {'Osborn'; 'Mcdowell'; 'Jewel'});
+%! var3 = struct ('id', {0; 1; 2}, 'name', {'Socorro'; 'Darla'; 'Leanne'});
+%! data = struct (...
+%!   'x_id', {'5ee28980fc9ab3'; '5ee28980dd7250'; '5ee289802422ac'}, ...
+%!   'index', {0; 1; 2}, ...
+%!   'guid', {'b229d1de-f94a'; '39cee338-01fb'; '3db8d55a-663e'}, ...
+%!   'latitude', {-17.124067; 13.205994; -35.453456}, ...
+%!   'longitude', {-61.161831; -37.276231; 14.080287}, ...
+%!   'friends', {var1; var2; var3});
+%! exp  = ['[', ...
+%!   '{', ...
+%!     '"x_id":"5ee28980fc9ab3",', ...
+%!     '"index":0,', ...
+%!     '"guid":"b229d1de-f94a",', ...
+%!     '"latitude":-17.124067,', ...
+%!     '"longitude":-61.161831,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Collins"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Hays"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Griffin"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{', ...
+%!     '"x_id":"5ee28980dd7250",', ...
+%!     '"index":1,', ...
+%!     '"guid":"39cee338-01fb",', ...
+%!     '"latitude":13.205994,', ...
+%!     '"longitude":-37.276231,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Jewel"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{', ...
+%!     '"x_id":"5ee289802422ac",', ...
+%!     '"index":2,', ...
+%!     '"guid":"3db8d55a-663e",', ...
+%!     '"latitude":-35.453456,', ...
+%!     '"longitude":14.080287,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Socorro"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Darla"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Leanne"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '}', ...
+%! ']'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%%% Test 7: encode cell arrays
+
+%!testif HAVE_RAPIDJSON
+%! assert (isequal (jsonencode ({}), '[]'));
+%! assert (isequal (jsonencode ({5}), '[5]'));
+%! assert (isequal (jsonencode ({'hello there'}), '["hello there"]'));
+
+%% Logical cell arrays
+%!testif HAVE_RAPIDJSON
+%! data = {'true', 'true'; 'false', 'true'};
+%! exp  = '["true","false","true","true"]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Cell array of character vectors
+%!testif HAVE_RAPIDJSON
+%! data = {'foo'; 'bar'; {'foo'; 'bar'}};
+%! exp  = '["foo","bar",["foo","bar"]]';
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% cell array of structs & a big test
+%!testif HAVE_RAPIDJSON
+%! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ...
+%!                'guid', 'b229d1de-f94a', 'latitude', -17.124067, ...
+%!                'longitude', -61.161831, ...
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Collins'; 'Hays'; 'Griffin'}));
+%! var2 = struct ('numericArray', {{'str'; 5; []}}, ...
+%!                'nonnumericArray', {[1; 2; NaN]});
+%! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ...
+%!                'address', ...
+%!                struct ('streetAddress', '21 2nd Street', ...
+%!                        'city', 'New York', 'state', 'NY'), ...
+%!                'phoneNumber', ...
+%!                struct ('type', 'home', 'number', '212 555-1234'));
+%! data = {var1; var2; var3};
+%! exp  = ['[', ...
+%!   '{', ...
+%!     '"x_id":"5ee28980fc9ab3",', ...
+%!     '"index":0,', ...
+%!     '"guid":"b229d1de-f94a",', ...
+%!     '"latitude":-17.124067,', ...
+%!     '"longitude":-61.161831,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Collins"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Hays"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Griffin"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '},', ...
+%!   '{"numericArray":["str",5,[]],"nonnumericArray":[1,2,null]},', ...
+%!   '{', ...
+%!      '"firstName":"John",', ...
+%!      '"lastName":"Smith",', ...
+%!      '"age":25,', ...
+%!      '"address":', ...
+%!      '{', ...
+%!          '"streetAddress":"21 2nd Street",', ...
+%!          '"city":"New York",', ...
+%!          '"state":"NY"', ...
+%!      '},', ...
+%!      '"phoneNumber":', ...
+%!          '{', ...
+%!            '"type":"home",', ...
+%!            '"number":"212 555-1234"', ...
+%!          '}', ...
+%!  '}]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% cell array of diferrent types & Customized encoding of Nan, Inf, -Inf
+%!testif HAVE_RAPIDJSON
+%! var =  struct ('x_id', '5ee28980dd7250', 'index', 1, ...
+%!                'guid', '39cee338-01fb', 'latitude', 13.205994, ...
+%!                'longitude', -37.276231,
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Osborn'; 'Mcdowell'; 'Jewel'}));
+%! data = {NaN; true; Inf; 2531.023; 'hello there'; var};
+%! exp  = ['[NaN,true,Infinity,2531.023,"hello there",', ...
+%!   '{', ...
+%!     '"x_id":"5ee28980dd7250",', ...
+%!     '"index":1,', ...
+%!     '"guid":"39cee338-01fb",', ...
+%!     '"latitude":13.205994,', ...
+%!     '"longitude":-37.276231,', ...
+%!     '"friends":[', ...
+%!       '{', ...
+%!         '"id":0,', ...
+%!         '"name":"Osborn"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":1,', ...
+%!         '"name":"Mcdowell"', ...
+%!       '},', ...
+%!       '{', ...
+%!         '"id":2,', ...
+%!         '"name":"Jewel"', ...
+%!       '}', ...
+%!     ']', ...
+%!   '}]'];
+%! obs  = jsonencode (data, 'ConvertInfAndNaN', false);
+%! assert (isequal (obs, exp));
+
+%% a big example
+%!testif HAVE_RAPIDJSON
+%! var1 = struct ('x_id', '5ee28980fc9ab3', 'index', 0, ...
+%!                'guid', 'b229d1de-f94a', 'latitude', -17.124067, ...
+%!                'longitude', -61.161831, ...
+%!                'friends', struct ('id', {0; 1; 2}, ...
+%!                                   'name', {'Collins'; 'Hays'; 'Griffin'}));
+%! var2 = struct ('numericArray', {{'str'; 5; -Inf}}, ...
+%!                'nonnumericArray', {[1; 2; NaN]});
+%! var3 = struct ('firstName', 'John', 'lastName', 'Smith', 'age', 25, ...
+%!                'address', ...
+%!                struct ('streetAddress', '21 2nd Street', ...
+%!                        'city', 'New York', 'state', 'NY'), ...
+%!                'phoneNumber', ...
+%!                struct ('type', 'home', 'number', '212 555-1234'));
+%! data = {{'str'; Inf; {}}; [1; 2; NaN]; {'foo'; 'bar'; {'foo'; 'bar'}};
+%!        cat(3, [1, 3; 5, 7], [2, 4; 6, 8]); {var1; var2 ;var3}};
+%! exp  = ['[["str",null,[]],[1,2,null],["foo","bar",["foo","bar"]],', ...
+%!   '[[[1,2],[3,4]],[[5,6],[7,8]]],' , ...
+%!   '[', ...
+%!     '{', ...
+%!       '"x_id":"5ee28980fc9ab3",', ...
+%!       '"index":0,', ...
+%!       '"guid":"b229d1de-f94a",', ...
+%!       '"latitude":-17.124067,', ...
+%!       '"longitude":-61.161831,', ...
+%!       '"friends":[', ...
+%!         '{', ...
+%!           '"id":0,', ...
+%!           '"name":"Collins"', ...
+%!         '},', ...
+%!         '{', ...
+%!           '"id":1,', ...
+%!           '"name":"Hays"', ...
+%!         '},', ...
+%!         '{', ...
+%!           '"id":2,', ...
+%!           '"name":"Griffin"', ...
+%!         '}', ...
+%!       ']', ...
+%!     '},', ...
+%!     '{"numericArray":["str",5,null],"nonnumericArray":[1,2,null]},', ...
+%!     '{', ...
+%!        '"firstName":"John",', ...
+%!        '"lastName":"Smith",', ...
+%!        '"age":25,', ...
+%!        '"address":', ...
+%!        '{', ...
+%!            '"streetAddress":"21 2nd Street",', ...
+%!            '"city":"New York",', ...
+%!            '"state":"NY"', ...
+%!        '},', ...
+%!        '"phoneNumber":', ...
+%!            '{', ...
+%!              '"type":"home",', ...
+%!              '"number":"212 555-1234"', ...
+%!            '}', ...
+%!    '}]]'];
+%! obs  = jsonencode (data);
+%! assert (isequal (obs, exp));
+
+%% Just basic tests to ensure option "PrettyPrint" is functional. 
+%!testif HAVE_RAPIDJSON_PRETTYWRITER
+%! data = {'Hello'; 'World!'};
+%! exp  = do_string_escapes ([ '[\n', ...
+%!                             '  "Hello",\n', ...
+%!                             '  "World!"\n', ...
+%!                             ']' ]);
+%! obs  = jsonencode (data, 'PrettyPrint', true);
+%! assert (isequal (obs, exp));
+%!
+%! exp  = '["Hello","World!"]';
+%! obs  = jsonencode (data, 'PrettyPrint', false);
+%! assert (isequal (obs, exp));
+
+%!testif HAVE_RAPIDJSON_PRETTYWRITER
+%! data = [1, 2; 3, 4];
+%! exp  = do_string_escapes ([ ...
+%! '[\n'                       ...
+%! '  [\n'                   ...
+%! '    1,\n'              ...
+%! '    2\n'               ...
+%! '  ],\n'                  ...
+%! '  [\n'                   ...
+%! '    3,\n'              ...
+%! '    4\n'               ...
+%! '  ]\n'                   ...
+%! ']' ]);
+%! obs  = jsonencode (data, 'PrettyPrint', true);
+%! assert (isequal (obs, exp));
+%!
+%! exp  = '[[1,2],[3,4]]';
+%! obs  = jsonencode (data, 'PrettyPrint', false);
+%! assert (isequal (obs, exp));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/json/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -0,0 +1,5 @@
+json_TEST_FILES = \
+  %reldir%/jsondecode_BIST.tst \
+  %reldir%/jsonencode_BIST.tst
+
+TEST_FILES += $(json_TEST_FILES)
--- a/test/line-continue.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/line-continue.tst	Sun May 16 09:44:35 2021 +0200
@@ -61,7 +61,7 @@
 %!
 %!assert (f (), 1)
 
-# String continuation using '\'
+## String continuation using '\'
 %!assert (["abc\
 %! def"], "abc def")
 
--- a/test/mex/bug-51725.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/mex/bug-51725.tst	Sun May 16 09:44:35 2021 +0200
@@ -24,4 +24,5 @@
 ########################################################################
 
 %!assert (bug_51725 (), [])
+## Note: ';' is required to suppress output
 %!error <element number 2 undefined in return list> [x,y,z] = bug_51725 ();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/mex/mexnumtst.c	Sun May 16 09:44:35 2021 +0200
@@ -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	Sun May 16 09:44:35 2021 +0200
@@ -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	Sun May 16 09:43:43 2021 +0200
+++ b/test/mex/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -1,11 +1,13 @@
 mex_TEST_FILES = \
   %reldir%/bug-54096.tst \
   %reldir%/bug-51725.tst \
+  %reldir%/mexnumtst.tst \
   $(MEX_TEST_SRC)
 
 MEX_TEST_SRC = \
   %reldir%/bug_54096.c \
-  %reldir%/bug_51725.c
+  %reldir%/bug_51725.c \
+  %reldir%/mexnumtst.c
 
 MEX_TEST_FUNCTIONS = $(MEX_TEST_SRC:%.c=%.mex)
 
--- a/test/mk-conv-tst.sh	Sun May 16 09:43:43 2021 +0200
+++ b/test/mk-conv-tst.sh	Sun May 16 09:44:35 2021 +0200
@@ -28,7 +28,7 @@
 cat <<EOF
 ## !!! DO NOT EDIT !!!
 ## THIS IS AN AUTOMATICALLY GENERATED FILE
-## modify build-conv-tests.sh to generate the tests you need.
+## modify mk-conv-tst.sh to generate the tests you need.
 
 
 %!shared r,dq,sq,b,bm,dm,cdm,fdm,fcdm,pm,sm,sbm,scm,s,m,cs,cm,fs,fm,fcs,fcm,i8s,i16s,i32s,i64s,i8m,i16m,i32m,i64m,ui8s,ui16s,ui32s,ui64s,ui8m,ui16m,ui32m,ui64m
@@ -71,7 +71,12 @@
 %! ui32m = uint32 (rand (5) * 10);
 %! ui64m = uint64 (rand (5) * 10);
 %!
-%!assert (typeinfo (r), "range")
+%!test
+%! if (disable_range ())
+%!   assert (typeinfo (r), "matrix")
+%! else
+%!   assert (typeinfo (r), "range")
+%! endif
 %!assert (typeinfo (dq), "string")
 %!assert (typeinfo (sq), "sq_string")
 %!assert (typeinfo (b), "bool")
--- a/test/mk-sparse-tst.sh	Sun May 16 09:43:43 2021 +0200
+++ b/test/mk-sparse-tst.sh	Sun May 16 09:44:35 2021 +0200
@@ -216,7 +216,7 @@
 %!assert (nnz (sparse (1,1,0)), 0)
 %!assert (nnz (sparse (eye (3))*0), 0)
 %!assert (nnz (sparse (eye (3))-sparse (eye (3))), 0)
-%!assert (full (sparse (eye (3))/0), full (eye (3)/0));
+%!assert (full (sparse (eye (3))/0), full (eye (3)/0))
 
 EOF
 }
@@ -576,8 +576,8 @@
 %!assert (as',  sparse (af'))
 %!assert (-as, sparse (-af))
 %!assert (!as, sparse (!af))
-%!error [i,j] = size (af);as(i-1,j+1);
-%!error [i,j] = size (af);as(i+1,j-1);
+%!error [i,j] = size (af);as(i-1,j+1)
+%!error [i,j] = size (af);as(i+1,j-1)
 %!test
 %! [Is,Js,Vs] = find (as);
 %! [If,Jf,Vf] = find (af);
--- a/test/mk_bc_overloads_expected.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/mk_bc_overloads_expected.m	Sun May 16 09:44:35 2021 +0200
@@ -1,9 +1,9 @@
-% this script is intended to be Matlab compatible
-% first, run the script
+%% this script is intended to be Matlab compatible
+%% first, run the script
 %
-%   ./build_bc_overloads_tests.sh overloads_only
+%%   ./build_bc_overloads_tests.sh overloads_only
 %
-% to generate the overloaded functions.
+%% to generate the overloaded functions.
 %
 ex.double = 1;
 ex.single = single (1);
--- a/test/module.mk	Sun May 16 09:43:43 2021 +0200
+++ b/test/module.mk	Sun May 16 09:44:35 2021 +0200
@@ -8,6 +8,7 @@
   %reldir%/fntests.m \
   %reldir%/args.tst \
   %reldir%/bug-31371.tst \
+  %reldir%/bug-40117.tst \
   %reldir%/bug-45969.tst \
   %reldir%/bug-45972.tst \
   %reldir%/bug-46330.tst \
@@ -18,6 +19,7 @@
   %reldir%/bug-55308.tst \
   %reldir%/bug-55321.tst \
   %reldir%/bug-55322.tst \
+  %reldir%/bug-59950.tst \
   %reldir%/colormaps.tst \
   %reldir%/command.tst \
   %reldir%/complex.tst \
@@ -83,6 +85,7 @@
 include %reldir%/bug-53956/module.mk
 include %reldir%/bug-54995/module.mk
 include %reldir%/bug-55758/module.mk
+include %reldir%/bug-56068/module.mk
 include %reldir%/bug-58572/module.mk
 include %reldir%/bug-58593/module.mk
 include %reldir%/bug-59451/module.mk
@@ -95,8 +98,10 @@
 include %reldir%/classdef/module.mk
 include %reldir%/classdef-multiple-inheritance/module.mk
 include %reldir%/classes/module.mk
+include %reldir%/colon-op/module.mk
 include %reldir%/ctor-vs-method/module.mk
 include %reldir%/fcn-handle/module.mk
+include %reldir%/json/module.mk
 include %reldir%/local-functions/module.mk
 include %reldir%/mex/module.mk
 include %reldir%/nest/module.mk
--- a/test/nest/arg_nest.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/arg_nest.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# arg_nest.m
+## arg_nest.m
 function x = arg_nest
   x = 1;
   A (x);
--- a/test/nest/nest.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/nest.tst	Sun May 16 09:44:35 2021 +0200
@@ -41,7 +41,7 @@
 ##        worked.  The output of "script_nest" is unassigned. This got
 ##        revealed by fixing bug #58686.
 
-%!xtest <*58691> assert (script_nest (), 5)
+%!test <*58691> assert (script_nest (), 5)
 
 %!assert (arg_ret (), 10)
 
@@ -156,7 +156,7 @@
 %! assert (observed, [1, 2, 1, 3, 2]);
 
 ## Test visibility of nested function from script called from parent.
-%!assert (script_nest_2 (42), 84);
+%!assert (script_nest_2 (42), 84)
 %!error script_nest_2 (0)
 
 %!assert (bug_59989 (), 6)
--- a/test/nest/no_closure.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/no_closure.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# no_closure.m
+## no_closure.m
 function r = no_closure (n)
   if (ischar (n))
     r = nested (n);
--- a/test/nest/persistent_nest.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/persistent_nest.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# persistent_nest
+## persistent_nest
 function y = persistent_nest ()
   persistent x = 0;
   g;
--- a/test/nest/recursive_nest.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/recursive_nest.m	Sun May 16 09:44:35 2021 +0200
@@ -1,11 +1,11 @@
-# recursive_nest.m
+## recursive_nest.m
 function x = recursive_nest ()
   global recursive_nest_inc = 1
   x = 5;
   f (20);
 
   function f (n)
-    if n > 0
+    if (n > 0)
       x = x + recursive_nest_inc;
       f (n - 1);
     end
--- a/test/nest/recursive_nest2.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/recursive_nest2.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# recursive_nest2.m
+## recursive_nest2.m
 function x = recursive_nest2 ()
   x = B (20);
   function v = B (n)
@@ -7,7 +7,7 @@
     C;
     v = Y;
     function BB (m)
-      if m > 0
+      if (m > 0)
         Y = Y + 1;
         BB(m - 1);
         C;
--- a/test/nest/scope0.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/scope0.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# scope0.m
+## scope0.m
 function scope0
   C;
   function A
--- a/test/nest/scope1.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/scope1.m	Sun May 16 09:44:35 2021 +0200
@@ -1,7 +1,7 @@
-# scope1.m
+## scope1.m
 function scope1 (n)
   value = n;
-  if value
+  if (value)
     C;
   end
   function A
--- a/test/nest/scope2.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/scope2.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# scope2.m
+## scope2.m
 function scope2
   C;
   function A
--- a/test/nest/scope3.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/scope3.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# scope3.m
+## scope3.m
 function scope3
   C;
   function A
--- a/test/nest/script_nest.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/script_nest.m	Sun May 16 09:44:35 2021 +0200
@@ -1,8 +1,8 @@
-# script_nest.m
+## script_nest.m
 function x = script_nest
   A (5)
   function A (n)
-    if n <= 0
+    if (n <= 0)
       script_nest_script;
     else
       A (n - 1);
--- a/test/nest/script_nest_2.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/script_nest_2.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# script_nest.m
+## script_nest.m
 function r = script_nest_2 (x)
   function r = nest_fun ()
     r = 13;
--- a/test/nest/script_nest_script.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/script_nest_script.m	Sun May 16 09:44:35 2021 +0200
@@ -1,2 +1,2 @@
-# script_nest_script.m
+## script_nest_script.m
 x = 5;
--- a/test/nest/script_nest_script_2.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/script_nest_script_2.m	Sun May 16 09:44:35 2021 +0200
@@ -1,4 +1,4 @@
-# script_nest_script.m
+## script_nest_script.m
 if (x > 0)
   r = x * 2;
 else
--- a/test/nest/varg_nest2.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/nest/varg_nest2.m	Sun May 16 09:44:35 2021 +0200
@@ -2,12 +2,12 @@
   [a, b] = f;
   x = a;
 
-  if nargout == 1
+  if (nargout == 1)
     x = a;
   endif
 
   function [a, b] = f
-    if nargout == 2
+    if (nargout == 2)
       a = b = 5;
     endif
   endfunction
--- a/test/parser.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/parser.tst	Sun May 16 09:44:35 2021 +0200
@@ -104,7 +104,7 @@
 %! assert (2 ^++a, 8);
 %! assert (a, 3);
 %! assert (a' ^2, 9);
-%! assert (2 ^sin(0), 1);
+%! assert (2 ^sin (0), 1);
 %! assert (-2 ^2, -4);;
 %! assert (2 ^+1 ^3, 8);
 %! assert (2 ^-1 ^3, 0.125);
@@ -214,7 +214,7 @@
 ## Level 13 (parentheses and indexing)
 %!test
 %! a.b1 = 2;
-%! assert (a.(strcat('b','1'))++, 2);
+%! assert (a.(strcat ('b','1'))++, 2);
 %! assert (a.b1, 3);
 %! b = {1 2 3 4 5};
 %! assert (b{(a. b1 + 1)}, 4);
@@ -286,19 +286,19 @@
 %!assert (123_456, 123456)
 %!assert (.123_456, .123456)
 %!assert (123_456.123_456, 123456.123456)
-%!assert (0xAB_CD, 43981)
+%!assert (0xAB_CD, uint16 (43981))
 %!assert (2e0_1, 20)
 
 ## Test binary constants
-%!assert (0b101, 5)
+%!assert (0b101, uint8 (5))
 %!assert (0B1100_0001, 0xC1)
-%!assert (class (0b1), "double")
+%!assert (class (0b1), "uint8")
 
 ## Test range of large binary and hexadecimal literals
-%!assert (0x8000_0000_0000_0000, 2^63)
-%!assert (0xFFFF_FFFF_FFFF_FFFF, 2^64)
-%!assert (0b10000000_0000000_000000000_00000000_00000000_00000000_00000000_00000000, 2^63)
-%!assert (0b11111111_1111111_111111111_11111111_11111111_11111111_11111111_11111111, 2^64)
+%!assert (0x8000_0000_0000_0000, uint64 (2^63))
+%!assert (0xFFFF_FFFF_FFFF_FFFF, uint64 (2^64))
+%!assert (0b10000000_0000000_000000000_00000000_00000000_00000000_00000000_00000000, uint64 (2^63))
+%!assert (0b11111111_1111111_111111111_11111111_11111111_11111111_11111111_11111111, uint64 (2^64))
 
 ## Test creation of anonymous functions
 
@@ -335,7 +335,7 @@
 #!error <vertical dimensions mismatch \(1x2 vs 1x1\)> z = [1, 2; 3]
 
 %!test
-%! f = @(s,t=toeplitz(s),u=t(x=2:end-1,x)=32)t;
+%! f = @(s,t=toeplitz (s),u=t(x=2:end-1,x)=32)t;
 %! assert (f (1), 1);
 %! assert (f (1, 2), 2);
 
--- a/test/pkg/pkg.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/pkg/pkg.tst	Sun May 16 09:44:35 2021 +0200
@@ -31,6 +31,11 @@
 
 %!shared old_prefix, old_archprefix, old_local_list, old_global_list, prefix, restorecfg, restorecache, restoreglobalcache, rmtmpdir, mfile_pkg_name, mfile_pkg_tgz
 
+%!function test_cleanup (prefix)
+%! confirm_recursive_rmdir (0, "local");
+%! sts = rmdir (prefix, "s");
+%!endfunction
+
 %!testif HAVE_Z
 %! ## Do all tests in a temporary directory
 %! [old_prefix, old_archprefix] = pkg ("prefix");
@@ -48,7 +53,7 @@
 %! pkg ("prefix", prefix, prefix);
 %! pkg ("local_list", fullfile (prefix, "octave_packages"));
 %! pkg ("global_list", fullfile (prefix, "octave_packages"));
-%! rmtmpdir = @onCleanup (@() confirm_recursive_rmdir (0, "local") && rmdir (prefix, "s"));
+%! rmtmpdir = @onCleanup (@() test_cleanup (prefix));
 %!
 %! ## Create tar.gz file packages of testing directories in prefix directory
 %! mfile_pkg_name = {"mfile_basic_test", "mfile_minimal_test"};
@@ -74,7 +79,7 @@
 %!
 %!error pkg ("install", "nonexistent.zip")
 
-# -local
+## -local
 %!testif HAVE_Z
 %! for i = 1:numel (mfile_pkg_name)
 %!   silent_pkg_install ("-local", mfile_pkg_tgz{i});
@@ -82,18 +87,18 @@
 %!   pkg ("uninstall", mfile_pkg_name{i});
 %! endfor
 
-# -forge (need check for options?)
+## -forge (need check for options?)
 ## FIXME: Need test
-# We do not test this yet ... fails if no internet connection
-# use dataframe which is an mfile only package
+## We do not test this yet ... fails if no internet connection
+## use dataframe which is an mfile only package
 #%!test
 #%! silent_pkg_install ("-forge", "dataframe");
 #%! pkg ("uninstall", "dataframe");
 
-# -nodeps
+## -nodeps
 ## FIXME: Need test
 
-# -verbose
+## -verbose
 ## FIXME: Need test
 
 ## Action load/unload (within install/uninstall)
@@ -111,19 +116,19 @@
 %!   end_unwind_protect
 %! endfor
 %!
-%!error <package foobar is not installed> pkg ("load", "foobar");
+%!error <package foobar is not installed> pkg ("load", "foobar")
 
-# -nodeps
+## -nodeps
 ## FIXME: Need test
 
-# -verbose
+## -verbose
 ## FIXME: Need test
 
 ## Action list
 %!test
 %! [user_packages, system_packages] = pkg ("list");
 
-# -forge
+## -forge
 #%!test
 #%! oct_forge_pkgs = pkg ("list", "-forge");
 
@@ -136,7 +141,7 @@
 %! system (["chmod -Rf u+w '" prefix "'"]);     ## FIXME: Work around bug #53578
 %! pkg ("uninstall", mfile_pkg_name{1});
 
-# -verbose
+## -verbose
 ## FIXME: Need test
 
 ## Action prefix
@@ -151,11 +156,11 @@
 
 ## Action build
 ## FIXME: Need test
-# pkg build -verbose /tmp image-*
+## pkg build -verbose /tmp image-*
 
 ## Action rebuild
 ## FIXME: Need test
-# pkg rebuild signal
+## pkg rebuild signal
 
 ## Future commands
 %!error pkg ("whereis", "myfunc.m")
--- a/test/publish/publish.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/publish/publish.tst	Sun May 16 09:44:35 2021 +0200
@@ -49,7 +49,7 @@
 %!     publish (fname{1}, opts);
 %!   endfor
 %!   confirm_recursive_rmdir (false, "local");
-%!   rmdir (tmpDir, "s");
+%!   sts = rmdir (tmpDir, "s");
 %! unwind_protect_cleanup
 %!   set (0, "defaultfigurevisible", visibility);
 %!   graphics_toolkit (toolkit);
@@ -81,7 +81,7 @@
 %!   str1 = fileread ("test_script.m");
 %!   str2 = grabcode (fullfile (tmpDir, "test_script.html"));
 %!   confirm_recursive_rmdir (false, "local");
-%!   rmdir (tmpDir, "s");
+%!   sts = rmdir (tmpDir, "s");
 %!   ## Canonicalize strings
 %!   str1 = strjoin (deblank (strsplit (str1, "\n")), "\n");
 %!   str2 = strjoin (deblank (strsplit (str2, "\n")), "\n");
--- a/test/publish/test_script.m	Sun May 16 09:43:43 2021 +0200
+++ b/test/publish/test_script.m	Sun May 16 09:44:35 2021 +0200
@@ -32,7 +32,7 @@
 i = 0:2*pi
 
 # some real comment
-y = sin(i)
+y = sin (i)
 
 %%
 %
@@ -43,16 +43,16 @@
 x = 0:2*pi
 
 # some real comment and split code block
-y = sin(x)
+y = sin (x)
 
 %%
 %
 
 % reusing old values
-y = cos(i)
+y = cos (i)
 
 # some real comment and split code block
-y = cos(x)
+y = cos (x)
 
 %% Text formatting
 % PLAIN TEXT _ITALIC TEXT_ *BOLD TEXT* |MONOSPACED TEXT|
--- a/test/range.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/range.tst	Sun May 16 09:44:35 2021 +0200
@@ -163,3 +163,330 @@
 %!test <*46859>
 %! rng = 1 : (1001/250)/(1/250);
 %! assert (numel (1000));
+
+## Combinations of exceptional values and a few normal ones.
+
+%!shared mt_row, inf, nan, zero, pt3, pt6, pt9, one, epsilon
+%! mt_row = zeros (1, 0, 'double');
+%! inf = Inf ('double');
+%! nan = NaN ('double');
+%! zero = double (0.0);
+%! pt3 = double (0.3);
+%! pt6 = double (0.6);
+%! pt9 = double (0.9);
+%! one = double (1.0);
+%! epsilon = eps ('double');
+%!assert <*59229> (nan:-pt3:-one, nan)
+%!assert <*59229> (nan:-pt3:-inf, nan)
+%!assert <*59229> (nan:-pt3:zero, nan)
+%!assert <*59229> (nan:-pt3:one, nan)
+%!assert <*59229> (nan:-pt3:inf, nan)
+%!assert <*59229> (nan:-pt3:nan, nan)
+%!assert <*59229> (nan:-inf:-one, nan)
+%!assert <*59229> (nan:-inf:-inf, nan)
+%!assert <*59229> (nan:-inf:zero, nan)
+%!assert <*59229> (nan:-inf:one, nan)
+%!assert <*59229> (nan:-inf:inf, nan)
+%!assert <*59229> (nan:-inf:nan, nan)
+%!assert <*59229> (nan:zero:-one, nan)
+%!assert <*59229> (nan:zero:-inf, nan)
+%!assert <*59229> (nan:zero:zero, nan)
+%!assert <*59229> (nan:zero:one, nan)
+%!assert <*59229> (nan:zero:inf, nan)
+%!assert <*59229> (nan:zero:nan, nan)
+%!assert <*59229> (nan:pt3:-one, nan)
+%!assert <*59229> (nan:pt3:-inf, nan)
+%!assert <*59229> (nan:pt3:zero, nan)
+%!assert <*59229> (nan:pt3:one, nan)
+%!assert <*59229> (nan:pt3:inf, nan)
+%!assert <*59229> (nan:pt3:nan, nan)
+%!assert <*59229> (nan:inf:-one, nan)
+%!assert <*59229> (nan:inf:-inf, nan)
+%!assert <*59229> (nan:inf:zero, nan)
+%!assert <*59229> (nan:inf:one, nan)
+%!assert <*59229> (nan:inf:inf, nan)
+%!assert <*59229> (nan:inf:nan, nan)
+%!assert <*59229> (nan:nan:-one, nan)
+%!assert <*59229> (nan:nan:-inf, nan)
+%!assert <*59229> (nan:nan:zero, nan)
+%!assert <*59229> (nan:nan:one, nan)
+%!assert <*59229> (nan:nan:inf, nan)
+%!assert <*59229> (nan:nan:nan, nan)
+%!assert <*59229> (-inf:-pt3:nan, nan)
+%!assert <*59229> (-inf:-inf:nan, nan)
+%!assert <*59229> (-inf:zero:nan, nan)
+%!assert <*59229> (-inf:pt3:nan, nan)
+%!assert <*59229> (-inf:inf:nan, nan)
+%!assert <*59229> (zero:-pt3:nan, nan)
+%!assert <*59229> (zero:-inf:nan, nan)
+%!assert <*59229> (zero:zero:nan, nan)
+%!assert <*59229> (zero:pt3:nan, nan)
+%!assert <*59229> (zero:inf:nan, nan)
+%!assert <*59229> (inf:-pt3:nan, nan)
+%!assert <*59229> (inf:-inf:nan, nan)
+%!assert <*59229> (inf:zero:nan, nan)
+%!assert <*59229> (inf:pt3:nan, nan)
+%!assert <*59229> (inf:inf:nan, nan)
+%!assert <*59229> (-inf:nan:-one, nan)
+%!assert <*59229> (-inf:nan:-inf, nan)
+%!assert <*59229> (-inf:nan:zero, nan)
+%!assert <*59229> (-inf:nan:one, nan)
+%!assert <*59229> (-inf:nan:inf, nan)
+%!assert <*59229> (-inf:nan:nan, nan)
+%!assert <*59229> (zero:nan:-one, nan)
+%!assert <*59229> (zero:nan:-inf, nan)
+%!assert <*59229> (zero:nan:zero, nan)
+%!assert <*59229> (zero:nan:one, nan)
+%!assert <*59229> (zero:nan:inf, nan)
+%!assert <*59229> (zero:nan:nan, nan)
+%!assert <*59229> (inf:nan:-one, nan)
+%!assert <*59229> (inf:nan:-inf, nan)
+%!assert <*59229> (inf:nan:zero, nan)
+%!assert <*59229> (inf:nan:one, nan)
+%!assert <*59229> (inf:nan:inf, nan)
+%!assert <*59229> (inf:nan:nan, nan)
+%!assert <*59229> (inf:-pt3:inf, nan)
+%!assert <*59229> (-inf:-pt3:-inf, nan)
+%!assert <*59229> (inf:pt3:inf, nan)
+%!assert <*59229> (-inf:pt3:-inf, nan)
+%!assert <*59229> (-inf:-inf:-inf, nan)
+%!assert <*59229> (zero:-inf:-inf, nan)
+%!assert <*59229> (inf:-inf:-one, nan)
+%!assert <*59229> (inf:-inf:-inf, nan)
+%!assert <*59229> (inf:-inf:zero, nan)
+%!assert <*59229> (inf:-inf:one, nan)
+%!assert <*59229> (inf:-inf:inf, nan)
+%!assert <*59229> (-inf:inf:-one, nan)
+%!assert <*59229> (-inf:inf:-inf, nan)
+%!assert <*59229> (-inf:inf:zero, nan)
+%!assert <*59229> (-inf:inf:one, nan)
+%!assert <*59229> (-inf:inf:inf, nan)
+%!assert <*59229> (zero:inf:inf, nan)
+%!assert <*59229> (inf:inf:inf, nan)
+%!assert <*59229> (zero:zero:-one, mt_row)
+%!assert <*59229> (zero:zero:zero, mt_row)
+%!assert <*59229> (zero:zero:one, mt_row)
+%!assert <*59229> (zero:zero:-inf, mt_row)
+%!assert <*59229> (zero:zero:inf, mt_row)
+%!assert <*59229> (-inf:zero:-one, mt_row)
+%!assert <*59229> (-inf:zero:zero, mt_row)
+%!assert <*59229> (-inf:zero:one, mt_row)
+%!assert <*59229> (-inf:zero:-inf, mt_row)
+%!assert <*59229> (-inf:zero:inf, mt_row)
+%!assert <*59229> (inf:zero:-one, mt_row)
+%!assert <*59229> (inf:zero:zero, mt_row)
+%!assert <*59229> (inf:zero:one, mt_row)
+%!assert <*59229> (inf:zero:-inf, mt_row)
+%!assert <*59229> (inf:zero:inf, mt_row)
+%!assert <*59229> (zero:pt3:-one, mt_row)
+%!assert <*59229> (zero:pt3:-inf, mt_row)
+%!assert <*59229> (inf:pt3:-one, mt_row)
+%!assert <*59229> (inf:pt3:zero, mt_row)
+%!assert <*59229> (inf:pt3:one, mt_row)
+%!assert <*59229> (inf:pt3:-inf, mt_row)
+%!assert <*59229> (zero:inf:-one, mt_row)
+%!assert <*59229> (zero:inf:-inf, mt_row)
+%!assert <*59229> (inf:inf:-one, mt_row)
+%!assert <*59229> (inf:inf:zero, mt_row)
+%!assert <*59229> (inf:inf:one, mt_row)
+%!assert <*59229> (inf:inf:-inf, mt_row)
+%!assert <*59229> (zero:-pt3:one, mt_row)
+%!assert <*59229> (zero:-pt3:inf, mt_row)
+%!assert <*59229> (-inf:-pt3:-one, mt_row)
+%!assert <*59229> (-inf:-pt3:zero, mt_row)
+%!assert <*59229> (-inf:-pt3:one, mt_row)
+%!assert <*59229> (-inf:-pt3:inf, mt_row)
+%!assert <*59229> (zero:-inf:one, mt_row)
+%!assert <*59229> (zero:-inf:inf, mt_row)
+%!assert <*59229> (-inf:-inf:-one, mt_row)
+%!assert <*59229> (-inf:-inf:zero, mt_row)
+%!assert <*59229> (-inf:-inf:one, mt_row)
+%!assert <*59229> (-inf:-inf:inf, mt_row)
+%!assert <*59229> (zero:-inf:-one, zero)
+%!assert <*59229> (zero:-inf:zero, zero)
+%!assert <*59229> (zero:inf:zero, zero)
+%!assert <*59229> (zero:inf:one, zero)
+%!assert <*59229> (zero:-pt3:zero, zero)
+%!assert <*59229> (zero:pt3:zero, zero)
+%!assert <*59229> (zero:-pt3:-one, [zero, -pt3, -pt6, -pt9], epsilon)
+%!assert <*59229> (zero:pt3:one, [zero, pt3, pt6, pt9], epsilon)
+%!error <range with infinite number of elements cannot be stored> zero:-pt3:-inf
+%!error <range with infinite number of elements cannot be stored> inf:-pt3:-one
+%!error <range with infinite number of elements cannot be stored> inf:-pt3:zero
+%!error <range with infinite number of elements cannot be stored> inf:-pt3:one
+%!error <range with infinite number of elements cannot be stored> inf:-pt3:-inf
+%!error <range with infinite number of elements cannot be stored> zero:pt3:inf
+%!error <range with infinite number of elements cannot be stored> -inf:pt3:-one
+%!error <range with infinite number of elements cannot be stored> -inf:pt3:zero
+%!error <range with infinite number of elements cannot be stored> -inf:pt3:one
+%!error <range with infinite number of elements cannot be stored> -inf:pt3:inf
+
+## Again, this time with singles.
+%!shared mt_row, inf, nan, zero, pt3, pt6, pt9, one, epsilon
+%! mt_row = zeros (1, 0, 'single');
+%! inf = Inf ('single');
+%! nan = NaN ('single');
+%! zero = single (0.0);
+%! pt3 = single (0.3);
+%! pt6 = single (0.6);
+%! pt9 = single (0.9);
+%! one = single (1.0);
+%! epsilon = eps ('single');
+%!assert <*59229> (nan:-pt3:-one, nan)
+%!assert <*59229> (nan:-pt3:-inf, nan)
+%!assert <*59229> (nan:-pt3:zero, nan)
+%!assert <*59229> (nan:-pt3:one, nan)
+%!assert <*59229> (nan:-pt3:inf, nan)
+%!assert <*59229> (nan:-pt3:nan, nan)
+%!assert <*59229> (nan:-inf:-one, nan)
+%!assert <*59229> (nan:-inf:-inf, nan)
+%!assert <*59229> (nan:-inf:zero, nan)
+%!assert <*59229> (nan:-inf:one, nan)
+%!assert <*59229> (nan:-inf:inf, nan)
+%!assert <*59229> (nan:-inf:nan, nan)
+%!assert <*59229> (nan:zero:-one, nan)
+%!assert <*59229> (nan:zero:-inf, nan)
+%!assert <*59229> (nan:zero:zero, nan)
+%!assert <*59229> (nan:zero:one, nan)
+%!assert <*59229> (nan:zero:inf, nan)
+%!assert <*59229> (nan:zero:nan, nan)
+%!assert <*59229> (nan:pt3:-one, nan)
+%!assert <*59229> (nan:pt3:-inf, nan)
+%!assert <*59229> (nan:pt3:zero, nan)
+%!assert <*59229> (nan:pt3:one, nan)
+%!assert <*59229> (nan:pt3:inf, nan)
+%!assert <*59229> (nan:pt3:nan, nan)
+%!assert <*59229> (nan:inf:-one, nan)
+%!assert <*59229> (nan:inf:-inf, nan)
+%!assert <*59229> (nan:inf:zero, nan)
+%!assert <*59229> (nan:inf:one, nan)
+%!assert <*59229> (nan:inf:inf, nan)
+%!assert <*59229> (nan:inf:nan, nan)
+%!assert <*59229> (nan:nan:-one, nan)
+%!assert <*59229> (nan:nan:-inf, nan)
+%!assert <*59229> (nan:nan:zero, nan)
+%!assert <*59229> (nan:nan:one, nan)
+%!assert <*59229> (nan:nan:inf, nan)
+%!assert <*59229> (nan:nan:nan, nan)
+%!assert <*59229> (-inf:-pt3:nan, nan)
+%!assert <*59229> (-inf:-inf:nan, nan)
+%!assert <*59229> (-inf:zero:nan, nan)
+%!assert <*59229> (-inf:pt3:nan, nan)
+%!assert <*59229> (-inf:inf:nan, nan)
+%!assert <*59229> (zero:-pt3:nan, nan)
+%!assert <*59229> (zero:-inf:nan, nan)
+%!assert <*59229> (zero:zero:nan, nan)
+%!assert <*59229> (zero:pt3:nan, nan)
+%!assert <*59229> (zero:inf:nan, nan)
+%!assert <*59229> (inf:-pt3:nan, nan)
+%!assert <*59229> (inf:-inf:nan, nan)
+%!assert <*59229> (inf:zero:nan, nan)
+%!assert <*59229> (inf:pt3:nan, nan)
+%!assert <*59229> (inf:inf:nan, nan)
+%!assert <*59229> (-inf:nan:-one, nan)
+%!assert <*59229> (-inf:nan:-inf, nan)
+%!assert <*59229> (-inf:nan:zero, nan)
+%!assert <*59229> (-inf:nan:one, nan)
+%!assert <*59229> (-inf:nan:inf, nan)
+%!assert <*59229> (-inf:nan:nan, nan)
+%!assert <*59229> (zero:nan:-one, nan)
+%!assert <*59229> (zero:nan:-inf, nan)
+%!assert <*59229> (zero:nan:zero, nan)
+%!assert <*59229> (zero:nan:one, nan)
+%!assert <*59229> (zero:nan:inf, nan)
+%!assert <*59229> (zero:nan:nan, nan)
+%!assert <*59229> (inf:nan:-one, nan)
+%!assert <*59229> (inf:nan:-inf, nan)
+%!assert <*59229> (inf:nan:zero, nan)
+%!assert <*59229> (inf:nan:one, nan)
+%!assert <*59229> (inf:nan:inf, nan)
+%!assert <*59229> (inf:nan:nan, nan)
+%!assert <*59229> (inf:-pt3:inf, nan)
+%!assert <*59229> (-inf:-pt3:-inf, nan)
+%!assert <*59229> (inf:pt3:inf, nan)
+%!assert <*59229> (-inf:pt3:-inf, nan)
+%!assert <*59229> (-inf:-inf:-inf, nan)
+%!assert <*59229> (zero:-inf:-inf, nan)
+%!assert <*59229> (inf:-inf:-one, nan)
+%!assert <*59229> (inf:-inf:-inf, nan)
+%!assert <*59229> (inf:-inf:zero, nan)
+%!assert <*59229> (inf:-inf:one, nan)
+%!assert <*59229> (inf:-inf:inf, nan)
+%!assert <*59229> (-inf:inf:-one, nan)
+%!assert <*59229> (-inf:inf:-inf, nan)
+%!assert <*59229> (-inf:inf:zero, nan)
+%!assert <*59229> (-inf:inf:one, nan)
+%!assert <*59229> (-inf:inf:inf, nan)
+%!assert <*59229> (zero:inf:inf, nan)
+%!assert <*59229> (inf:inf:inf, nan)
+%!assert <*59229> (zero:zero:-one, mt_row)
+%!assert <*59229> (zero:zero:zero, mt_row)
+%!assert <*59229> (zero:zero:one, mt_row)
+%!assert <*59229> (zero:zero:-inf, mt_row)
+%!assert <*59229> (zero:zero:inf, mt_row)
+%!assert <*59229> (-inf:zero:-one, mt_row)
+%!assert <*59229> (-inf:zero:zero, mt_row)
+%!assert <*59229> (-inf:zero:one, mt_row)
+%!assert <*59229> (-inf:zero:-inf, mt_row)
+%!assert <*59229> (-inf:zero:inf, mt_row)
+%!assert <*59229> (inf:zero:-one, mt_row)
+%!assert <*59229> (inf:zero:zero, mt_row)
+%!assert <*59229> (inf:zero:one, mt_row)
+%!assert <*59229> (inf:zero:-inf, mt_row)
+%!assert <*59229> (inf:zero:inf, mt_row)
+%!assert <*59229> (zero:pt3:-one, mt_row)
+%!assert <*59229> (zero:pt3:-inf, mt_row)
+%!assert <*59229> (inf:pt3:-one, mt_row)
+%!assert <*59229> (inf:pt3:zero, mt_row)
+%!assert <*59229> (inf:pt3:one, mt_row)
+%!assert <*59229> (inf:pt3:-inf, mt_row)
+%!assert <*59229> (zero:inf:-one, mt_row)
+%!assert <*59229> (zero:inf:-inf, mt_row)
+%!assert <*59229> (inf:inf:-one, mt_row)
+%!assert <*59229> (inf:inf:zero, mt_row)
+%!assert <*59229> (inf:inf:one, mt_row)
+%!assert <*59229> (inf:inf:-inf, mt_row)
+%!assert <*59229> (zero:-pt3:one, mt_row)
+%!assert <*59229> (zero:-pt3:inf, mt_row)
+%!assert <*59229> (-inf:-pt3:-one, mt_row)
+%!assert <*59229> (-inf:-pt3:zero, mt_row)
+%!assert <*59229> (-inf:-pt3:one, mt_row)
+%!assert <*59229> (-inf:-pt3:inf, mt_row)
+%!assert <*59229> (zero:-inf:one, mt_row)
+%!assert <*59229> (zero:-inf:inf, mt_row)
+%!assert <*59229> (-inf:-inf:-one, mt_row)
+%!assert <*59229> (-inf:-inf:zero, mt_row)
+%!assert <*59229> (-inf:-inf:one, mt_row)
+%!assert <*59229> (-inf:-inf:inf, mt_row)
+%!assert <*59229> (zero:-inf:-one, zero)
+%!assert <*59229> (zero:-inf:zero, zero)
+%!assert <*59229> (zero:inf:zero, zero)
+%!assert <*59229> (zero:inf:one, zero)
+%!assert <*59229> (zero:-pt3:zero, zero)
+%!assert <*59229> (zero:pt3:zero, zero)
+%!assert <*59229> (zero:-pt3:-one, [zero, -pt3, -pt6, -pt9], epsilon)
+%!assert <*59229> (zero:pt3:one, [zero, pt3, pt6, pt9], epsilon)
+%!error <range with infinite number of elements cannot be stored> zero:-pt3:-inf
+%!error <range with infinite number of elements cannot be stored> inf:-pt3:-one
+%!error <range with infinite number of elements cannot be stored> inf:-pt3:zero
+%!error <range with infinite number of elements cannot be stored> inf:-pt3:one
+%!error <range with infinite number of elements cannot be stored> inf:-pt3:-inf
+%!error <range with infinite number of elements cannot be stored> zero:pt3:inf
+%!error <range with infinite number of elements cannot be stored> -inf:pt3:-one
+%!error <range with infinite number of elements cannot be stored> -inf:pt3:zero
+%!error <range with infinite number of elements cannot be stored> -inf:pt3:one
+%!error <range with infinite number of elements cannot be stored> -inf:pt3:inf
+
+## Tests with different input classes
+%!error <invalid types found in range> ({1}:1:5)
+%!error <invalid types found in range> (1:{1}:5)
+%!error <invalid types found in range> (1:1:{5})
+%!error <incompatible types found in range> (int8(1):int16(1):5)
+%!error <incompatible types found in range> (int8(1):1:int16(5))
+## Tests with mixed integer/floating point values
+%!error <colon operator lower bound invalid> (1.5:uint8(1):5)
+%!error <colon operator lower bound invalid> (-1:uint8(1):5)
+%!error <colon operator increment invalid> (uint8(1):1.5:5)
+%!error <colon operator increment invalid> (uint8(1):-1:5)
+%!error <colon operator upper bound invalid> (uint8(1):1:5.5)
+%!error <colon operator upper bound invalid> (uint8(1):1:256)
--- a/test/struct.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/struct.tst	Sun May 16 09:44:35 2021 +0200
@@ -37,7 +37,7 @@
 
 %!test
 %! s.a = 1;
-%! fail ("fieldnames (s, 1)", "Invalid call to fieldnames");
+%! fail ("fieldnames (s, 1)", "called with too many inputs");
 
 %!error fieldnames (1)
 
--- a/test/system.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/system.tst	Sun May 16 09:44:35 2021 +0200
@@ -98,13 +98,13 @@
 %! assert ((e1 && strcmp (s2.modestr(1), "d") && e3 && e4 < 0));
 
 %!error <Invalid call to mkdir> mkdir ()
-%!error <Invalid call to mkdir> mkdir ("foo", 1, 2)
+%!error <called with too many inputs> mkdir ("foo", 1, 2)
 %!error <Invalid call to rmdir> rmdir ()
 
 %!test
 %! crr = confirm_recursive_rmdir ();
 %! confirm_recursive_rmdir (0);
-%! assert (!rmdir ("foo", "s"));
+%! assert (! rmdir ("foo", "s"));
 %! confirm_recursive_rmdir (crr);
 
 %!test
--- a/test/try.tst	Sun May 16 09:43:43 2021 +0200
+++ b/test/try.tst	Sun May 16 09:44:35 2021 +0200
@@ -47,7 +47,7 @@
 %! catch
 %! end_try_catch
 %! a = 2;
-%! assert (!exist ('x'));
+%! assert (! exist ('x'));
 %! assert (a,2);
 
 %!test
@@ -65,9 +65,9 @@
 %!   a;
 %!   error ("Shouldn't get here");
 %! catch
-%!   assert (lasterr()(1:13), "'a' undefined");
+%!   assert (lasterr ()(1:13), "'a' undefined");
 %! end_try_catch
-%! assert (lasterr()(1:13), "'a' undefined");
+%! assert (lasterr ()(1:13), "'a' undefined");
 
 %!test
 %! try
@@ -96,13 +96,13 @@
 %!     a;
 %!     error ("Shouldn't get here");
 %!   catch
-%!     assert (lasterr()(1:13), "'a' undefined");
+%!     assert (lasterr ()(1:13), "'a' undefined");
 %!   end_try_catch
 %!   clear b;
 %!   b;
 %!   error ("Shouldn't get here");
 %! catch
-%!   assert (lasterr()(1:13), "'b' undefined");
+%!   assert (lasterr ()(1:13), "'b' undefined");
 %! end_try_catch
 
 %!test
@@ -112,12 +112,12 @@
 %!   error ("Shouldn't get here");
 %! catch
 %!   try
-%!     assert (lasterr()(1:13), "'a' undefined");
+%!     assert (lasterr ()(1:13), "'a' undefined");
 %!     clear b;
 %!     b;
 %!     error ("Shouldn't get here");
 %!   catch
-%!     assert (lasterr()(1:13), "'b' undefined");
+%!     assert (lasterr ()(1:13), "'b' undefined");
 %!   end_try_catch
 %! end_try_catch
 
@@ -131,7 +131,7 @@
 %!     error (["rethrow: " lasterr]);
 %!   end_try_catch
 %! catch
-%!   assert (lasterr()(1:22), "rethrow: 'a' undefined");
+%!   assert (lasterr ()(1:22), "rethrow: 'a' undefined");
 %! end_try_catch
 
 %!test